diff options
Diffstat (limited to 'core/java')
22 files changed, 490 insertions, 303 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 33a47b2..5a0d246 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1371,6 +1371,9 @@ public class Notification implements Parcelable when = parcel.readLong(); if (parcel.readInt() != 0) { mSmallIcon = Icon.CREATOR.createFromParcel(parcel); + if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) { + icon = mSmallIcon.getResId(); + } } number = parcel.readInt(); if (parcel.readInt() != 0) { @@ -1588,13 +1591,17 @@ public class Notification implements Parcelable } /** - * Flatten this notification from a parcel. + * Flatten this notification into a parcel. */ public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(1); parcel.writeLong(when); + if (mSmallIcon == null && icon != 0) { + // you snuck an icon in here without using the builder; let's try to keep it + mSmallIcon = Icon.createWithResource("", icon); + } if (mSmallIcon != null) { parcel.writeInt(1); mSmallIcon.writeToParcel(parcel, 0); @@ -2791,7 +2798,10 @@ public class Notification implements Parcelable return this; } - private void setFlag(int mask, boolean value) { + /** + * @hide + */ + public void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; } else { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0904e21..605c006 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.graphics.drawable.Icon; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -216,6 +217,12 @@ public class NotificationManager } } fixLegacySmallIcon(notification, pkg); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + if (notification.getSmallIcon() == null) { + throw new IllegalArgumentException("Invalid notification (no valid small icon): " + + notification); + } + } if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); Notification stripped = notification.clone(); Builder.stripForDelivery(stripped); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ed20086..b9862ca 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -552,19 +552,6 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM"; /** - * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that - * holds data needed by the system to wipe factory reset protection. The data needed to wipe - * the device depend on the installed factory reset protection implementation. For example, - * if an account is needed to unlock a device, this extra may contain data used to - * authenticate that account. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS - = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS"; - - /** * This MIME type is used for starting the Device Owner provisioning that does not require * provisioning features introduced in Android API level * {@link android.os.Build.VERSION_CODES#MNC} or later levels. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bd50ca0..dd1c5c2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2900,7 +2900,7 @@ public abstract class PackageManager { * * @return A List<ResolveInfo> containing one entry for each matching * Receiver. These are ordered from first to last in priority. If - * there are no matching receivers, an empty list is returned. + * there are no matching receivers, an empty list or {@code null} is returned. * * @see #MATCH_DEFAULT_ONLY * @see #GET_INTENT_FILTERS @@ -2936,7 +2936,7 @@ public abstract class PackageManager { * ServiceInfo. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by * resolveService(). If there are no matching services, an empty - * list is returned. + * list or {@code null} is returned. * * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER @@ -2955,7 +2955,7 @@ public abstract class PackageManager { * ServiceInfo. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by * resolveService(). If there are no matching services, an empty - * list is returned. + * list or {@code null} is returned. * * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER @@ -2977,7 +2977,7 @@ public abstract class PackageManager { * @param flags Additional option flags. * @return A List<ResolveInfo> containing one entry for each matching * ProviderInfo. These are ordered from best to worst match. If - * there are no matching providers, an empty list is returned. + * there are no matching providers, an empty list or {@code null} is returned. * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER */ diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index d165240..eb6e1c2 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1165,25 +1165,23 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_USER_FOREGROUND = 0x0008; // Event for connectivity changed. public static final int EVENT_CONNECTIVITY_CHANGED = 0x0009; - // Event for significant motion taking us out of idle mode. - public static final int EVENT_SIGNIFICANT_MOTION = 0x000a; // Event for becoming active taking us out of idle mode. - public static final int EVENT_ACTIVE = 0x000b; + public static final int EVENT_ACTIVE = 0x000a; // Event for a package being installed. - public static final int EVENT_PACKAGE_INSTALLED = 0x000c; + public static final int EVENT_PACKAGE_INSTALLED = 0x000b; // Event for a package being uninstalled. - public static final int EVENT_PACKAGE_UNINSTALLED = 0x000d; + public static final int EVENT_PACKAGE_UNINSTALLED = 0x000c; // Event for a package being uninstalled. - public static final int EVENT_ALARM = 0x000e; + public static final int EVENT_ALARM = 0x000d; // Record that we have decided we need to collect new stats data. - public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f; + public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000e; // Event for a package becoming inactive due to being unused for a period of time. - public static final int EVENT_PACKAGE_INACTIVE = 0x0010; + public static final int EVENT_PACKAGE_INACTIVE = 0x000f; // Event for a package becoming active due to an interaction. - public static final int EVENT_PACKAGE_ACTIVE = 0x0011; + public static final int EVENT_PACKAGE_ACTIVE = 0x0010; // Number of event types. - public static final int EVENT_COUNT = 0x0012; + public static final int EVENT_COUNT = 0x0011; // Mask to extract out only the type part of the event. public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); @@ -1840,12 +1838,12 @@ public abstract class BatteryStats implements Parcelable { public static final String[] HISTORY_EVENT_NAMES = new String[] { "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn", - "motion", "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active" + "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active" }; public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn", - "Esm", "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa" + "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa" }; /** @@ -4017,8 +4015,10 @@ public abstract class BatteryStats implements Parcelable { if (userCpuTimeUs > 0 || systemCpuTimeUs > 0) { sb.setLength(0); sb.append(prefix); - sb.append(" Total cpu time: "); - formatTimeMs(sb, (userCpuTimeUs + systemCpuTimeUs) / 1000); + sb.append(" Total cpu time: u="); + formatTimeMs(sb, userCpuTimeUs / 1000); + sb.append("s="); + formatTimeMs(sb, systemCpuTimeUs / 1000); pw.println(sb.toString()); } diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index 268295d..fe4aa13 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -28,4 +28,5 @@ interface IDeviceIdleController { int[] getAppIdTempWhitelist(); boolean isPowerSaveWhitelistApp(String name); void addPowerSaveTempWhitelistApp(String name, long duration, int userId); + void exitIdle(String reason); } diff --git a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl index 0071a33..52db223 100644 --- a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl +++ b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl @@ -16,8 +16,6 @@ package android.service.persistentdata; -import android.app.PendingIntent; -import android.os.Bundle; import android.os.ParcelFileDescriptor; /** @@ -32,7 +30,6 @@ interface IPersistentDataBlockService { int write(in byte[] data); byte[] read(); void wipe(); - void wipeIfAllowed(in Bundle bundle, in PendingIntent pi); int getDataBlockSize(); long getMaximumDataBlockSize(); diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java index 31570c6..0ffdf68 100644 --- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java +++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java @@ -17,8 +17,6 @@ package android.service.persistentdata; import android.annotation.SystemApi; -import android.app.PendingIntent; -import android.os.Bundle; import android.os.RemoteException; import android.util.Slog; @@ -43,56 +41,6 @@ import android.util.Slog; @SystemApi public class PersistentDataBlockManager { private static final String TAG = PersistentDataBlockManager.class.getSimpleName(); - - /** - * Broadcast action that will be called when the {@link #wipeIfAllowed(Bundle,PendingIntent)} - * method is called. A broadcast with this action will be sent to the package allowed to write - * to the persistent data block. Packages receiving this broadcasts should respond by using the - * {@link android.app.PendingIntent} sent in the {@link #EXTRA_WIPE_IF_ALLOWED_CALLBACK} extra. - */ - public static final String ACTION_WIPE_IF_ALLOWED - = "android.service.persistentdata.action.WIPE_IF_ALLOWED"; - - /** - * A {@link android.os.Parcelable} extra of type {@link android.app.PendingIntent} used to - * response to {@link #wipeIfAllowed(Bundle,PendingIntent)}. This extra will set in broadcasts - * with an action of {@link #ACTION_WIPE_IF_ALLOWED}. - */ - public static final String EXTRA_WIPE_IF_ALLOWED_CALLBACK - = "android.service.persistentdata.extra.WIPE_IF_ALLOWED_CALLBACK"; - - /** - * Result code indicating that the data block was wiped. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_SUCCESS = 0; - - /** - * Result code indicating that a remote exception was received while processing the request. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_REMOTE_EXCEPTION = 1; - - /** - * Result code indicating that a network error occurred while processing the request. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_NETWORK_ERROR = 2; - - /** - * Result code indicating that the data block could not be cleared with the provided data. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_NOT_COMPLIANT = 3; - private IPersistentDataBlockService sService; public PersistentDataBlockManager(IPersistentDataBlockService service) { @@ -170,28 +118,6 @@ public class PersistentDataBlockManager { } /** - * Attempt to wipe the data block by sending a broadcast to the package allowed to modify the - * datablock. The allowed package can refuse to wipe the data block based on the contents of - * the specified bundle. This bundle may contain data used by the allowed package to wipe the - * partition such as account credentials or an authorization token. - * @param bundle data used to wipe the data block. The contents of this bundle depend on the - * allowed package receiving the data. - * @param pi intent called when attempt finished. The result code of this intent will be set - * to one of {@link #STATUS_SUCCESS}, {@link #STATUS_ERROR_REMOTE_EXCEPTION}, - * {@link #STATUS_ERROR_NETWORK_ERROR}, or {@link #STATUS_ERROR_NOT_COMPLIANT}. - */ - public void wipeIfAllowed(Bundle bundle, PendingIntent pi) { - if (pi == null) { - throw new NullPointerException(); - } - try { - sService.wipeIfAllowed(bundle, pi); - } catch (RemoteException e) { - onError("wiping persistent partition"); - } - } - - /** * Writes a byte enabling or disabling the ability to "OEM unlock" the device. */ public void setOemUnlockEnabled(boolean enabled) { diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 98c684c..39dd29b 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -1097,7 +1097,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true); mWindow.getWindow().addFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); initViews(); mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT); mWindow.setToken(mToken); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 73cfd8c..2e2ba88 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -4148,24 +4148,38 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mOnHierarchyChangeListener = listener; } - /** - * @hide - */ - protected void onViewAdded(View child) { + void dispatchViewAdded(View child) { + onViewAdded(child); if (mOnHierarchyChangeListener != null) { mOnHierarchyChangeListener.onChildViewAdded(this, child); } } /** - * @hide + * Called when a new child is added to this ViewGroup. Overrides should always + * call super.onViewAdded. + * + * @param child the added child view */ - protected void onViewRemoved(View child) { + public void onViewAdded(View child) { + } + + void dispatchViewRemoved(View child) { + onViewRemoved(child); if (mOnHierarchyChangeListener != null) { mOnHierarchyChangeListener.onChildViewRemoved(this, child); } } + /** + * Called when a child view is removed from this ViewGroup. Overrides should always + * call super.onViewRemoved. + * + * @param child the removed child view + */ + public void onViewRemoved(View child) { + } + private void clearCachedLayoutMode() { if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) { mLayoutMode = LAYOUT_MODE_UNDEFINED; @@ -4292,7 +4306,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.resetRtlProperties(); } - onViewAdded(child); + dispatchViewAdded(child); if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; @@ -4554,7 +4568,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - onViewRemoved(view); + dispatchViewRemoved(view); if (view.getVisibility() != View.GONE) { notifySubtreeAccessibilityStateChangedIfNeeded(); @@ -4646,7 +4660,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager needGlobalAttributesUpdate(false); - onViewRemoved(view); + dispatchViewRemoved(view); } removeFromArray(start, count); @@ -4729,7 +4743,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(view, false); } - onViewRemoved(view); + dispatchViewRemoved(view); view.mParent = null; children[i] = null; @@ -4788,7 +4802,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(child, false); } - onViewRemoved(child); + dispatchViewRemoved(child); } /** diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index db78ec5..b49cbc6 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -186,7 +186,9 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Window cache miss"); } + final long identityToken = Binder.clearCallingIdentity(); window = connection.getWindow(accessibilityWindowId); + Binder.restoreCallingIdentity(identityToken); if (window != null) { sAccessibilityCache.addWindow(window); return window; @@ -222,7 +224,9 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); } + final long identityToken = Binder.clearCallingIdentity(); windows = connection.getWindows(); + Binder.restoreCallingIdentity(identityToken); if (windows != null) { final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { @@ -282,9 +286,11 @@ public final class AccessibilityInteractionClient } } final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId( accessibilityWindowId, accessibilityNodeId, interactionId, this, prefetchFlags, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); // If the scale is zero the call has failed. if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( @@ -328,9 +334,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfosByViewId( accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -374,9 +382,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfosByText( accessibilityWindowId, accessibilityNodeId, text, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -419,9 +429,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findFocus(accessibilityWindowId, accessibilityNodeId, focusType, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -461,9 +473,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.focusSearch(accessibilityWindowId, accessibilityNodeId, direction, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -502,9 +516,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.performAccessibilityAction( accessibilityWindowId, accessibilityNodeId, action, arguments, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { return getPerformAccessibilityActionResultAndClear(interactionId); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6454b57..a96bf71 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3113,9 +3113,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private boolean performStylusButtonPressAction(MotionEvent ev) { - if (ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && ev.isButtonPressed(MotionEvent.BUTTON_SECONDARY) - && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) { + if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) { final View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { final int longPressPosition = mMotionPosition; @@ -3785,7 +3783,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (mTouchMode == TOUCH_MODE_DOWN && mMotionPosition != INVALID_POSITION - && (performButtonActionOnTouchDown(ev) || performStylusButtonPressAction(ev))) { + && performButtonActionOnTouchDown(ev)) { removeCallbacks(mPendingCheckForTap); } } @@ -3828,11 +3826,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mTouchMode = TOUCH_MODE_DONE_WAITING; updateSelectorState(); } else if (motionView != null) { - if (performStylusButtonPressAction(ev)) { - removeCallbacks(mPendingCheckForTap); - removeCallbacks(mPendingCheckForLongPress); - } - // Still within bounds, update the hotspot. final float[] point = mTmpPoint; point[0] = x; @@ -4072,7 +4065,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te public boolean onGenericMotionEvent(MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (event.getAction()) { - case MotionEvent.ACTION_SCROLL: { + case MotionEvent.ACTION_SCROLL: if (mTouchMode == TOUCH_MODE_REST) { final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); if (vscroll != 0) { @@ -4082,9 +4075,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } - } + break; + + case MotionEvent.ACTION_BUTTON_PRESS: + int actionButton = event.getActionButton(); + if ((actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY) + && (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP)) { + if (performStylusButtonPressAction(event)) { + removeCallbacks(mPendingCheckForLongPress); + removeCallbacks(mPendingCheckForTap); + } + } + break; } } + return super.onGenericMotionEvent(event); } diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index a15080e..ebb54ff 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -17,6 +17,7 @@ package android.widget; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Handler; import android.os.Message; @@ -24,6 +25,7 @@ import android.os.SystemClock; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; +import android.view.accessibility.AccessibilityEvent; import android.widget.RemoteViews.RemoteView; import java.util.Formatter; @@ -58,6 +60,7 @@ public class Chronometer extends TextView { } private long mBase; + private long mNow; // the currently displayed time private boolean mVisible; private boolean mStarted; private boolean mRunning; @@ -224,6 +227,7 @@ public class Chronometer extends TextView { } private synchronized void updateText(long now) { + mNow = now; long seconds = now - mBase; seconds /= 1000; String text = DateUtils.formatElapsedTime(mRecycle, seconds); @@ -279,6 +283,60 @@ public class Chronometer extends TextView { } } + private static final int MIN_IN_SEC = 60; + private static final int HOUR_IN_SEC = MIN_IN_SEC*60; + private static String formatDuration(long ms) { + final Resources res = Resources.getSystem(); + final StringBuilder text = new StringBuilder(); + + int duration = (int) (ms / DateUtils.SECOND_IN_MILLIS); + if (duration < 0) { + duration = -duration; + } + + int h = 0; + int m = 0; + + if (duration >= HOUR_IN_SEC) { + h = duration / HOUR_IN_SEC; + duration -= h * HOUR_IN_SEC; + } + if (duration >= MIN_IN_SEC) { + m = duration / MIN_IN_SEC; + duration -= m * MIN_IN_SEC; + } + int s = duration; + + try { + if (h > 0) { + text.append(res.getQuantityString( + com.android.internal.R.plurals.duration_hours, h, h)); + } + if (m > 0) { + if (text.length() > 0) { + text.append(' '); + } + text.append(res.getQuantityString( + com.android.internal.R.plurals.duration_minutes, m, m)); + } + + if (text.length() > 0) { + text.append(' '); + } + text.append(res.getQuantityString( + com.android.internal.R.plurals.duration_seconds, s, s)); + } catch (Resources.NotFoundException e) { + // Ignore; plurals throws an exception for an untranslated quantity for a given locale. + return null; + } + return text.toString(); + } + + @Override + public CharSequence getContentDescription() { + return formatDuration(mNow - mBase); + } + @Override public CharSequence getAccessibilityClassName() { return Chronometer.class.getName(); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 238d6c4..9ca59f1 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -4157,6 +4157,11 @@ public class Editor { offset = adjustedOffset; } positionCursor = true; + } else if (adjustedOffset < mPreviousOffset) { + // Handle has jumped to the start of the word, and the user is moving + // their finger towards the handle, the delta should be updated. + mTouchWordDelta = mTextView.convertToLocalHorizontalCoordinate(x) + - layout.getPrimaryHorizontal(mPreviousOffset); } } @@ -4291,6 +4296,11 @@ public class Editor { offset = adjustedOffset; } positionCursor = true; + } else if (adjustedOffset > mPreviousOffset) { + // Handle has jumped to the end of the word, and the user is moving + // their finger towards the handle, the delta should be updated. + mTouchWordDelta = layout.getPrimaryHorizontal(mPreviousOffset) + - mTextView.convertToLocalHorizontalCoordinate(x); } } diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 6cc4bda..258424a 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -935,22 +935,14 @@ public class GridLayout extends ViewGroup { super.onDebugDraw(canvas); } - // Add/remove - - /** - * @hide - */ @Override - protected void onViewAdded(View child) { + public void onViewAdded(View child) { super.onViewAdded(child); invalidateStructure(); } - /** - * @hide - */ @Override - protected void onViewRemoved(View child) { + public void onViewRemoved(View child) { super.onViewRemoved(child); invalidateStructure(); } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 929cacd..6f0cec6 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -116,7 +116,7 @@ interface IBatteryStats { void noteWifiRadioPowerState(int powerState, long timestampNs); void noteNetworkInterfaceType(String iface, int type); void noteNetworkStatsEnabled(); - void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion); + void noteDeviceIdleMode(boolean enabled, String activeReason, int activeUid); void setBatteryState(int status, int health, int plugType, int level, int temp, int volt); long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 230d96d..03f2e3a 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -26,6 +26,13 @@ import android.view.View; * @hide */ public class MetricsLogger implements MetricsConstants { + public static final int VOLUME_DIALOG = 207; + public static final int VOLUME_DIALOG_DETAILS = 208; + public static final int ACTION_VOLUME_SLIDER = 209; + public static final int ACTION_VOLUME_STREAM = 210; + public static final int ACTION_VOLUME_KEY = 211; + public static final int ACTION_VOLUME_ICON = 212; + public static final int ACTION_RINGER_MODE = 213; // Temporary constants go here, to await migration to MetricsConstants. public static void visible(Context context, int category) throws IllegalArgumentException { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 07d1fc8..229079f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -95,7 +95,8 @@ import java.util.concurrent.locks.ReentrantLock; public final class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; - private static final boolean DEBUG_ENERGY = false; + public static final boolean DEBUG_ENERGY = false; + private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY || false; private static final boolean DEBUG_HISTORY = false; private static final boolean USE_OLD_HISTORY = false; // for debugging. @@ -105,7 +106,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 127 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 128 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -151,6 +152,9 @@ public final class BatteryStatsImpl extends BatteryStats { BatteryCallback cb = mCallback; switch (msg.what) { case MSG_UPDATE_WAKELOCKS: + synchronized (BatteryStatsImpl.this) { + updateCpuTimeLocked(); + } if (cb != null) { cb.batteryNeedsCpuUpdate(); } @@ -178,6 +182,7 @@ public final class BatteryStatsImpl extends BatteryStats { public interface ExternalStatsSync { void scheduleSync(String reason); + void scheduleWifiSync(String reason); } public final MyHandler mHandler; @@ -2503,12 +2508,11 @@ public final class BatteryStatsImpl extends BatteryStats { boolean unpluggedScreenOff = unplugged && screenOff; if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) { updateKernelWakelocksLocked(); - requestWakelockCpuUpdate(); - if (!unpluggedScreenOff) { - // We are switching to no longer tracking wake locks, but we want - // the next CPU update we receive to take them in to account. - mDistributeWakelockCpu = true; + if (DEBUG_ENERGY_CPU) { + Slog.d(TAG, "Updating cpu time because screen is now " + + (unpluggedScreenOff ? "off" : "on")); } + updateCpuTimeLocked(); mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime); } } @@ -2772,10 +2776,14 @@ public final class BatteryStatsImpl extends BatteryStats { mWakeLockNesting++; } if (uid >= 0) { - //if (uid == 0) { - // Slog.wtf(TAG, "Acquiring wake lock from root: " + name); - //} - requestWakelockCpuUpdate(); + if (mOnBatteryScreenOffTimeBase.isRunning()) { + // We only update the cpu time when a wake lock is acquired if the screen is off. + // If the screen is on, we don't distribute the power amongst partial wakelocks. + if (DEBUG_ENERGY_CPU) { + Slog.d(TAG, "Updating cpu time because of +wake_lock"); + } + requestWakelockCpuUpdate(); + } getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime); } } @@ -2805,7 +2813,12 @@ public final class BatteryStatsImpl extends BatteryStats { } } if (uid >= 0) { - requestWakelockCpuUpdate(); + if (mOnBatteryScreenOffTimeBase.isRunning()) { + if (DEBUG_ENERGY_CPU) { + Slog.d(TAG, "Updating cpu time because of -wake_lock"); + } + requestWakelockCpuUpdate(); + } getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime); } } @@ -2874,46 +2887,14 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); } - public int startAddingCpuLocked() { + public boolean startAddingCpuLocked() { mHandler.removeMessages(MSG_UPDATE_WAKELOCKS); - - if (!mOnBatteryInternal) { - return -1; - } - - final int N = mPartialTimers.size(); - if (N == 0) { - mLastPartialTimers.clear(); - mDistributeWakelockCpu = false; - return 0; - } - - if (!mOnBatteryScreenOffTimeBase.isRunning() && !mDistributeWakelockCpu) { - return 0; - } - - mDistributeWakelockCpu = false; - - // How many timers should consume CPU? Only want to include ones - // that have already been in the list. - for (int i=0; i<N; i++) { - StopwatchTimer st = mPartialTimers.get(i); - if (st.mInList) { - Uid uid = st.mUid; - // We don't include the system UID, because it so often - // holds wake locks at one request or another of an app. - if (uid != null && uid.mUid != Process.SYSTEM_UID) { - return 50; - } - } - } - - return 0; + return mOnBatteryInternal; } - public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime, - int totalUTime, int totalSTime, int statUserTime, int statSystemTime, - int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime) { + public void finishAddingCpuLocked(int totalUTime, int totalSTime, int statUserTime, + int statSystemTime, int statIOWaitTime, int statIrqTime, + int statSoftIrqTime, int statIdleTime) { if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime + " user=" + statUserTime + " sys=" + statSystemTime + " io=" + statIOWaitTime + " irq=" + statIrqTime @@ -2926,70 +2907,6 @@ public final class BatteryStatsImpl extends BatteryStats { mCurStepStatIrqTime += statIrqTime; mCurStepStatSoftIrqTime += statSoftIrqTime; mCurStepStatIdleTime += statIdleTime; - - final int N = mPartialTimers.size(); - if (perc != 0) { - int num = 0; - for (int i=0; i<N; i++) { - StopwatchTimer st = mPartialTimers.get(i); - if (st.mInList) { - Uid uid = st.mUid; - // We don't include the system UID, because it so often - // holds wake locks at one request or another of an app. - if (uid != null && uid.mUid != Process.SYSTEM_UID) { - num++; - } - } - } - if (num != 0) { - for (int i=0; i<N; i++) { - StopwatchTimer st = mPartialTimers.get(i); - if (st.mInList) { - Uid uid = st.mUid; - if (uid != null && uid.mUid != Process.SYSTEM_UID) { - int myUTime = remainUTime/num; - int mySTime = remainSTtime/num; - remainUTime -= myUTime; - remainSTtime -= mySTime; - num--; - Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*"); - proc.addCpuTimeLocked(myUTime, mySTime); - } - } - } - } - - // Just in case, collect any lost CPU time. - if (remainUTime != 0 || remainSTtime != 0) { - Uid uid = getUidStatsLocked(Process.SYSTEM_UID); - if (uid != null) { - Uid.Proc proc = uid.getProcessStatsLocked("*lost*"); - proc.addCpuTimeLocked(remainUTime, remainSTtime); - } - } - } - - final int NL = mLastPartialTimers.size(); - boolean diff = N != NL; - for (int i=0; i<NL && !diff; i++) { - diff |= mPartialTimers.get(i) != mLastPartialTimers.get(i); - } - if (!diff) { - for (int i=0; i<NL; i++) { - mPartialTimers.get(i).mInList = true; - } - return; - } - - for (int i=0; i<NL; i++) { - mLastPartialTimers.get(i).mInList = false; - } - mLastPartialTimers.clear(); - for (int i=0; i<N; i++) { - StopwatchTimer st = mPartialTimers.get(i); - st.mInList = true; - mLastPartialTimers.add(st); - } } public void noteProcessDiedLocked(int uid, int pid) { @@ -3271,11 +3188,11 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public void noteDeviceIdleModeLocked(boolean enabled, boolean fromActive, boolean fromMotion) { + public void noteDeviceIdleModeLocked(boolean enabled, String activeReason, int activeUid) { final long elapsedRealtime = SystemClock.elapsedRealtime(); final long uptime = SystemClock.uptimeMillis(); boolean nowIdling = enabled; - if (mDeviceIdling && !enabled && !fromActive && !fromMotion) { + if (mDeviceIdling && !enabled && activeReason == null) { // We don't go out of general idling mode until explicitly taken out of // device idle through going active or significant motion. nowIdling = true; @@ -3293,14 +3210,8 @@ public final class BatteryStatsImpl extends BatteryStats { } if (mDeviceIdleModeEnabled != enabled) { mDeviceIdleModeEnabled = enabled; - if (fromMotion) { - addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SIGNIFICANT_MOTION, - "", 0); - } - if (fromActive) { - addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE, - "", 0); - } + addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE, + activeReason != null ? activeReason : "", activeUid); if (enabled) { mHistoryCur.states2 |= HistoryItem.STATE2_DEVICE_IDLE_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode enabled to: " @@ -3580,7 +3491,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mWifiOn = true; mWifiOnTimer.startRunningLocked(elapsedRealtime); - scheduleSyncExternalStatsLocked("wifi-off"); + scheduleSyncExternalWifiStatsLocked("wifi-off"); } } @@ -3594,7 +3505,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtime); - scheduleSyncExternalStatsLocked("wifi-on"); + scheduleSyncExternalWifiStatsLocked("wifi-on"); } } @@ -3846,7 +3757,7 @@ public final class BatteryStatsImpl extends BatteryStats { int uid = mapUid(ws.get(i)); getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime); } - scheduleSyncExternalStatsLocked("wifi-running"); + scheduleSyncExternalWifiStatsLocked("wifi-running"); } else { Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running"); } @@ -3885,7 +3796,7 @@ public final class BatteryStatsImpl extends BatteryStats { int uid = mapUid(ws.get(i)); getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime); } - scheduleSyncExternalStatsLocked("wifi-stopped"); + scheduleSyncExternalWifiStatsLocked("wifi-stopped"); } else { Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running"); } @@ -3900,7 +3811,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mWifiState = wifiState; mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime); - scheduleSyncExternalStatsLocked("wifi-state"); + scheduleSyncExternalWifiStatsLocked("wifi-state"); } } @@ -7632,6 +7543,10 @@ public final class BatteryStatsImpl extends BatteryStats { * @param info The energy information from the WiFi controller. */ public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) { + if (DEBUG_ENERGY) { + Slog.d(TAG, "Updating wifi stats"); + } + final long elapsedRealtimeMs = SystemClock.elapsedRealtime(); NetworkStats delta = null; try { @@ -7829,6 +7744,10 @@ public final class BatteryStatsImpl extends BatteryStats { * Distribute Cell radio energy info and network traffic to apps. */ public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) { + if (DEBUG_ENERGY) { + Slog.d(TAG, "Updating mobile radio stats"); + } + NetworkStats delta = null; try { if (!ArrayUtils.isEmpty(mMobileIfaces)) { @@ -7901,6 +7820,10 @@ public final class BatteryStatsImpl extends BatteryStats { * @param info The energy information from the bluetooth controller. */ public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) { + if (DEBUG_ENERGY) { + Slog.d(TAG, "Updating bluetooth stats"); + } + if (info != null && mOnBatteryInternal) { mHasBluetoothEnergyReporting = true; mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked( @@ -7959,30 +7882,196 @@ public final class BatteryStatsImpl extends BatteryStats { } } + // We use an anonymous class to access these variables, + // so they can't live on the stack or they'd have to be + // final MutableLong objects (more allocations). + // Used in updateCpuTimeLocked(). + long mTempTotalCpuUserTimeUs; + long mTempTotalCpuSystemTimeUs; + /** - * Read and distribute CPU usage across apps. + * Read and distribute CPU usage across apps. If their are partial wakelocks being held + * and we are on battery with screen off, we give more of the cpu time to those apps holding + * wakelocks. If the screen is on, we just assign the actual cpu time an app used. */ - public void updateCpuTimeLocked(boolean firstTime) { + public void updateCpuTimeLocked() { + if (DEBUG_ENERGY_CPU) { + Slog.d(TAG, "!Cpu updating!"); + } + + // Holding a wakelock costs more than just using the cpu. + // Currently, we assign only half the cpu time to an app that is running but + // not holding a wakelock. The apps holding wakelocks get the rest of the blame. + // If no app is holding a wakelock, then the distribution is normal. + final int wakelockWeight = 50; + + // Read the time spent at various cpu frequencies. final int cpuSpeedSteps = getCpuSpeedSteps(); final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta(); - KernelUidCpuTimeReader.Callback callback = null; - if (mOnBatteryInternal && !firstTime) { - callback = new KernelUidCpuTimeReader.Callback() { - @Override - public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs) { - final Uid u = getUidStatsLocked(mapUid(uid)); - u.mUserCpuTime.addCountLocked(userTimeUs); - u.mSystemCpuTime.addCountLocked(systemTimeUs); - for (int i = 0; i < cpuSpeedSteps; i++) { - if (u.mSpeedBins[i] == null) { - u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); + + int numWakelocks = 0; + + // Calculate how many wakelocks we have to distribute amongst. The system is excluded. + // Only distribute cpu power to wakelocks if the screen is off and we're on battery. + final int numPartialTimers = mPartialTimers.size(); + if (mOnBatteryScreenOffTimeBase.isRunning()) { + for (int i = 0; i < numPartialTimers; i++) { + final StopwatchTimer timer = mPartialTimers.get(i); + if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) { + // Since the collection and blaming of wakelocks can be scheduled to run after + // some delay, the mPartialTimers list may have new entries. We can't blame + // the newly added timer for past cpu time, so we only consider timers that + // were present for one round of collection. Once a timer has gone through + // a round of collection, its mInList field is set to true. + numWakelocks++; + } + } + } + + final int numWakelocksF = numWakelocks; + mTempTotalCpuUserTimeUs = 0; + mTempTotalCpuSystemTimeUs = 0; + + // Read the CPU data for each UID. This will internally generate a snapshot so next time + // we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise + // we just ignore the data. + final long startTimeMs = SystemClock.elapsedRealtime(); + mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null : + new KernelUidCpuTimeReader.Callback() { + @Override + public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs) { + final Uid u = getUidStatsLocked(mapUid(uid)); + + // Accumulate the total system and user time. + mTempTotalCpuUserTimeUs += userTimeUs; + mTempTotalCpuSystemTimeUs += systemTimeUs; + + StringBuilder sb = null; + if (DEBUG_ENERGY_CPU) { + sb = new StringBuilder(); + sb.append(" got time for uid=").append(u.mUid).append(": u="); + TimeUtils.formatDuration(userTimeUs / 1000, sb); + sb.append(" s="); + TimeUtils.formatDuration(systemTimeUs / 1000, sb); + sb.append("\n"); + } + + if (numWakelocksF > 0) { + // We have wakelocks being held, so only give a portion of the + // time to the process. The rest will be distributed among wakelock + // holders. + userTimeUs = (userTimeUs * wakelockWeight) / 100; + systemTimeUs = (systemTimeUs * wakelockWeight) / 100; + } + + if (sb != null) { + sb.append(" adding to uid=").append(u.mUid).append(": u="); + TimeUtils.formatDuration(userTimeUs / 1000, sb); + sb.append(" s="); + TimeUtils.formatDuration(systemTimeUs / 1000, sb); + Slog.d(TAG, sb.toString()); + } + + u.mUserCpuTime.addCountLocked(userTimeUs); + u.mSystemCpuTime.addCountLocked(systemTimeUs); + + // Add the cpu speeds to this UID. These are used as a ratio + // for computing the power this UID used. + for (int i = 0; i < cpuSpeedSteps; i++) { + if (u.mSpeedBins[i] == null) { + u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); + } + u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]); } - u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]); } + }); + + if (DEBUG_ENERGY_CPU) { + Slog.d(TAG, "Reading cpu stats took " + (SystemClock.elapsedRealtime() - startTimeMs) + + " ms"); + } + + if (mOnBatteryInternal && numWakelocks > 0) { + // Distribute a portion of the total cpu time to wakelock holders. + mTempTotalCpuUserTimeUs = (mTempTotalCpuUserTimeUs * (100 - wakelockWeight)) / 100; + mTempTotalCpuSystemTimeUs = + (mTempTotalCpuSystemTimeUs * (100 - wakelockWeight)) / 100; + + for (int i = 0; i < numPartialTimers; i++) { + final StopwatchTimer timer = mPartialTimers.get(i); + + // The system does not share any blame, as it is usually holding the wakelock + // on behalf of an app. + if (timer.mInList && timer.mUid != null && timer.mUid.mUid != Process.SYSTEM_UID) { + int userTimeUs = (int) (mTempTotalCpuUserTimeUs / numWakelocks); + int systemTimeUs = (int) (mTempTotalCpuSystemTimeUs / numWakelocks); + + if (DEBUG_ENERGY_CPU) { + StringBuilder sb = new StringBuilder(); + sb.append(" Distributing wakelock uid=").append(timer.mUid.mUid) + .append(": u="); + TimeUtils.formatDuration(userTimeUs / 1000, sb); + sb.append(" s="); + TimeUtils.formatDuration(systemTimeUs / 1000, sb); + Slog.d(TAG, sb.toString()); + } + + timer.mUid.mUserCpuTime.addCountLocked(userTimeUs); + timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs); + + final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*"); + proc.addCpuTimeLocked(userTimeUs, systemTimeUs); + + mTempTotalCpuUserTimeUs -= userTimeUs; + mTempTotalCpuSystemTimeUs -= systemTimeUs; + numWakelocks--; } - }; + } + + if (mTempTotalCpuUserTimeUs > 0 || mTempTotalCpuSystemTimeUs > 0) { + // Anything left over is given to the system. + if (DEBUG_ENERGY_CPU) { + StringBuilder sb = new StringBuilder(); + sb.append(" Distributing lost time to system: u="); + TimeUtils.formatDuration(mTempTotalCpuUserTimeUs / 1000, sb); + sb.append(" s="); + TimeUtils.formatDuration(mTempTotalCpuSystemTimeUs / 1000, sb); + Slog.d(TAG, sb.toString()); + } + + final Uid u = getUidStatsLocked(Process.SYSTEM_UID); + u.mUserCpuTime.addCountLocked(mTempTotalCpuUserTimeUs); + u.mSystemCpuTime.addCountLocked(mTempTotalCpuSystemTimeUs); + + final Uid.Proc proc = u.getProcessStatsLocked("*lost*"); + proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs, + (int) mTempTotalCpuSystemTimeUs); + } + } + + // See if there is a difference in wakelocks between this collection and the last + // collection. + if (ArrayUtils.referenceEquals(mPartialTimers, mLastPartialTimers)) { + // No difference, so each timer is now considered for the next collection. + for (int i = 0; i < numPartialTimers; i++) { + mPartialTimers.get(i).mInList = true; + } + } else { + // The lists are different, meaning we added (or removed a timer) since the last + // collection. + final int numLastPartialTimers = mLastPartialTimers.size(); + for (int i = 0; i < numLastPartialTimers; i++) { + mLastPartialTimers.get(i).mInList = false; + } + mLastPartialTimers.clear(); + + // Mark the current timers as gone through a collection. + for (int i = 0; i < numPartialTimers; i++) { + final StopwatchTimer timer = mPartialTimers.get(i); + timer.mInList = true; + mLastPartialTimers.add(timer); + } } - mKernelUidCpuTimeReader.readDelta(callback); } boolean setChargingLocked(boolean charging) { @@ -8157,6 +8246,12 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private void scheduleSyncExternalWifiStatsLocked(String reason) { + if (mExternalSync != null) { + mExternalSync.scheduleWifiSync(reason); + } + } + // This should probably be exposed in the API, though it's not critical public static final int BATTERY_PLUGGED_NONE = 0; diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java index b236378..62926d1 100644 --- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java @@ -16,9 +16,11 @@ package com.android.internal.os; import android.annotation.Nullable; +import android.os.SystemClock; import android.text.TextUtils; import android.util.Slog; import android.util.SparseLongArray; +import android.util.TimeUtils; import java.io.BufferedReader; import java.io.FileReader; @@ -49,6 +51,7 @@ public class KernelUidCpuTimeReader { private SparseLongArray mLastUserTimeUs = new SparseLongArray(); private SparseLongArray mLastSystemTimeUs = new SparseLongArray(); + private long mLastTimeRead = 0; /** * Reads the proc file, calling into the callback with a delta of time for each UID. @@ -57,6 +60,7 @@ public class KernelUidCpuTimeReader { * a fresh delta. */ public void readDelta(@Nullable Callback callback) { + long now = SystemClock.elapsedRealtime(); try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); String line; @@ -75,10 +79,32 @@ public class KernelUidCpuTimeReader { userTimeDeltaUs -= mLastUserTimeUs.valueAt(index); systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index); - if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) { - // The UID must have been removed from accounting, then added back. - userTimeDeltaUs = userTimeUs; - systemTimeDeltaUs = systemTimeUs; + final long timeDiffMs = (now - mLastTimeRead) * 1000; + if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0 || + userTimeDeltaUs > timeDiffMs || systemTimeDeltaUs > timeDiffMs ) { + StringBuilder sb = new StringBuilder("Malformed cpu data!\n"); + sb.append("Time between reads: "); + TimeUtils.formatDuration(timeDiffMs, sb); + sb.append("ms\n"); + sb.append("Previous times: u="); + TimeUtils.formatDuration(mLastUserTimeUs.valueAt(index) / 1000, sb); + sb.append("ms s="); + TimeUtils.formatDuration(mLastSystemTimeUs.valueAt(index) / 1000, sb); + sb.append("ms\n"); + sb.append("Current times: u="); + TimeUtils.formatDuration(userTimeUs / 1000, sb); + sb.append("ms s="); + TimeUtils.formatDuration(systemTimeUs / 1000, sb); + sb.append("ms\n"); + sb.append("Delta for UID=").append(uid).append(": u="); + TimeUtils.formatDuration(userTimeDeltaUs / 1000, sb); + sb.append("ms s="); + TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb); + sb.append("ms"); + Slog.wtf(TAG, sb.toString()); + + userTimeDeltaUs = 0; + systemTimeDeltaUs = 0; } } @@ -92,6 +118,7 @@ public class KernelUidCpuTimeReader { } catch (IOException e) { Slog.e(TAG, "Failed to read uid_cputime", e); } + mLastTimeRead = now; } /** diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index 4693d4b..1d62623 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -20,17 +20,27 @@ import android.graphics.drawable.Icon; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.text.TextUtils; public class StatusBarIcon implements Parcelable { public UserHandle user; + public String pkg; public Icon icon; public int iconLevel; public boolean visible = true; public int number; public CharSequence contentDescription; - public StatusBarIcon(UserHandle user, Icon icon, int iconLevel, int number, + public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number, CharSequence contentDescription) { + if (icon.getType() == Icon.TYPE_RESOURCE + && TextUtils.isEmpty(icon.getResPackage())) { + // This is an odd situation where someone's managed to hand us an icon without a + // package inside, probably by mashing an int res into a Notification object. + // Now that we have the correct package name handy, let's fix it. + icon = Icon.createWithResource(resPackage, icon.getResId()); + } + this.pkg = resPackage; this.user = user; this.icon = icon; this.iconLevel = iconLevel; @@ -41,21 +51,23 @@ public class StatusBarIcon implements Parcelable { public StatusBarIcon(String iconPackage, UserHandle user, int iconId, int iconLevel, int number, CharSequence contentDescription) { - this(user, Icon.createWithResource(iconPackage, iconId), + this(user, iconPackage, Icon.createWithResource(iconPackage, iconId), iconLevel, number, contentDescription); } @Override public String toString() { - return "StatusBarIcon(icon=" + this.icon + return "StatusBarIcon(icon=" + icon + + ((iconLevel != 0)?(" level=" + iconLevel):"") + + (visible?" visible":"") + " user=" + user.getIdentifier() - + " level=" + this.iconLevel + " visible=" + visible - + " num=" + this.number + " )"; + + ((number != 0)?(" num=" + number):"") + + " )"; } @Override public StatusBarIcon clone() { - StatusBarIcon that = new StatusBarIcon(this.user, this.icon, + StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon, this.iconLevel, this.number, this.contentDescription); that.visible = this.visible; return that; @@ -70,6 +82,7 @@ public class StatusBarIcon implements Parcelable { public void readFromParcel(Parcel in) { this.icon = (Icon) in.readParcelable(null); + this.pkg = in.readString(); this.user = (UserHandle) in.readParcelable(null); this.iconLevel = in.readInt(); this.visible = in.readInt() != 0; @@ -79,6 +92,7 @@ public class StatusBarIcon implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeParcelable(this.icon, 0); + out.writeString(this.pkg); out.writeParcelable(this.user, 0); out.writeInt(this.iconLevel); out.writeInt(this.visible ? 1 : 0); diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 62e724a..9d0636a 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -387,4 +387,26 @@ public class ArrayUtils { public static <T> boolean contains(ArrayList<T> cur, T val) { return (cur != null) ? cur.contains(val) : false; } + + /** + * Returns true if the two ArrayLists are equal with respect to the objects they contain. + * The objects must be in the same order and be reference equal (== not .equals()). + */ + public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) { + if (a == b) { + return true; + } + + final int sizeA = a.size(); + final int sizeB = b.size(); + if (a == null || b == null || sizeA != sizeB) { + return false; + } + + boolean diff = false; + for (int i = 0; i < sizeA && !diff; i++) { + diff |= a.get(i) != b.get(i); + } + return !diff; + } } diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index be727f1..585cbc9 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -127,6 +127,8 @@ public class ResolverDrawerLayout extends ViewGroup { final ViewConfiguration vc = ViewConfiguration.get(context); mTouchSlop = vc.getScaledTouchSlop(); mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); + + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } public void setSmallCollapsed(boolean smallCollapsed) { @@ -593,11 +595,6 @@ public class ResolverDrawerLayout extends ViewGroup { } @Override - public CharSequence getAccessibilityClassName() { - return ResolverDrawerLayout.class.getName(); - } - - @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); if (isEnabled()) { |