diff options
66 files changed, 2092 insertions, 376 deletions
diff --git a/api/current.txt b/api/current.txt index 5cf7e4832d48..23bbdbad8d07 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11826,6 +11826,20 @@ package android.hardware.usb { field public static final android.os.Parcelable.Creator CREATOR; } + public class UsbConfiguration implements android.os.Parcelable { + method public int describeContents(); + method public int getAttributes(); + method public int getId(); + method public android.hardware.usb.UsbInterface getInterface(int); + method public int getInterfaceCount(); + method public int getMaxPower(); + method public java.lang.String getName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int ATTR_REMOTE_WAKEUP_MASK = 32; // 0x20 + field public static final int ATTR_SELF_POWERED_MASK = 64; // 0x40 + field public static final android.os.Parcelable.Creator CREATOR; + } + public final class UsbConstants { ctor public UsbConstants(); field public static final int USB_CLASS_APP_SPEC = 254; // 0xfe @@ -11865,6 +11879,8 @@ package android.hardware.usb { public class UsbDevice implements android.os.Parcelable { method public int describeContents(); + method public android.hardware.usb.UsbConfiguration getConfiguration(int); + method public int getConfigurationCount(); method public int getDeviceClass(); method public int getDeviceId(); method public static int getDeviceId(java.lang.String); @@ -11895,6 +11911,8 @@ package android.hardware.usb { method public java.lang.String getSerial(); method public boolean releaseInterface(android.hardware.usb.UsbInterface); method public android.hardware.usb.UsbRequest requestWait(); + method public boolean setConfiguration(android.hardware.usb.UsbConfiguration); + method public boolean setInterface(android.hardware.usb.UsbInterface); } public class UsbEndpoint implements android.os.Parcelable { @@ -11912,12 +11930,14 @@ package android.hardware.usb { public class UsbInterface implements android.os.Parcelable { method public int describeContents(); + method public int getAlternateSetting(); method public android.hardware.usb.UsbEndpoint getEndpoint(int); method public int getEndpointCount(); method public int getId(); method public int getInterfaceClass(); method public int getInterfaceProtocol(); method public int getInterfaceSubclass(); + method public java.lang.String getName(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } @@ -16308,8 +16328,10 @@ package android.opengl { } public abstract class EGLObjectHandle { - ctor protected EGLObjectHandle(int); - method public int getHandle(); + ctor protected deprecated EGLObjectHandle(int); + ctor protected EGLObjectHandle(long); + method public deprecated int getHandle(); + method public long getNativeHandle(); } public class EGLSurface extends android.opengl.EGLObjectHandle { diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 89e15d25dd62..01e761544644 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -232,6 +232,8 @@ public class Am extends BaseCommand { " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + + " [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" + + " (to embed a comma into a string escape it using \"\\,\")\n" + " [-n <COMPONENT>] [-f <FLAGS>]\n" + " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + " [--debug-log-resolution] [--exclude-stopped-packages]\n" + @@ -419,6 +421,15 @@ public class Am extends BaseCommand { } intent.putExtra(key, list); hasIntentInfo = true; + } else if (opt.equals("--esa")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + // Split on commas unless they are preceeded by an escape. + // The escape character must be escaped for the string and + // again for the regex, thus four escape characters become one. + String[] strings = value.split("(?<!\\\\),"); + intent.putExtra(key, strings); + hasIntentInfo = true; } else if (opt.equals("--ez")) { String key = nextArgRequired(); String value = nextArgRequired(); diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk index ca8008bdba31..5c11b7546f84 100644 --- a/cmds/screencap/Android.mk +++ b/cmds/screencap/Android.mk @@ -16,11 +16,4 @@ LOCAL_MODULE:= screencap LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES += \ - external/skia/include/core \ - external/skia/include/effects \ - external/skia/include/images \ - external/skia/src/ports \ - external/skia/include/utils - include $(BUILD_EXECUTABLE) diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java new file mode 100644 index 000000000000..92d6f75964ce --- /dev/null +++ b/core/java/android/hardware/usb/UsbConfiguration.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class representing a configuration on a {@link UsbDevice}. + * A USB configuration can have one or more interfaces, each one providing a different + * piece of functionality, separate from the other interfaces. + * An interface will have one or more {@link UsbEndpoint}s, which are the + * channels by which the host transfers data with the device. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about communicating with USB hardware, read the + * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p> + * </div> + */ +public class UsbConfiguration implements Parcelable { + + private final int mId; + private final String mName; + private final int mAttributes; + private final int mMaxPower; + private Parcelable[] mInterfaces; + + /** + * Mask for "self-powered" bit in the configuration's attributes. + * @see #getAttributes + */ + public static final int ATTR_SELF_POWERED_MASK = 1 << 6; + + /** + * Mask for "remote wakeup" bit in the configuration's attributes. + * @see #getAttributes + */ + public static final int ATTR_REMOTE_WAKEUP_MASK = 1 << 5; + + /** + * UsbConfiguration should only be instantiated by UsbService implementation + * @hide + */ + public UsbConfiguration(int id, String name, int attributes, int maxPower) { + mId = id; + mName = name; + mAttributes = attributes; + mMaxPower = maxPower; + } + + /** + * Returns the configuration's ID field. + * This is an integer that uniquely identifies the configuration on the device. + * + * @return the configuration's ID + */ + public int getId() { + return mId; + } + + /** + * Returns the configuration's name. + * + * @return the configuration's name + */ + public String getName() { + return mName; + } + + /** + * Returns the configuration's attributes field. + * This field contains a bit field with the following flags: + * + * Bit 7: always set to 1 + * Bit 6: self-powered + * Bit 5: remote wakeup enabled + * Bit 0-4: reserved + * @see #ATTR_SELF_POWERED_MASK + * @see #ATTR_REMOTE_WAKEUP_MASK + * @return the configuration's attributes + */ + public int getAttributes() { + return mAttributes; + } + + /** + * Returns the configuration's max power consumption, in milliamps. + * + * @return the configuration's max power + */ + public int getMaxPower() { + return mMaxPower * 2; + } + + /** + * Returns the number of {@link UsbInterface}s this configuration contains. + * + * @return the number of endpoints + */ + public int getInterfaceCount() { + return mInterfaces.length; + } + + /** + * Returns the {@link UsbInterface} at the given index. + * + * @return the interface + */ + public UsbInterface getInterface(int index) { + return (UsbInterface)mInterfaces[index]; + } + + /** + * Only used by UsbService implementation + * @hide + */ + public void setInterfaces(Parcelable[] interfaces) { + mInterfaces = interfaces; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("UsbConfiguration[mId=" + mId + + ",mName=" + mName + ",mAttributes=" + mAttributes + + ",mMaxPower=" + mMaxPower + ",mInterfaces=["); + for (int i = 0; i < mInterfaces.length; i++) { + builder.append("\n"); + builder.append(mInterfaces[i].toString()); + } + builder.append("]"); + return builder.toString(); + } + + public static final Parcelable.Creator<UsbConfiguration> CREATOR = + new Parcelable.Creator<UsbConfiguration>() { + public UsbConfiguration createFromParcel(Parcel in) { + int id = in.readInt(); + String name = in.readString(); + int attributes = in.readInt(); + int maxPower = in.readInt(); + Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); + UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower); + configuration.setInterfaces(interfaces); + return configuration; + } + + public UsbConfiguration[] newArray(int size) { + return new UsbConfiguration[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mId); + parcel.writeString(mName); + parcel.writeInt(mAttributes); + parcel.writeInt(mMaxPower); + parcel.writeParcelableArray(mInterfaces, 0); + } +} diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index b0ba9c193ecf..d90e06e6c8a1 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -50,7 +50,10 @@ public class UsbDevice implements Parcelable { private final int mClass; private final int mSubclass; private final int mProtocol; - private final Parcelable[] mInterfaces; + private Parcelable[] mConfigurations; + + // list of all interfaces on the device + private UsbInterface[] mInterfaces; /** * UsbDevice should only be instantiated by UsbService implementation @@ -58,8 +61,7 @@ public class UsbDevice implements Parcelable { */ public UsbDevice(String name, int vendorId, int productId, int Class, int subClass, int protocol, - String manufacturerName, String productName, String serialNumber, - Parcelable[] interfaces) { + String manufacturerName, String productName, String serialNumber) { mName = name; mVendorId = vendorId; mProductId = productId; @@ -69,7 +71,6 @@ public class UsbDevice implements Parcelable { mManufacturerName = manufacturerName; mProductName = productName; mSerialNumber = serialNumber; - mInterfaces = interfaces; } /** @@ -169,21 +170,74 @@ public class UsbDevice implements Parcelable { } /** + * Returns the number of {@link UsbConfiguration}s this device contains. + * + * @return the number of configurations + */ + public int getConfigurationCount() { + return mConfigurations.length; + } + + /** + * Returns the {@link UsbConfiguration} at the given index. + * + * @return the configuration + */ + public UsbConfiguration getConfiguration(int index) { + return (UsbConfiguration)mConfigurations[index]; + } + + private UsbInterface[] getInterfaceList() { + if (mInterfaces == null) { + int configurationCount = mConfigurations.length; + int interfaceCount = 0; + for (int i = 0; i < configurationCount; i++) { + UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i]; + interfaceCount += configuration.getInterfaceCount(); + } + + mInterfaces = new UsbInterface[interfaceCount]; + int offset = 0; + for (int i = 0; i < configurationCount; i++) { + UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i]; + interfaceCount = configuration.getInterfaceCount(); + for (int j = 0; j < interfaceCount; j++) { + mInterfaces[offset++] = configuration.getInterface(j); + } + } + } + + return mInterfaces; + } + + /** * Returns the number of {@link UsbInterface}s this device contains. + * For devices with multiple configurations, you will probably want to use + * {@link UsbConfiguration#getInterfaceCount} instead. * * @return the number of interfaces */ public int getInterfaceCount() { - return mInterfaces.length; + return getInterfaceList().length; } /** * Returns the {@link UsbInterface} at the given index. + * For devices with multiple configurations, you will probably want to use + * {@link UsbConfiguration#getInterface} instead. * * @return the interface */ public UsbInterface getInterface(int index) { - return (UsbInterface)mInterfaces[index]; + return getInterfaceList()[index]; + } + + /** + * Only used by UsbService implementation + * @hide + */ + public void setConfigurations(Parcelable[] configuration) { + mConfigurations = configuration; } @Override @@ -204,11 +258,17 @@ public class UsbDevice implements Parcelable { @Override public String toString() { - return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId + - ",mProductId=" + mProductId + ",mClass=" + mClass + - ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + + ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + - ",mSerialNumber=" + mSerialNumber + ",mInterfaces=" + mInterfaces + "]"; + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=["); + for (int i = 0; i < mConfigurations.length; i++) { + builder.append("\n"); + builder.append(mConfigurations[i].toString()); + } + builder.append("]"); + return builder.toString(); } public static final Parcelable.Creator<UsbDevice> CREATOR = @@ -223,9 +283,11 @@ public class UsbDevice implements Parcelable { String manufacturerName = in.readString(); String productName = in.readString(); String serialNumber = in.readString(); - Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); - return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, - manufacturerName, productName, serialNumber, interfaces); + Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader()); + UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, + manufacturerName, productName, serialNumber); + device.setConfigurations(configurations); + return device; } public UsbDevice[] newArray(int size) { @@ -247,7 +309,7 @@ public class UsbDevice implements Parcelable { parcel.writeString(mManufacturerName); parcel.writeString(mProductName); parcel.writeString(mSerialNumber); - parcel.writeParcelableArray(mInterfaces, 0); + parcel.writeParcelableArray(mConfigurations, 0); } public static int getDeviceId(String name) { diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 389475fca6c9..628395159fc0 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -101,6 +101,25 @@ public class UsbDeviceConnection { } /** + * Sets the current {@link android.hardware.usb.UsbInterface}. + * Used to select between two interfaces with the same ID but different alternate setting. + * + * @return true if the interface was successfully released + */ + public boolean setInterface(UsbInterface intf) { + return native_set_interface(intf.getId(), intf.getAlternateSetting()); + } + + /** + * Sets the device's current {@link android.hardware.usb.UsbConfiguration}. + * + * @return true if the configuration was successfully set + */ + public boolean setConfiguration(UsbConfiguration configuration) { + return native_set_configuration(configuration.getId()); + } + + /** * Performs a control transaction on endpoint zero for this device. * The direction of the transfer is determined by the request type. * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is @@ -236,6 +255,8 @@ public class UsbDeviceConnection { private native byte[] native_get_desc(); private native boolean native_claim_interface(int interfaceID, boolean force); private native boolean native_release_interface(int interfaceID); + private native boolean native_set_interface(int interfaceID, int alternateSetting); + private native boolean native_set_configuration(int configurationID); private native int native_control_request(int requestType, int request, int value, int index, byte[] buffer, int offset, int length, int timeout); private native int native_bulk_request(int endpoint, byte[] buffer, diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java index e94baa16dcf3..de01a885d8c0 100644 --- a/core/java/android/hardware/usb/UsbInterface.java +++ b/core/java/android/hardware/usb/UsbInterface.java @@ -35,27 +35,31 @@ import android.os.Parcelable; public class UsbInterface implements Parcelable { private final int mId; + private final int mAlternateSetting; + private final String mName; private final int mClass; private final int mSubclass; private final int mProtocol; - private final Parcelable[] mEndpoints; + private Parcelable[] mEndpoints; /** * UsbInterface should only be instantiated by UsbService implementation * @hide */ - public UsbInterface(int id, int Class, int subClass, int protocol, - Parcelable[] endpoints) { + public UsbInterface(int id, int alternateSetting, String name, + int Class, int subClass, int protocol) { mId = id; + mAlternateSetting = alternateSetting; + mName = name; mClass = Class; mSubclass = subClass; mProtocol = protocol; - mEndpoints = endpoints; } /** - * Returns the interface's ID field. - * This is an integer that uniquely identifies the interface on the device. + * Returns the interface's bInterfaceNumber field. + * This is an integer that along with the alternate setting uniquely identifies + * the interface on the device. * * @return the interface's ID */ @@ -64,6 +68,28 @@ public class UsbInterface implements Parcelable { } /** + * Returns the interface's bAlternateSetting field. + * This is an integer that along with the ID uniquely identifies + * the interface on the device. + * {@link UsbDeviceConnection#setInterface} can be used to switch between + * two interfaces with the same ID but different alternate setting. + * + * @return the interface's alternate setting + */ + public int getAlternateSetting() { + return mAlternateSetting; + } + + /** + * Returns the interface's name. + * + * @return the interface's name + */ + public String getName() { + return mName; + } + + /** * Returns the interface's class field. * Some useful constants for USB classes can be found in {@link UsbConstants} * @@ -109,22 +135,42 @@ public class UsbInterface implements Parcelable { return (UsbEndpoint)mEndpoints[index]; } + /** + * Only used by UsbService implementation + * @hide + */ + public void setEndpoints(Parcelable[] endpoints) { + mEndpoints = endpoints; + } + @Override public String toString() { - return "UsbInterface[mId=" + mId + ",mClass=" + mClass + + StringBuilder builder = new StringBuilder("UsbInterface[mId=" + mId + + ",mAlternateSetting=" + mAlternateSetting + + ",mName=" + mName + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + - ",mEndpoints=" + mEndpoints + "]"; + ",mEndpoints=["); + for (int i = 0; i < mEndpoints.length; i++) { + builder.append("\n"); + builder.append(mEndpoints[i].toString()); + } + builder.append("]"); + return builder.toString(); } public static final Parcelable.Creator<UsbInterface> CREATOR = new Parcelable.Creator<UsbInterface>() { public UsbInterface createFromParcel(Parcel in) { int id = in.readInt(); + int alternateSetting = in.readInt(); + String name = in.readString(); int Class = in.readInt(); int subClass = in.readInt(); int protocol = in.readInt(); Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader()); - return new UsbInterface(id, Class, subClass, protocol, endpoints); + UsbInterface intf = new UsbInterface(id, alternateSetting, name, Class, subClass, protocol); + intf.setEndpoints(endpoints); + return intf; } public UsbInterface[] newArray(int size) { @@ -138,6 +184,8 @@ public class UsbInterface implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mId); + parcel.writeInt(mAlternateSetting); + parcel.writeString(mName); parcel.writeInt(mClass); parcel.writeInt(mSubclass); parcel.writeInt(mProtocol); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 18018e214dfe..40bbbd45ee2c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6082,6 +6082,24 @@ public final class Settings { "lock_screen_show_notifications"; /** + * Defines global zen mode. One of ZEN_MODE_OFF, ZEN_MODE_LIMITED, ZEN_MODE_FULL. + * + * @hide + */ + public static final String ZEN_MODE = "zen_mode"; + + /** @hide */ public static final int ZEN_MODE_OFF = 0; + /** @hide */ public static final int ZEN_MODE_LIMITED = 1; + /** @hide */ public static final int ZEN_MODE_FULL = 2; + + /** @hide */ public static String zenModeToString(int mode) { + if (mode == ZEN_MODE_OFF) return "ZEN_MODE_OFF"; + if (mode == ZEN_MODE_LIMITED) return "ZEN_MODE_LIMITED"; + if (mode == ZEN_MODE_FULL) return "ZEN_MODE_FULL"; + throw new IllegalArgumentException("Invalid zen mode: " + mode); + } + + /** * 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/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 66580f88c0b5..ffd5c45fb5d0 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -56,7 +56,6 @@ import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewParent; -import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -4479,6 +4478,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * scroll such that the indicated position is displayed, but it will * stop early if scrolling further would scroll boundPosition out of * view. + * * @param position Scroll to this adapter position. * @param boundPosition Do not scroll if it would move this adapter * position out of view. @@ -7128,7 +7128,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * understanding of layout. */ abstract class AbsSubPositionScroller extends AbsPositionScroller { - private static final int DEFAULT_SCROLL_DURATION = 200; + private static final int DURATION_AUTO = -1; + + private static final int DURATION_AUTO_MIN = 100; + private static final int DURATION_AUTO_MAX = 500; private final SubScroller mSubScroller = new SubScroller(); @@ -7157,9 +7160,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } + final int itemCount = getCount(); + final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1); final int firstPosition = getFirstVisiblePosition(); final int lastPosition = firstPosition + getChildCount(); - final int targetRow = getRowForPosition(targetPosition); + final int targetRow = getRowForPosition(clampedPosition); final int firstRow = getRowForPosition(firstPosition); final int lastRow = getRowForPosition(lastPosition); if (useOffset || targetRow <= firstRow) { @@ -7168,7 +7173,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } else if (targetRow >= lastRow - 1) { // Offset so the target row is bottom-aligned. final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - mOffset = listHeight - getHeightForPosition(targetPosition); + mOffset = getHeightForPosition(clampedPosition) - listHeight; } else { // Don't scroll, target is entirely on-screen. return; @@ -7190,7 +7195,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int firstChildHeight = firstChild.getHeight(); final float startOffsetRatio; if (firstChildHeight == 0) { - startOffsetRatio = 1; + startOffsetRatio = 0; } else { startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight; } @@ -7202,40 +7207,63 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } - mSubScroller.startScroll(startSubRow, endSubRow, duration); + final int durationMillis; + if (duration == DURATION_AUTO) { + final float subRowDelta = Math.abs(startSubRow - endSubRow); + durationMillis = (int) MathUtils.lerp( + DURATION_AUTO_MIN, DURATION_AUTO_MAX, subRowDelta / getCount()); + } else { + durationMillis = duration; + } + + mSubScroller.startScroll(startSubRow, endSubRow, durationMillis); postOnAnimation(mAnimationFrame); } - private float computeBoundSubRow(int targetRow, int boundRow) { - // If the final offset is greater than 0, we're aiming above the - // suggested target row. Compute the actual target row and offset - // within that row by subtracting the height of each preceeding row. - int remainingOffset = mOffset; + /** + * Given a target row and offset, computes the sub-row position that + * aligns with the top of the list. If the offset is negative, the + * resulting sub-row will be smaller than the target row. + */ + private float resolveOffset(int targetRow, int offset) { + // Compute the target sub-row position by finding the actual row + // indicated by the target and offset. + int remainingOffset = offset; int targetHeight = getHeightForRow(targetRow); - while (targetRow > 1 && remainingOffset > targetHeight) { - targetRow--; - remainingOffset -= targetHeight; - targetHeight = getHeightForRow(targetRow); + if (offset < 0) { + // Subtract row heights until we find the right row. + while (targetRow > 0 && remainingOffset < 0) { + remainingOffset += targetHeight; + targetRow--; + targetHeight = getHeightForRow(targetRow); + } + } else if (offset > 0) { + // Add row heights until we find the right row. + while (targetRow < getCount() - 1 && remainingOffset > targetHeight) { + remainingOffset -= targetHeight; + targetRow++; + targetHeight = getHeightForRow(targetRow); + } } - // Compute the offset within the actual target row. final float targetOffsetRatio; - if (remainingOffset > 0) { - // We can't reach that offset given the row count. + if (remainingOffset < 0 || targetHeight == 0) { targetOffsetRatio = 0; - } else if (targetHeight == 0) { - targetOffsetRatio = 1; } else { targetOffsetRatio = remainingOffset / (float) targetHeight; } - // The final offset has been accounted for, reset it. - final float targetSubRow = targetRow - targetOffsetRatio; + return targetRow + targetOffsetRatio; + } + + private float computeBoundSubRow(int targetRow, int boundRow) { + final float targetSubRow = resolveOffset(targetRow, mOffset); mOffset = 0; + // The target row is below the bound row, so the end position would + // push the bound position above the list. Abort! if (targetSubRow >= boundRow) { - // End position would push the bound position above the list. return boundRow; } @@ -7243,39 +7271,24 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // bound position's view further below the list. final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); final int boundHeight = getHeightForRow(boundRow); - int endRow = boundRow; - int totalHeight = boundHeight; - int endHeight; - do { - endRow--; - endHeight = getHeightForRow(endRow); - totalHeight += endHeight; - } while (totalHeight < listHeight && endRow > 0); - - final float endOffsetRatio; - if (endHeight == 0) { - endOffsetRatio = 1; - } else { - endOffsetRatio = (totalHeight - listHeight) / (float) endHeight; - } + final float boundSubRow = resolveOffset(boundRow, -listHeight + boundHeight); - final float boundSubRow = endRow + endOffsetRatio; return Math.max(boundSubRow, targetSubRow); } @Override public void start(int position) { - scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, false, 0, INVALID_POSITION, DURATION_AUTO); } @Override public void start(int position, int boundPosition) { - scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, false, 0, boundPosition, DURATION_AUTO); } @Override public void startWithOffset(int position, int offset) { - scrollToPosition(position, true, offset, INVALID_POSITION, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, true, offset, INVALID_POSITION, DURATION_AUTO); } @Override @@ -7327,7 +7340,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int rowHeight = getHeightForRow(row); final int offset = (int) (rowHeight * (subRow - row)); final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue()); - setSelectionFromTop(position, -offset + addOffset); + setSelectionFromTop(position, -offset - addOffset); if (shouldPost) { postOnAnimation(mAnimationFrame); @@ -7346,7 +7359,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * Scroller capable of returning floating point positions. */ static class SubScroller { - private final Interpolator mInterpolator; + private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator(); private float mStartPosition; private float mEndPosition; @@ -7356,18 +7369,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private float mPosition; private float mInterpolatedValue; - public SubScroller() { - this(null); - } - - public SubScroller(Interpolator interpolator) { - if (interpolator == null) { - mInterpolator = new AccelerateDecelerateInterpolator(); - } else { - mInterpolator = interpolator; - } - } - public void startScroll(float startPosition, float endPosition, int duration) { mStartPosition = startPosition; mEndPosition = endPosition; @@ -7387,7 +7388,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1); } - mInterpolatedValue = mInterpolator.getInterpolation(value); + mInterpolatedValue = INTERPOLATOR.getInterpolation(value); mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition; return elapsed < mDuration; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index bf62745f254f..05c57e8997cf 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -244,9 +244,11 @@ public class ZygoteInit { } static void preload() { + Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); + Log.d(TAG, "end preload"); } private static void preloadOpenGL() { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 5056c57847ba..cf69d9eea956 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -164,9 +164,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/include \ $(TOP)/system/media/camera/include \ external/skia/src/core \ - external/skia/src/pdf \ external/skia/src/images \ - external/skia/include/utils \ external/sqlite/dist \ external/sqlite/android \ external/expat/lib \ diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index c10b963f578f..467a9a124fc4 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -123,20 +123,45 @@ android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz, return (ret == 0) ? JNI_TRUE : JNI_FALSE; } -static jint +static jboolean android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, jint interfaceID) { struct usb_device* device = get_device_from_object(env, thiz); if (!device) { ALOGE("device is closed in native_release_interface"); - return -1; + return JNI_FALSE; } int ret = usb_device_release_interface(device, interfaceID); if (ret == 0) { // allow kernel to reconnect its driver usb_device_connect_kernel_driver(device, interfaceID, true); } - return ret; + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean +android_hardware_UsbDeviceConnection_set_interface(JNIEnv *env, jobject thiz, jint interfaceID, + jint alternateSetting) +{ + struct usb_device* device = get_device_from_object(env, thiz); + if (!device) { + ALOGE("device is closed in native_set_interface"); + return JNI_FALSE; + } + int ret = usb_device_set_interface(device, interfaceID, alternateSetting); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean +android_hardware_UsbDeviceConnection_set_configuration(JNIEnv *env, jobject thiz, jint configurationID) +{ + struct usb_device* device = get_device_from_object(env, thiz); + if (!device) { + ALOGE("device is closed in native_set_configuration"); + return JNI_FALSE; + } + int ret = usb_device_set_configuration(device, configurationID); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; } static jint @@ -229,6 +254,8 @@ static JNINativeMethod method_table[] = { {"native_get_desc", "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc}, {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface}, {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface}, + {"native_set_interface","(II)Z", (void *)android_hardware_UsbDeviceConnection_set_interface}, + {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration}, {"native_control_request", "(IIII[BIII)I", (void *)android_hardware_UsbDeviceConnection_control_request}, {"native_bulk_request", "(I[BIII)I", diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 1c5be420c8df..42fa1061fb78 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2357,8 +2357,8 @@ <!-- Sets whether or not this ViewGroup should be treated as a single entity when doing an Activity transition. Typically, the elements inside a ViewGroup are each transitioned from the scene individually. The default - for a ViewGroup is false unless it has a background. - See {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)} + for a ViewGroup is false unless it has a background. See + {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.View, String)} for more information. --> <attr name="transitionGroup" format="boolean" /> </declare-styleable> diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 495ad195d130..2cc7a848d898 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -61,12 +61,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ $(LOCAL_PATH)/../../include/utils \ - external/skia/include/core \ - external/skia/include/effects \ - external/skia/include/images \ - external/skia/src/core \ - external/skia/src/ports \ - external/skia/include/utils + external/skia/src/core LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES LOCAL_CFLAGS += -Wno-unused-parameter diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 62f6c7636883..7a2e288af13f 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -112,6 +112,15 @@ void DeferredLayerUpdater::doUpdateTexImage() { frameNumber = newFrameNumber; dropCounter++; } + + bool forceFilter = false; + sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer(); + if (buffer != NULL) { + // force filtration if buffer size != layer size + forceFilter = mWidth != buffer->getWidth() + || mHeight != buffer->getHeight(); + } + #if DEBUG_RENDERER if (dropCounter > 0) { RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter); @@ -120,8 +129,8 @@ void DeferredLayerUpdater::doUpdateTexImage() { mSurfaceTexture->getTransformMatrix(transform); GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget(); - LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, !mBlend, - renderTarget, transform); + LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, + !mBlend, forceFilter, renderTarget, transform); } } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 54ce64f4069d..8992a13a5c91 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -46,6 +46,7 @@ Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight): stencil = NULL; debugDrawUpdate = false; hasDrawnSinceUpdate = false; + forceFilter = false; deferredList = NULL; caches.resourceCache.incrementRefcount(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 8cc027ae117a..f6538f29dcc4 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -127,6 +127,14 @@ public: return texture.blend; } + inline void setForceFilter(bool forceFilter) { + this->forceFilter = forceFilter; + } + + inline bool getForceFilter() const { + return forceFilter; + } + inline void setAlpha(int alpha) { this->alpha = alpha; } @@ -343,9 +351,15 @@ private: SkColorFilter* colorFilter; /** + * Indicates raster data backing the layer is scaled, requiring filtration. + */ + bool forceFilter; + + /** * Opacity of the layer. */ int alpha; + /** * Blending mode of the layer. */ diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index ea8eb31f8437..e0ac2ba31faa 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -290,14 +290,15 @@ Layer* LayerRenderer::createTextureLayer() { } void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, GLenum renderTarget, float* transform) { + bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) { if (layer) { layer->setBlend(!isOpaque); + layer->setForceFilter(forceFilter); layer->setSize(width, height); layer->layer.set(0.0f, 0.0f, width, height); layer->region.set(width, height); layer->regionRect.set(0.0f, 0.0f, width, height); - layer->getTexTransform().load(transform); + layer->getTexTransform().load(textureTransform); if (renderTarget != layer->getRenderTarget()) { layer->setRenderTarget(renderTarget); diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 84acd4452000..40e461a345dc 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -56,7 +56,7 @@ public: ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height); ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, GLenum renderTarget, float* transform); + bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform); ANDROID_API static void destroyLayer(Layer* layer); ANDROID_API static void destroyLayerDeferred(Layer* layer); ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 9ac2792a716f..1c59c3065ee9 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1068,6 +1068,7 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawExternalTexture(layer->getTexture()); } if (currentTransform()->isPureTranslate() && + !layer->getForceFilter() && layer->getWidth() == (uint32_t) rect.getWidth() && layer->getHeight() == (uint32_t) rect.getHeight()) { const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); diff --git a/libs/input/Android.mk b/libs/input/Android.mk index 6011ff03c1c8..a7fb0e212489 100644 --- a/libs/input/Android.mk +++ b/libs/input/Android.mk @@ -31,7 +31,6 @@ LOCAL_SHARED_LIBRARIES := \ libinputflinger LOCAL_C_INCLUDES := \ - external/skia/include/core \ frameworks/native/services diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk index ad874c894fd1..95ae33bc29a1 100644 --- a/media/tests/omxjpegdecoder/Android.mk +++ b/media/tests/omxjpegdecoder/Android.mk @@ -34,11 +34,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES := \ $(TOP)/external/jpeg \ - $(TOP)/external/skia/include/config \ - $(TOP)/external/skia/include/core \ - $(TOP)/external/skia/include/images \ - $(TOP)/external/skia/include/utils \ - $(TOP)/external/skia/include/effects \ $(TOP)/frameworks/base/media/libstagefright \ $(TOP)/frameworks/base/include/ \ $(TOP)/frameworks/base/ \ diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk index 8b333e729454..31540307f586 100644 --- a/native/graphics/jni/Android.mk +++ b/native/graphics/jni/Android.mk @@ -23,7 +23,6 @@ LOCAL_SHARED_LIBRARIES := \ libskia LOCAL_C_INCLUDES += \ - external/skia/include/core \ frameworks/base/native/include \ frameworks/base/core/jni/android/graphics diff --git a/opengl/java/android/opengl/EGLObjectHandle.java b/opengl/java/android/opengl/EGLObjectHandle.java index e6e397602def..113f867c404f 100644 --- a/opengl/java/android/opengl/EGLObjectHandle.java +++ b/opengl/java/android/opengl/EGLObjectHandle.java @@ -24,36 +24,35 @@ package android.opengl; public abstract class EGLObjectHandle { private final long mHandle; - // TODO Deprecate EGLObjectHandle(int) method + /** + * @deprecated Use {@link EGLObjectHandle(long)} instead. Handles + * on 64 bit platforms will be wider than java ints. + */ + @Deprecated protected EGLObjectHandle(int handle) { mHandle = handle; } - // TODO Unhide the EGLObjectHandle(long) method - /** - * {@hide} - */ protected EGLObjectHandle(long handle) { mHandle = handle; } - // TODO Deprecate getHandle() method in favor of getNativeHandle() /** - * Returns the native handle of the wrapped EGL object. This handle can be - * cast to the corresponding native type on the native side. - * - * For example, EGLDisplay dpy = (EGLDisplay)handle; - * - * @return the native handle of the wrapped EGL object. + * @deprecated Use {@link #getNativeHandle()} instead. Handles on + * 64 bit platforms will be wider than java ints. */ + @Deprecated public int getHandle() { if ((mHandle & 0xffffffffL) != mHandle) { throw new UnsupportedOperationException(); } return (int)mHandle; } - - // TODO Unhide getNativeHandle() method /** - * {@hide} + * Returns the native handle of the wrapped EGL object. This handle can be + * cast to the corresponding native type on the native side. + * + * For example, EGLDisplay dpy = (EGLDisplay)handle; + * + * @return the native handle of the wrapped EGL object. */ public long getNativeHandle() { return mHandle; diff --git a/packages/SystemUI/res/anim/heads_up_exit.xml b/packages/SystemUI/res/anim/heads_up_exit.xml index 05c144a1720d..2cad8f6fc2a4 100644 --- a/packages/SystemUI/res/anim/heads_up_exit.xml +++ b/packages/SystemUI/res/anim/heads_up_exit.xml @@ -1,13 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > - <scale - android:interpolator="@android:interpolator/accelerate_quad" - android:fromXScale="1.0" android:toXScale="0.7" - android:fromYScale="1.0" android:toYScale="0.7" - android:pivotX="50%" android:pivotY="50%" - android:duration="@android:integer/config_shortAnimTime" /> - <alpha + <translate + android:interpolator="@android:interpolator/overshoot" + android:fromYDelta="0" android:toYDelta="-50%" + android:duration="@android:integer/config_shortAnimTime" /> + <alpha android:interpolator="@android:interpolator/accelerate_quad" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="@android:integer/config_shortAnimTime" /> diff --git a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png Binary files differdeleted file mode 100644 index 3b952d0f06aa..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png Binary files differnew file mode 100644 index 000000000000..267e7bac65e2 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png Binary files differnew file mode 100644 index 000000000000..fa23e857d970 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png Binary files differnew file mode 100644 index 000000000000..aa8635c29412 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png diff --git a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png Binary files differdeleted file mode 100644 index a0ab991185f5..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png Binary files differnew file mode 100644 index 000000000000..db51f6b6b551 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png Binary files differnew file mode 100644 index 000000000000..b0185a54d1da --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png Binary files differnew file mode 100644 index 000000000000..949ab10ca2e0 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png Binary files differindex 6002cfbe95d7..31eb8f72010b 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png Binary files differindex 586a7385993f..c76d0e1788d1 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png Binary files differdeleted file mode 100644 index 42e5593f8206..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png Binary files differnew file mode 100644 index 000000000000..8d22ce23391e --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png Binary files differnew file mode 100644 index 000000000000..7f7cb6380377 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png Binary files differnew file mode 100644 index 000000000000..abdeb3bfed3c --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png Binary files differdeleted file mode 100644 index 586a7385993f..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png Binary files differnew file mode 100644 index 000000000000..29fb50f820ed --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png Binary files differnew file mode 100644 index 000000000000..afe85b4ce0bf --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png Binary files differnew file mode 100644 index 000000000000..5e5053fb00e0 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png diff --git a/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml deleted file mode 100644 index 59d9fcfc7a16..000000000000 --- a/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android" - android:exitFadeDuration="@android:integer/config_mediumAnimTime"> - <item android:state_pressed="true" - android:drawable="@drawable/heads_up_notification_bg_pressed" /> -</selector> diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml new file mode 100644 index 000000000000..71f7c212d4fa --- /dev/null +++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<com.android.systemui.statusbar.policy.HeadsUpNotificationView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="match_parent" + > + <FrameLayout + android:id="@+id/content_holder" + android:layout_height="wrap_content" + android:layout_width="@dimen/notification_panel_width" + android:layout_marginStart="@dimen/notification_panel_margin_left" + android:background="@drawable/heads_up_window_bg" + /> +</com.android.systemui.statusbar.policy.HeadsUpNotificationView> diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml index 564dc51cbe66..3a58b845eb92 100644 --- a/packages/SystemUI/res/layout/heads_up.xml +++ b/packages/SystemUI/res/layout/heads_up.xml @@ -17,25 +17,11 @@ ** limitations under the License. */ --> - -<!-- android:background="@drawable/status_bar_closed_default_background" --> <com.android.systemui.statusbar.policy.HeadsUpNotificationView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:orientation="vertical" - > - <FrameLayout - android:layout_height="wrap_content" - android:layout_width="@dimen/notification_panel_width" - android:id="@+id/content_slider" - android:layout_marginStart="@dimen/notification_panel_margin_left" - > - <FrameLayout - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:id="@+id/content_holder" - android:background="@drawable/heads_up_window_bg" - /> - </FrameLayout> -</com.android.systemui.statusbar.policy.HeadsUpNotificationView> + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="@dimen/notification_panel_width" + android:id="@+id/content_holder" + android:layout_marginStart="@dimen/notification_panel_margin_left" + android:background="@drawable/notification_panel_bg" + />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index eb6690839a30..ea6be1b96149 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -62,7 +62,11 @@ android:src="@drawable/stat_notify_more" android:visibility="gone" /> - + <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/modeIcon" + android:layout_width="@dimen/status_bar_icon_size" + android:layout_height="match_parent" + android:visibility="gone" + /> <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 1693e01c3d01..56c1f4ed5c6c 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -58,6 +58,12 @@ android:layout_height="@dimen/notification_panel_header_height" /> + <com.android.systemui.statusbar.phone.ZenModeView + android:id="@+id/zenmode" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + <TextView android:id="@+id/emergency_calls_only" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 9aa7cfdf3666..25c516b31c00 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -15,7 +15,7 @@ ** limitations under the License. --> -<LinearLayout +<com.android.systemui.statusbar.phone.PanelHeaderView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/header" @@ -106,4 +106,4 @@ android:contentDescription="@string/accessibility_notifications_button" /> </FrameLayout> -</LinearLayout> +</com.android.systemui.statusbar.phone.PanelHeaderView> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 7ff52de0c1b0..c3ed1f7aa3d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -104,6 +104,9 @@ public abstract class BaseStatusBar extends SystemUI implements public static final int EXPANDED_LEAVE_ALONE = -10000; public static final int EXPANDED_FULL_OPEN = -10001; + private static final String EXTRA_INTERCEPT = "android.intercept"; + private static final float INTERCEPTED_ALPHA = .2f; + protected CommandQueue mCommandQueue; protected IStatusBarService mBarService; protected H mHandler = createHandler(); @@ -155,6 +158,8 @@ public abstract class BaseStatusBar extends SystemUI implements private RecentsComponent mRecents; + protected int mZenMode; + public IStatusBarService getStatusBarService() { return mBarService; } @@ -163,7 +168,7 @@ public abstract class BaseStatusBar extends SystemUI implements return mDeviceProvisioned; } - private final ContentObserver mProvisioningObserver = new ContentObserver(mHandler) { + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { final boolean provisioned = 0 != Settings.Global.getInt( @@ -172,6 +177,9 @@ public abstract class BaseStatusBar extends SystemUI implements mDeviceProvisioned = provisioned; updateNotificationIcons(); } + final int mode = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + setZenMode(mode); } }; @@ -239,10 +247,13 @@ public abstract class BaseStatusBar extends SystemUI implements ServiceManager.checkService(DreamService.DREAM_SERVICE)); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mProvisioningObserver.onChange(false); // set up + mSettingsObserver.onChange(false); // set up mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true, - mProvisioningObserver); + mSettingsObserver); + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, + mSettingsObserver); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), @@ -980,6 +991,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.d(TAG, "addNotificationViews: added at " + pos); } + updateInterceptedState(entry); updateExpansionStates(); updateNotificationIcons(); } @@ -1010,6 +1022,35 @@ public abstract class BaseStatusBar extends SystemUI implements } } + protected void setZenMode(int mode) { + if (!isDeviceProvisioned()) return; + final boolean change = mZenMode != mode; + mZenMode = mode; + final int N = mNotificationData.size(); + for (int i = 0; i < N; i++) { + final NotificationData.Entry entry = mNotificationData.get(i); + if (change && !shouldIntercept()) { + entry.notification.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false); + } + updateInterceptedState(entry); + } + updateNotificationIcons(); + } + + private boolean shouldIntercept() { + return mZenMode == Settings.Global.ZEN_MODE_LIMITED + || mZenMode == Settings.Global.ZEN_MODE_FULL; + } + + protected boolean shouldIntercept(Notification n) { + return shouldIntercept() && n.extras.getBoolean(EXTRA_INTERCEPT); + } + + private void updateInterceptedState(NotificationData.Entry entry) { + final boolean intercepted = shouldIntercept(entry.notification.getNotification()); + entry.row.findViewById(R.id.container).setAlpha(intercepted ? INTERCEPTED_ALPHA : 1); + } + protected abstract void haltTicker(); protected abstract void setAreThereNotifications(); protected abstract void updateNotificationIcons(); @@ -1202,6 +1243,7 @@ public abstract class BaseStatusBar extends SystemUI implements } else { entry.content.setOnClickListener(null); } + updateInterceptedState(entry); } protected void notifyHeadsUpScreenOn(boolean screenOn) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 6be6d4d43a19..ae7440744908 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -56,6 +56,10 @@ public class NotificationPanelView extends PanelView { mHandleBar = resources.getDrawable(R.drawable.status_bar_close); mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height); mHandleView = findViewById(R.id.handle); + PanelHeaderView header = (PanelHeaderView) findViewById(R.id.header); + ZenModeView zenModeView = (ZenModeView) findViewById(R.id.zenmode); + zenModeView.setAdapter( new ZenModeViewAdapter(mContext)); + header.setZenModeView(zenModeView); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java new file mode 100644 index 000000000000..a28324d9cb4f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.widget.LinearLayout; + +public class PanelHeaderView extends LinearLayout { + private static final String TAG = "PanelHeaderView"; + private static final boolean DEBUG = false; + + private ZenModeView mZenModeView; + + public PanelHeaderView(Context context) { + super(context); + } + + public PanelHeaderView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setZenModeView(ZenModeView zmv) { + mZenModeView = zmv; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final boolean rt = super.dispatchTouchEvent(ev); + if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev); + if (mZenModeView != null) { + mZenModeView.dispatchExternalTouchEvent(ev); + } + return rt; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + final boolean rt = super.onInterceptTouchEvent(ev); + if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev); + return rt; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean rt = super.onTouchEvent(event); + if (DEBUG) logTouchEvent("onTouchEvent", rt, event); + return true; + } + + private void logTouchEvent(String method, boolean rt, MotionEvent ev) { + Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + ev); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 211499132741..51d06693c29a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -189,6 +189,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { IconMerger mNotificationIcons; // [+> View mMoreIcon; + // mode indicator icon + ImageView mModeIcon; // expanded notifications NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -341,6 +343,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { }}; @Override + public void setZenMode(int mode) { + super.setZenMode(mode); + if (mModeIcon == null) return; + if (!isDeviceProvisioned()) return; + final boolean limited = mode == Settings.Global.ZEN_MODE_LIMITED; + final boolean full = mode == Settings.Global.ZEN_MODE_FULL; + mModeIcon.setVisibility(full || limited ? View.VISIBLE : View.GONE); + final int icon = limited ? R.drawable.stat_sys_zen_limited : R.drawable.stat_sys_zen_full; + if (full || limited) { + mModeIcon.setImageResource(icon); + } + } + + @Override public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); @@ -352,6 +368,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // Lastly, call to the icon policy to install/update all the icons. mIconPolicy = new PhoneStatusBarPolicy(mContext); + mSettingsObserver.onChange(false); // set up mHeadsUpObserver.onChange(true); // set up if (ENABLE_HEADS_UP) { @@ -455,6 +472,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon); mNotificationIcons.setOverflowIndicator(mMoreIcon); + mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon); mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents); mTickerView = mStatusBarView.findViewById(R.id.ticker); @@ -855,7 +873,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { PixelFormat.TRANSLUCENT); lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; lp.gravity = Gravity.TOP; - lp.y = getStatusBarHeight(); lp.setTitle("Heads Up"); lp.packageName = mContext.getPackageName(); lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp; @@ -909,41 +926,43 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (shadeEntry == null) { return; } - if (mUseHeadsUp && shouldInterrupt(notification)) { - if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); - Entry interruptionCandidate = new Entry(key, notification, null); - ViewGroup holder = mHeadsUpNotificationView.getHolder(); - if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { - mInterruptingNotificationTime = System.currentTimeMillis(); - mInterruptingNotificationEntry = interruptionCandidate; - shadeEntry.setInterruption(); + if (!shouldIntercept(notification.getNotification())) { + if (mUseHeadsUp && shouldInterrupt(notification)) { + if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); + Entry interruptionCandidate = new Entry(key, notification, null); + ViewGroup holder = mHeadsUpNotificationView.getHolder(); + if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { + mInterruptingNotificationTime = System.currentTimeMillis(); + mInterruptingNotificationEntry = interruptionCandidate; + shadeEntry.setInterruption(); - // 1. Populate mHeadsUpNotificationView - mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry); + // 1. Populate mHeadsUpNotificationView + mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry); - // 2. Animate mHeadsUpNotificationView in - mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); + // 2. Animate mHeadsUpNotificationView in + mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); - // 3. Set alarm to age the notification off - resetHeadsUpDecayTimer(); - } - } else if (notification.getNotification().fullScreenIntent != null) { - // Stop screensaver if the notification has a full-screen intent. - // (like an incoming phone call) - awakenDreams(); + // 3. Set alarm to age the notification off + resetHeadsUpDecayTimer(); + } + } else if (notification.getNotification().fullScreenIntent != null) { + // Stop screensaver if the notification has a full-screen intent. + // (like an incoming phone call) + awakenDreams(); - // not immersive & a full-screen alert should be shown - if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); - try { - notification.getNotification().fullScreenIntent.send(); - } catch (PendingIntent.CanceledException e) { - } - } else { - // usual case: status bar visible & not immersive + // not immersive & a full-screen alert should be shown + if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); + try { + notification.getNotification().fullScreenIntent.send(); + } catch (PendingIntent.CanceledException e) { + } + } else { + // usual case: status bar visible & not immersive - // show the ticker if there isn't already a heads up - if (mInterruptingNotificationEntry == null) { - tick(null, notification, true); + // show the ticker if there isn't already a heads up + if (mInterruptingNotificationEntry == null) { + tick(null, notification, true); + } } } addNotificationViews(shadeEntry); @@ -1096,6 +1115,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // in "public" mode (atop a secure keyguard), secret notifs are totally hidden continue; } + if (shouldIntercept(ent.notification.getNotification())) { + continue; + } toShow.add(ent.icon); } @@ -2183,6 +2205,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { pw.println(windowStateToString(mStatusBarWindowState)); pw.print(" mStatusBarMode="); pw.println(BarTransitions.modeToString(mStatusBarMode)); + pw.print(" mZenMode="); + pw.println(Settings.Global.zenModeToString(mZenMode)); dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); if (mNavigationBarView != null) { pw.print(" mNavigationBarWindowState="); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java new file mode 100644 index 000000000000..f5dc4d993e07 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.PathShape; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.RelativeSizeSpan; +import android.text.style.URLSpan; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.PopupWindow; +import android.widget.RelativeLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition; + +public class ZenModeView extends RelativeLayout { + private static final String TAG = ZenModeView.class.getSimpleName(); + private static final boolean DEBUG = false; + + private static final Typeface CONDENSED = + Typeface.create("sans-serif-condensed", Typeface.NORMAL); + private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network + private static final int BACKGROUND = 0xff1d3741; //0x3333b5e5; + private static final long DURATION = new ValueAnimator().getDuration(); + private static final long BOUNCE_DURATION = DURATION / 3; + private static final float BOUNCE_SCALE = 0.8f; + private static final float SETTINGS_ALPHA = 0.6f; + private static final int INFO_WINDOW_DELAY = 2000; + + private static final String LIMITED_TEXT = + "New notifications suppressed except calls, alarms & timers."; + private static final String FULL_TEXT = + "You won't hear any calls, alarms or timers."; + + private final Context mContext; + private final Paint mPathPaint; + private final TextView mHintText; + private final ModeSpinner mModeSpinner; + private final ImageView mCloseButton; + private final ImageView mSettingsButton; + private final InfoWindow mInfoWindow; + private final Rect mLayoutRect = new Rect(); + private final UntilPager mUntilPager; + private final AlarmWarning mAlarmWarning; + + private float mDownY; + private int mDownBottom; + private boolean mPeekable = true; + private boolean mClosing; + private int mBottom; + private int mWidthSpec; + private Adapter mAdapter; + + public ZenModeView(Context context) { + this(context, null); + } + + public ZenModeView(Context context, AttributeSet attrs) { + super(context, attrs); + if (DEBUG) log("new %s()", getClass().getSimpleName()); + mContext = context; + + mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPathPaint.setStyle(Paint.Style.STROKE); + mPathPaint.setColor(GRAY); + mPathPaint.setStrokeWidth(5); + + final int iconSize = mContext.getResources() + .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width); + final int topRowSize = iconSize * 2 / 3; + + mCloseButton = new ImageView(mContext); + mCloseButton.setAlpha(0f); + mCloseButton.setImageDrawable(sd(closePath(topRowSize), topRowSize, mPathPaint)); + addView(mCloseButton, new LayoutParams(topRowSize, topRowSize)); + mCloseButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + bounce(v, null); + close(); + } + }); + + mSettingsButton = new ImageView(mContext); + mSettingsButton.setAlpha(0f); + final int p = topRowSize / 7; + mSettingsButton.setPadding(p, p, p, p); + mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal); + LayoutParams lp = new LayoutParams(topRowSize, topRowSize); + lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + addView(mSettingsButton, lp); + mSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mAdapter == null || mAdapter.getMode() != Adapter.MODE_LIMITED) { + return; + } + if (!mInfoWindow.isShowing()) { + mInfoWindow.show(mUntilPager); + } + bounce(mSettingsButton, null); + } + }); + mInfoWindow = new InfoWindow(mContext, LIMITED_TEXT); + + mModeSpinner = new ModeSpinner(mContext); + mModeSpinner.setAlpha(0); + mModeSpinner.setEnabled(false); + mModeSpinner.setId(android.R.id.title); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize); + lp.addRule(RelativeLayout.CENTER_HORIZONTAL); + addView(mModeSpinner, lp); + + + mUntilPager = new UntilPager(mContext, mPathPaint, iconSize); + mUntilPager.setId(android.R.id.tabhost); + mUntilPager.setAlpha(0); + lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.addRule(BELOW, mModeSpinner.getId()); + addView(mUntilPager, lp); + + mAlarmWarning = new AlarmWarning(mContext); + mAlarmWarning.setAlpha(0); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp.addRule(CENTER_HORIZONTAL); + lp.addRule(BELOW, mUntilPager.getId()); + addView(mAlarmWarning, lp); + + mHintText = new TextView(mContext); + mHintText.setTypeface(CONDENSED); + mHintText.setText("Swipe down for Limited Interruptions"); + mHintText.setGravity(Gravity.CENTER); + mHintText.setTextColor(GRAY); + addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + } + + private boolean isApplicable() { + return mAdapter != null && mAdapter.isApplicable(); + } + + private void close() { + mClosing = true; + final int startBottom = mBottom; + final int max = mPeekable ? getExpandedBottom() : startBottom; + mHintText.animate().alpha(1).setUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + final float f = animation.getAnimatedFraction(); + final int hintBottom = mHintText.getBottom(); + setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max); + if (f == 1) { + mPeekable = true; + mClosing = false; + mModeSpinner.updateState(); + if (mAdapter != null) { + mAdapter.cancel(); + } + } + } + }).start(); + mUntilPager.animate().alpha(0).start(); + mAlarmWarning.animate().alpha(0).start(); + mInfoWindow.dismiss(); + } + + public void setAdapter(Adapter adapter) { + mAdapter = adapter; + mAdapter.setCallbacks(new Adapter.Callbacks() { + @Override + public void onChanged() { + post(new Runnable() { + @Override + public void run() { + updateState(true); + } + }); + } + }); + updateState(false); + } + + private void updateState(boolean animate) { + final boolean applicable = isApplicable(); + setVisibility(applicable ? VISIBLE : GONE); + if (!applicable) { + return; + } + if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_OFF && !mPeekable) { + close(); + } else { + mModeSpinner.updateState(); + mUntilPager.updateState(); + mAlarmWarning.updateState(animate); + final float settingsAlpha = getSettingsButtonAlpha(); + if (settingsAlpha != mSettingsButton.getAlpha()) { + if (animate) { + mSettingsButton.animate().alpha(settingsAlpha).start(); + } else { + mSettingsButton.setAlpha(settingsAlpha); + } + } + if (mPeekable && mAdapter != null && mAdapter.getMode() != Adapter.MODE_OFF) { + if (DEBUG) log("panic expand!"); + mPeekable = false; + mModeSpinner.setEnabled(true); + mBottom = getExpandedBottom(); + setExpanded(1); + } + mInfoWindow.dismiss(); + } + } + + private float getSettingsButtonAlpha() { + final boolean full = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL; + final boolean collapsed = mHintText.getAlpha() == 1; + return full || collapsed ? 0 : SETTINGS_ALPHA; + } + + private static Path closePath(int size) { + final int pad = size / 4; + final Path p = new Path(); + p.moveTo(pad, pad); + p.lineTo(size - pad, size - pad); + p.moveTo(size - pad, pad); + p.lineTo(pad, size - pad); + return p; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (DEBUG) log("onMeasure %s %s", + MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec)); + if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) { + throw new UnsupportedOperationException("Width must be exact"); + } + if (widthMeasureSpec != mWidthSpec) { + if (DEBUG) log(" super.onMeasure"); + final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + super.onMeasure(widthMeasureSpec, hms); + mBottom = mPeekable ? mHintText.getMeasuredHeight() : getExpandedBottom(); + mWidthSpec = widthMeasureSpec; + } + if (DEBUG) log("mBottom (OM) = " + mBottom); + setMeasuredDimension(getMeasuredWidth(), mBottom); + if (DEBUG) log(" mw=%s mh=%s", + toString(getMeasuredWidthAndState()), toString(getMeasuredHeightAndState())); + } + + private static String toString(int sizeAndState) { + final int size = sizeAndState & MEASURED_SIZE_MASK; + final boolean tooSmall = (sizeAndState & MEASURED_STATE_TOO_SMALL) != 0; + return size + (tooSmall ? "TOO SMALL" : ""); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mLayoutRect.set(left, top, right, bottom); + if (DEBUG) log("onLayout %s %s %dx%d", changed, + mLayoutRect.toShortString(), mLayoutRect.width(), mLayoutRect.height()); + super.onLayout(changed, left, top, right, bottom); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final boolean rt = super.dispatchTouchEvent(ev); + if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev); + return rt; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + final boolean rt = super.onInterceptTouchEvent(ev); + if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev); + if (isApplicable() + && ev.getAction() == MotionEvent.ACTION_DOWN + && ev.getY() > mCloseButton.getBottom() + && mPeekable) { + return true; + } + return rt; + } + + private static void logTouchEvent(String method, boolean rt, MotionEvent event) { + final String action = MotionEvent.actionToString(event.getAction()); + Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + action); + } + + private int getExpandedBottom() { + int b = mModeSpinner.getMeasuredHeight() + mUntilPager.getMeasuredHeight(); + if (mAlarmWarning.getAlpha() == 1) b += mAlarmWarning.getMeasuredHeight(); + return b; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean rt = super.onTouchEvent(event); + if (DEBUG) logTouchEvent("onTouchEvent", rt, event); + if (!isApplicable() || !mPeekable) { + return rt; + } + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mDownY = event.getY(); + if (DEBUG) log(" mDownY=" + mDownY); + mDownBottom = mBottom; + return true; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + final float dy = event.getY() - mDownY; + setPeeked(mDownBottom + (int)dy, getExpandedBottom()); + } else if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + final float dy = event.getY() - mDownY; + setPeeked(mDownBottom + (int)dy, getExpandedBottom()); + if (mPeekable) { + close(); + } + } + return rt; + } + + private void setPeeked(int peeked, int max) { + if (DEBUG) log("setPeeked=" + peeked); + final int min = mHintText.getBottom(); + peeked = Math.max(min, Math.min(peeked, max)); + if (mBottom == peeked) { + return; + } + if (peeked == max) { + mPeekable = false; + mModeSpinner.setEnabled(true); + if (mAdapter != null) { + mAdapter.setMode(Adapter.MODE_LIMITED); + } + } + if (peeked == min) { + mPeekable = true; + mModeSpinner.setEnabled(false); + } + if (DEBUG) log(" mBottom=" + peeked); + mBottom = peeked; + final float f = (peeked - min) / (float)(max - min); + setExpanded(f); + requestLayout(); + } + + private void setExpanded(float f) { + if (DEBUG) log("setExpanded " + f); + final int a = (int)(Color.alpha(BACKGROUND) * f); + setBackgroundColor(Color.argb(a, + Color.red(BACKGROUND), Color.green(BACKGROUND), Color.blue(BACKGROUND))); + mHintText.setAlpha(1 - f); + mCloseButton.setAlpha(f); + mModeSpinner.setAlpha(f); + mUntilPager.setAlpha(f); + mSettingsButton.setAlpha(f * getSettingsButtonAlpha()); + } + + private static void log(String msg, Object... args) { + Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args)); + } + + private static ShapeDrawable sd(Path p, int size, Paint pt) { + final ShapeDrawable sd = new ShapeDrawable(new PathShape(p, size, size)); + sd.getPaint().set(pt); + sd.setIntrinsicHeight(size); + sd.setIntrinsicWidth(size); + return sd; + } + + public void dispatchExternalTouchEvent(MotionEvent ev) { + if (isApplicable()) { + onTouchEvent(ev); + } + } + + private static void bounce(final View v, final Runnable midBounce) { + v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3) + .setListener(new AnimatorListenerAdapter() { + private boolean mFired; + @Override + public void onAnimationEnd(Animator animation) { + if (!mFired) { + mFired = true; + if (midBounce != null) { + midBounce.run(); + } + v.animate().scaleX(1).scaleY(1).setListener(null).start(); + } + } + }).start(); + } + + private final class UntilPager extends RelativeLayout { + private final ImageView mPrev; + private final ImageView mNext; + private final TextView mText1; + private final TextView mText2; + + private TextView mText; + + public UntilPager(Context context, Paint pathPaint, int iconSize) { + super(context); + mText1 = new TextView(mContext); + mText1.setTypeface(CONDENSED); + mText1.setTextColor(GRAY); + mText1.setGravity(Gravity.CENTER); + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize); + addView(mText1, lp); + mText = mText1; + + mText2 = new TextView(mContext); + mText2.setTypeface(CONDENSED); + mText2.setTextColor(GRAY); + mText2.setAlpha(0); + mText2.setGravity(Gravity.CENTER); + addView(mText2, lp); + + lp = new LayoutParams(iconSize, iconSize); + final View v = new View(mContext); + v.setBackgroundColor(BACKGROUND); + addView(v, lp); + mPrev = new ImageView(mContext); + mPrev.setId(android.R.id.button1); + mPrev.setImageDrawable(sd(prevPath(iconSize), iconSize, pathPaint)); + addView(mPrev, lp); + mPrev.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onNav(v, -1); + } + }); + + lp = new LayoutParams(iconSize, iconSize); + lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + final View v2 = new View(mContext); + v2.setBackgroundColor(BACKGROUND); + addView(v2, lp); + mNext = new ImageView(mContext); + mNext.setId(android.R.id.button2); + mNext.setImageDrawable(sd(nextPath(iconSize), iconSize, pathPaint)); + addView(mNext, lp); + mNext.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onNav(v, 1); + } + }); + + updateState(); + } + + private void onNav(View v, int d) { + bounce(v, null); + if (mAdapter == null) { + return; + } + if (mAdapter.getExitConditionCount() == 1) { + horBounce(d); + return; + } + final int w = getWidth(); + final float s = Math.signum(d); + final TextView current = mText; + final TextView other = mText == mText1 ? mText2 : mText1; + final ExitCondition ec = mAdapter.getExitCondition(d); + setText(other, ec); + other.setTranslationX(-s * w); + other.animate().translationX(0).alpha(1).setDuration(DURATION).start(); + current.animate().translationX(s * w).alpha(0).setDuration(DURATION).start(); + mText = other; + mAdapter.select(ec); + } + + private void horBounce(int d) { + final int w = getWidth(); + mText.animate() + .setDuration(BOUNCE_DURATION) + .translationX(Math.signum(d) * w / 20) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mText.animate().translationX(0).setListener(null).start(); + } + }).start(); + } + + private void setText(final TextView textView, final ExitCondition ec) { + SpannableStringBuilder ss = new SpannableStringBuilder(ec.line1 + "\n" + ec.line2); + ss.setSpan(new RelativeSizeSpan(1.5f), (ec.line1 + "\n").length(), ss.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + if (ec.action != null) { + ss.setSpan(new CustomLinkSpan() { + @Override + public void onClick() { + // TODO wire up links + Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show(); + } + }, (ec.line1 + "\n").length(), ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + } else { + textView.setMovementMethod(null); + } + textView.setText(ss); + } + + private void updateState() { + if (mAdapter == null) { + return; + } + setText(mText, mAdapter.getExitCondition(0)); + } + + private Path prevPath(int size) { + final int hp = size / 3; + final int vp = size / 4; + final Path p = new Path(); + p.moveTo(size - hp, vp); + p.lineTo(hp, size / 2); + p.lineTo(size - hp, size - vp); + return p; + } + + private Path nextPath(int size) { + final int hp = size / 3; + final int vp = size / 4; + Path p = new Path(); + p.moveTo(hp, vp); + p.lineTo(size - hp, size / 2); + p.lineTo(hp, size - vp); + return p; + } + } + + private abstract static class CustomLinkSpan extends URLSpan { + abstract public void onClick(); + + public CustomLinkSpan() { + super("#"); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + ds.bgColor = BACKGROUND; + } + + @Override + public void onClick(View widget) { + onClick(); + } + } + + public interface Adapter { + public static final int MODE_OFF = 0; + public static final int MODE_LIMITED = 1; + public static final int MODE_FULL = 2; + + boolean isApplicable(); + int getMode(); + void setMode(int mode); + void select(ExitCondition ec); + void cancel(); + void setCallbacks(Callbacks callbacks); + ExitCondition getExitCondition(int d); + int getExitConditionCount(); + + public static class ExitCondition { + public String summary; + public String line1; + public String line2; + public String action; + } + + public interface Callbacks { + void onChanged(); + } + } + + private final class ModeSpinner extends Spinner { + public ModeSpinner(final Context context) { + super(context); + setBackgroundResource(R.drawable.spinner_default_holo_dark_am_no_underline); + final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(mContext, 0) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (DEBUG) log("getView %s parent=%s", position, parent); + return getDropDownView(position, convertView, parent); + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + if (DEBUG) log("getDropDownView %s cv=%s parent=%s", + position, convertView, parent); + final TextView tv = convertView != null ? (TextView) convertView + : new TextView(context); + final int mode = getItem(position); + tv.setText(modeToString(mode)); + if (convertView == null) { + if (DEBUG) log(" setting up view"); + tv.setTextColor(GRAY); + tv.setTypeface(CONDENSED); + tv.setAllCaps(true); + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f); + final int p = (int) tv.getTextSize() / 2; + if (parent instanceof ListView) { + tv.setPadding(p, p, p, p); + } else { + tv.setGravity(Gravity.CENTER_HORIZONTAL); + tv.setPadding(p, 0, p, 0); + } + } + tv.setOnTouchListener(new OnTouchListener(){ + @Override + public boolean onTouch(View v, MotionEvent event) { + if (DEBUG) log("onTouch %s %s", tv.getText(), + MotionEvent.actionToString(event.getAction())); + if (mAdapter != null) { + mAdapter.setMode(mode); + } + return false; + } + + }); + return tv; + } + }; + adapter.add(Adapter.MODE_LIMITED); + adapter.add(Adapter.MODE_FULL); + setAdapter(adapter); + } + + public void updateState() { + int mode = mAdapter != null ? mAdapter.getMode() : Adapter.MODE_LIMITED; + if (mode == Adapter.MODE_OFF) { + mode = Adapter.MODE_LIMITED; + } + if (DEBUG) log("setSelectedMode " + mode); + for (int i = 0; i < getAdapter().getCount(); i++) { + if (getAdapter().getItem(i).equals(mode)) { + if (DEBUG) log(" setting selection = " + i); + setSelection(i, true); + return; + } + } + } + + private String modeToString(int mode) { + if (mode == Adapter.MODE_LIMITED) return "Limited interruptions"; + if (mode == Adapter.MODE_FULL) return "Zero interruptions"; + throw new UnsupportedOperationException("Unsupported mode: " + mode); + } + } + + private final class AlarmWarning extends LinearLayout { + public AlarmWarning(Context context) { + super(context); + setOrientation(HORIZONTAL); + + final TextView tv = new TextView(mContext); + tv.setTextColor(GRAY); + tv.setGravity(Gravity.TOP); + tv.setTypeface(CONDENSED); + tv.setText(FULL_TEXT); + addView(tv); + + final ImageView icon = new ImageView(mContext); + icon.setAlpha(.75f); + int size = (int)tv.getTextSize(); + icon.setImageResource(android.R.drawable.ic_dialog_alert); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(size, size); + final int p = size / 4; + lp.bottomMargin = lp.topMargin = lp.rightMargin = lp.leftMargin = p; + addView(icon, 0, lp); + setPadding(p, 0, p, p); + } + + public void updateState(boolean animate) { + final boolean visible = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL; + final float alpha = visible ? 1 : 0; + if (alpha == getAlpha()) { + return; + } + if (animate) { + final boolean in = alpha == 1; + animate().alpha(alpha).setUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + if (mPeekable || mClosing) { + return; + } + float f = animation.getAnimatedFraction(); + if (!in) { + f = 1 - f; + } + ZenModeView.this.mBottom = mUntilPager.getBottom() + + (int)(mAlarmWarning.getMeasuredHeight() * f); + if (DEBUG) log("mBottom (AW) = " + mBottom); + requestLayout(); + } + }).start(); + } else { + setAlpha(alpha); + requestLayout(); + } + } + } + + private static class InfoWindow extends PopupWindow implements Runnable { + private final TextView mText; + + public InfoWindow(Context context, String text) { + mText = new TextView(context); + mText.setTypeface(CONDENSED); + mText.setBackgroundColor(0xbb000000); + mText.setTextColor(0xffffffff); + mText.setText(text); + mText.setGravity(Gravity.CENTER); + setAnimationStyle(android.R.style.Animation_Toast); + setContentView(mText); + } + + @Override + public void run() { + dismiss(); + } + + public void show(View over) { + setWidth(over.getMeasuredWidth()); + setHeight(over.getMeasuredHeight()); + final int[] loc = new int[2]; + over.getLocationInWindow(loc); + showAtLocation(over, Gravity.NO_GRAVITY, loc[0], loc[1]); + over.postDelayed(this, INFO_WINDOW_DELAY); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java new file mode 100644 index 000000000000..c9ac89f61c47 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.os.AsyncTask; +import android.os.Handler; +import android.provider.Settings; +import android.util.Log; + +import java.util.Arrays; +import java.util.List; + +public class ZenModeViewAdapter implements ZenModeView.Adapter { + private static final String TAG = "ZenModeViewAdapter"; + + private final Context mContext; + private final ContentResolver mResolver; + private final Handler mHandler = new Handler(); + private final SettingsObserver mObserver; + private final List<ExitCondition> mExits = Arrays.asList( + newExit("Until you delete this", "Until", "You delete this")); + + private Callbacks mCallbacks; + private int mExitIndex; + private boolean mDeviceProvisioned; + private int mMode; + + public ZenModeViewAdapter(Context context) { + mContext = context; + mResolver = mContext.getContentResolver(); + mObserver = new SettingsObserver(mHandler); + mObserver.init(); + } + + @Override + public boolean isApplicable() { + return mDeviceProvisioned; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public void setMode(int mode) { + final int v = mode == MODE_LIMITED ? Settings.Global.ZEN_MODE_LIMITED + : mode == MODE_FULL ? Settings.Global.ZEN_MODE_FULL + : Settings.Global.ZEN_MODE_OFF; + AsyncTask.execute(new Runnable() { + @Override + public void run() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ZEN_MODE, v); + } + }); + } + + @Override + public void cancel() { + if (mExitIndex != 0) { + mExitIndex = 0; + mHandler.post(mChange); + } + setMode(MODE_OFF); + } + + @Override + public void setCallbacks(final Callbacks callbacks) { + mHandler.post(new Runnable() { + @Override + public void run() { + mCallbacks = callbacks; + } + }); + } + + @Override + public ExitCondition getExitCondition(int d) { + final int n = mExits.size(); + final int i = (n + (mExitIndex + (int)Math.signum(d))) % n; + return mExits.get(i); + } + + @Override + public int getExitConditionCount() { + return mExits.size(); + } + + @Override + public void select(ExitCondition ec) { + final int i = mExits.indexOf(ec); + if (i == -1 || i == mExitIndex) { + return; + } + mExitIndex = i; + mHandler.post(mChange); + } + + private static ExitCondition newExit(String summary, String line1, String line2) { + final ExitCondition rt = new ExitCondition(); + rt.summary = summary; + rt.line1 = line1; + rt.line2 = line2; + return rt; + } + + private final Runnable mChange = new Runnable() { + public void run() { + if (mCallbacks == null) { + return; + } + try { + mCallbacks.onChanged(); + } catch (Throwable t) { + Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t); + } + } + }; + + private final class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + } + + public void init() { + loadSettings(); + mResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ZEN_MODE), + false, this); + mResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), + false, this); + } + + @Override + public void onChange(boolean selfChange) { + loadSettings(); + mChange.run(); // already on handler + } + + private void loadSettings() { + mDeviceProvisioned = Settings.Global.getInt(mResolver, + Settings.Global.DEVICE_PROVISIONED, 0) != 0; + mMode = getMode(); + } + + private int getMode() { + final int v = Settings.Global.getInt(mResolver, + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + if (v == Settings.Global.ZEN_MODE_LIMITED) return MODE_LIMITED; + if (v == Settings.Global.ZEN_MODE_FULL) return MODE_FULL; + return MODE_OFF; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index 491c35e5c6d3..f4bc4a46e204 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -28,6 +28,7 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.systemui.ExpandHelper; +import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.statusbar.BaseStatusBar; @@ -42,13 +43,13 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. private final int mTouchSensitivityDelay; private SwipeHelper mSwipeHelper; + private EdgeSwipeHelper mEdgeSwipeHelper; private BaseStatusBar mBar; private ExpandHelper mExpandHelper; - private long mStartTouchTime; + private long mStartTouchTime; private ViewGroup mContentHolder; - private ViewGroup mContentSlider; private NotificationData.Entry mHeadsUp; @@ -72,7 +73,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. public boolean setNotification(NotificationData.Entry headsUp) { mHeadsUp = headsUp; - mHeadsUp.row.setExpanded(false); + mHeadsUp.row.setExpanded(true); mHeadsUp.row.setShowingPublic(false); if (mContentHolder == null) { // too soon! @@ -83,7 +84,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. mContentHolder.setAlpha(1f); mContentHolder.removeAllViews(); mContentHolder.addView(mHeadsUp.row); - mSwipeHelper.snapChild(mContentSlider, 1f); + mSwipeHelper.snapChild(mContentHolder, 1f); mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay; return true; } @@ -94,10 +95,11 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. public void setMargin(int notificationPanelMarginPx) { if (SPEW) Log.v(TAG, "setMargin() " + notificationPanelMarginPx); - if (mContentSlider != null) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentSlider.getLayoutParams(); + if (mContentHolder != null && + mContentHolder.getLayoutParams() instanceof FrameLayout.LayoutParams) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentHolder.getLayoutParams(); lp.setMarginStart(notificationPanelMarginPx); - mContentSlider.setLayoutParams(lp); + mContentHolder.setLayoutParams(lp); } } @@ -122,15 +124,17 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. @Override public void onAttachedToWindow() { float densityScale = getResources().getDisplayMetrics().density; - float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); + final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext()); + float pagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop(); + float touchSlop = viewConfiguration.getScaledTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); + mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop); int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); mExpandHelper = new ExpandHelper(getContext(), this, minHeight, maxHeight); mContentHolder = (ViewGroup) findViewById(R.id.content_holder); - mContentSlider = (ViewGroup) findViewById(R.id.content_slider); if (mHeadsUp != null) { // whoops, we're on already! @@ -144,7 +148,8 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. if (System.currentTimeMillis() < mStartTouchTime) { return true; } - return mSwipeHelper.onInterceptTouchEvent(ev) + return mEdgeSwipeHelper.onInterceptTouchEvent(ev) + || mSwipeHelper.onInterceptTouchEvent(ev) || mExpandHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev); } @@ -157,7 +162,8 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. return false; } mBar.resetHeadsUpDecayTimer(); - return mSwipeHelper.onTouchEvent(ev) + return mEdgeSwipeHelper.onTouchEvent(ev) + || mSwipeHelper.onTouchEvent(ev) || mExpandHelper.onTouchEvent(ev) || super.onTouchEvent(ev); } @@ -226,11 +232,65 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. @Override public View getChildAtPosition(MotionEvent ev) { - return mContentSlider; + return mContentHolder; } @Override public View getChildContentView(View v) { - return mContentSlider; + return mContentHolder; + } + + private class EdgeSwipeHelper implements Gefingerpoken { + private static final boolean DEBUG_EDGE_SWIPE = false; + private final float mTouchSlop; + private boolean mConsuming; + private float mFirstY; + private float mFirstX; + + public EdgeSwipeHelper(float touchSlop) { + mTouchSlop = touchSlop; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action down " + ev.getY()); + mFirstX = ev.getX(); + mFirstY = ev.getY(); + mConsuming = false; + break; + + case MotionEvent.ACTION_MOVE: + if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action move " + ev.getY()); + final float dY = ev.getY() - mFirstY; + final float daX = Math.abs(ev.getX() - mFirstX); + final float daY = Math.abs(dY); + if (!mConsuming && (4f * daX) < daY && daY > mTouchSlop) { + if (dY > 0) { + if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found an open"); + mBar.animateExpandNotificationsPanel(); + } + if (dY < 0) { + if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found a close"); + mBar.onHeadsUpDismissed(); + } + mConsuming = true; + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done" ); + mConsuming = false; + break; + } + return mConsuming; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return mConsuming; + } } }
\ No newline at end of file diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index df2aaca49eca..243bd74c7617 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -16,6 +16,8 @@ package com.android.server.notification; +import android.os.IBinder; + public interface NotificationDelegate { void onSetDisabled(int status); void onClearAll(); @@ -24,4 +26,5 @@ public interface NotificationDelegate { void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message); void onPanelRevealed(); + boolean allowDisable(int what, IBinder token, String pkg); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ab46dfe0e63a..b791435d6b50 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -154,7 +154,7 @@ public class NotificationManagerService extends SystemService { private long[] mFallbackVibrationPattern; boolean mSystemReady; - int mDisabledNotifications; + private boolean mDisableNotificationAlerts; NotificationRecord mSoundNotification; NotificationRecord mVibrateNotification; @@ -202,6 +202,19 @@ public class NotificationManagerService extends SystemService { final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>(); + private int mZenMode; + private int mPreZenAlarmVolume = -1; + private int mPreZenRingerMode = -1; + // temporary, until we update apps to provide metadata + private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList( + "com.google.android.dialer", + "com.android.phone" + )); + private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList( + "com.google.android.deskclock" + )); + private static final String EXTRA_INTERCEPT = "android.intercept"; + private class NotificationListenerInfo implements IBinder.DeathRecipient { INotificationListener listener; ComponentName component; @@ -869,8 +882,8 @@ public class NotificationManagerService extends SystemService { @Override public void onSetDisabled(int status) { synchronized (mNotificationList) { - mDisabledNotifications = status; - if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { + mDisableNotificationAlerts = (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; + if (mDisableNotificationAlerts) { // cancel whatever's going on long identity = Binder.clearCallingIdentity(); try { @@ -968,6 +981,14 @@ public class NotificationManagerService extends SystemService { } Binder.restoreCallingIdentity(ident); } + + @Override + public boolean allowDisable(int what, IBinder token, String pkg) { + if (mZenMode == Settings.Global.ZEN_MODE_FULL && isCall(pkg, null)) { + return false; + } + return true; + } }; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @@ -1077,6 +1098,12 @@ public class NotificationManagerService extends SystemService { private final Uri ENABLED_NOTIFICATION_LISTENERS_URI = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + private final Uri ZEN_MODE + = Settings.Global.getUriFor(Settings.Global.ZEN_MODE); + + private final Uri MODE_RINGER + = Settings.Global.getUriFor(Settings.Global.MODE_RINGER); + SettingsObserver(Handler handler) { super(handler); } @@ -1087,6 +1114,10 @@ public class NotificationManagerService extends SystemService { false, this, UserHandle.USER_ALL); resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(ZEN_MODE, + false, this); + resolver.registerContentObserver(MODE_RINGER, + false, this); update(null); } @@ -1107,6 +1138,12 @@ public class NotificationManagerService extends SystemService { if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) { rebindListenerServices(); } + if (ZEN_MODE.equals(uri)) { + updateZenMode(); + } + if (MODE_RINGER.equals(uri)) { + updateRingerMode(); + } } } @@ -1170,8 +1207,10 @@ public class NotificationManagerService extends SystemService { // flag at least once and we'll go back to 0 after that. if (0 == Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) { - mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS; + mDisableNotificationAlerts = true; } + updateRingerMode(); + updateZenMode(); // register for various Intents IntentFilter filter = new IntentFilter(); @@ -1622,8 +1661,10 @@ public class NotificationManagerService extends SystemService { pw.println(" mSoundNotification=" + mSoundNotification); pw.println(" mVibrateNotification=" + mVibrateNotification); - pw.println(" mDisabledNotifications=0x" - + Integer.toHexString(mDisabledNotifications)); + pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts); + pw.println(" mZenMode=" + Settings.Global.zenModeToString(mZenMode)); + pw.println(" mPreZenAlarmVolume=" + mPreZenAlarmVolume); + pw.println(" mPreZenRingerMode=" + mPreZenRingerMode); pw.println(" mSystemReady=" + mSystemReady); pw.println(" mArchive=" + mArchive.toString()); Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); @@ -1767,9 +1808,13 @@ public class NotificationManagerService extends SystemService { return; } - // Should this notification make noise, vibe, or use the LED? - final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD); + // Is this notification intercepted by zen mode? + final boolean intercept = shouldIntercept(pkg, notification); + notification.extras.putBoolean(EXTRA_INTERCEPT, intercept); + // Should this notification make noise, vibe, or use the LED? + final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept; + if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept); synchronized (mNotificationList) { final StatusBarNotification n = new StatusBarNotification( pkg, id, tag, callingUid, callingPid, score, notification, user); @@ -1851,8 +1896,7 @@ public class NotificationManagerService extends SystemService { } // If we're not supposed to beep, vibrate, etc. then don't. - if (((mDisabledNotifications - & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) + if (!mDisableNotificationAlerts && (!(old != null && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) && (r.getUserId() == UserHandle.USER_ALL || @@ -1860,7 +1904,7 @@ public class NotificationManagerService extends SystemService { && canInterrupt && mSystemReady && mAudioManager != null) { - + if (DBG) Slog.v(TAG, "Interrupting!"); // sound // should we use the default notification sound? (indicated either by @@ -1905,6 +1949,8 @@ public class NotificationManagerService extends SystemService { final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); if (player != null) { + if (DBG) Slog.v(TAG, "Playing sound " + soundUri + + " on stream " + audioStreamType); player.playAsync(soundUri, user, looping, audioStreamType); } } catch (RemoteException e) { @@ -2437,4 +2483,67 @@ public class NotificationManagerService extends SystemService { updateLightsLocked(); } } + + private void updateRingerMode() { + final int ringerMode = Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.MODE_RINGER, -1); + final boolean nonSilentRingerMode = ringerMode == AudioManager.RINGER_MODE_NORMAL + || ringerMode == AudioManager.RINGER_MODE_VIBRATE; + if (mZenMode == Settings.Global.ZEN_MODE_FULL && nonSilentRingerMode) { + Settings.Global.putInt(getContext().getContentResolver(), + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + } + } + + private void updateZenMode() { + mZenMode = Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + if (DBG) Slog.d(TAG, "updateZenMode " + Settings.Global.zenModeToString(mZenMode)); + if (mAudioManager != null) { + if (mZenMode == Settings.Global.ZEN_MODE_FULL) { + // calls vibrate if ringer mode = vibrate, so set the ringer mode as well + mPreZenRingerMode = mAudioManager.getRingerMode(); + if (DBG) Slog.d(TAG, "Muting calls mPreZenRingerMode=" + mPreZenRingerMode); + mAudioManager.setStreamMute(AudioManager.STREAM_RING, true); + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); + // alarms don't simply respect mute, so set the volume as well + mPreZenAlarmVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM); + if (DBG) Slog.d(TAG, "Muting alarms mPreZenAlarmVolume=" + mPreZenAlarmVolume); + mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true); + mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0); + } else { + if (DBG) Slog.d(TAG, "Unmuting calls"); + mAudioManager.setStreamMute(AudioManager.STREAM_RING, false); + if (mPreZenRingerMode != -1) { + if (DBG) Slog.d(TAG, "Restoring ringer mode to " + mPreZenRingerMode); + mAudioManager.setRingerMode(mPreZenRingerMode); + mPreZenRingerMode = -1; + } + if (DBG) Slog.d(TAG, "Unmuting alarms"); + mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false); + if (mPreZenAlarmVolume != -1) { + if (DBG) Slog.d(TAG, "Restoring STREAM_ALARM to " + mPreZenAlarmVolume); + mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mPreZenAlarmVolume, 0); + mPreZenAlarmVolume = -1; + } + } + } + } + + private boolean isCall(String pkg, Notification n) { + return CALL_PACKAGES.contains(pkg); + } + + private boolean isAlarm(String pkg, Notification n) { + return ALARM_PACKAGES.contains(pkg); + } + + private boolean shouldIntercept(String pkg, Notification n) { + if (mZenMode == Settings.Global.ZEN_MODE_LIMITED) { + return !isCall(pkg, n) && !isAlarm(pkg, n); + } else if (mZenMode == Settings.Global.ZEN_MODE_FULL) { + return true; + } + return false; + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 07a74cd7e5f6..7f00ce7a687e 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3774,6 +3774,7 @@ public class PackageManagerService extends IPackageManager.Stub { updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg); } + boolean updatedPkgBetter = false; // First check if this is a system package that may involve an update if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { if (ps != null && !ps.codePath.equals(scanFile)) { @@ -3828,6 +3829,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { mSettings.enableSystemPackageLPw(ps.name); } + updatedPkgBetter = true; } } } @@ -3904,7 +3906,7 @@ public class PackageManagerService extends IPackageManager.Stub { String codePath = null; String resPath = null; - if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) { + if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) { if (ps != null && ps.resourcePathString != null) { resPath = ps.resourcePathString; } else { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 4395502438db..e7bbf1c07b18 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -1591,12 +1591,9 @@ public final class PowerManagerService extends com.android.server.SystemService | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) { final int newScreenState = getDesiredScreenPowerStateLocked(); - if (newScreenState != mDisplayPowerRequest.screenState) { - mDisplayPowerRequest.screenState = newScreenState; - nativeSetPowerState( - mDisplayPowerRequest.wantScreenOnNormal(), - newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT); - } + mDisplayPowerRequest.screenState = newScreenState; + nativeSetPowerState(isScreenOnLocked(), + newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT); int screenBrightness = mScreenBrightnessSettingDefault; float screenAutoBrightnessAdjustment = 0.0f; @@ -1806,11 +1803,15 @@ public final class PowerManagerService extends com.android.server.SystemService private boolean isScreenOnInternal() { synchronized (mLock) { - return !mSystemReady - || mDisplayPowerRequest.wantScreenOnNormal(); + return isScreenOnLocked(); } } + private boolean isScreenOnLocked() { + return mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING; + } + private void handleBatteryStateChangedLocked() { mDirty |= DIRTY_BATTERY_STATE; updatePowerStateLocked(); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 2ae467eabdd1..8219eb53e988 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -23,9 +23,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.StatusBarNotification; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.util.Slog; @@ -207,6 +205,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub @Override public void disable(int what, IBinder token, String pkg) { + if (!mNotificationDelegate.allowDisable(what, token, pkg)) { + if (SPEW) Slog.d(TAG, "Blocking disable request from " + pkg); + return; + } disableInternal(mCurrentUserId, what, token, pkg); } @@ -676,26 +678,4 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } } - - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) - || Intent.ACTION_SCREEN_OFF.equals(action)) { - collapsePanels(); - } - /* - else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { - updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false), - intent.getStringExtra(Telephony.Intents.EXTRA_SPN), - intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false), - intent.getStringExtra(Telephony.Intents.EXTRA_PLMN)); - } - else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - updateResources(); - } - */ - } - }; - } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 7675ba6f62a8..56144b090fe3 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -30,7 +30,6 @@ LOCAL_C_INCLUDES += \ frameworks/base/libs \ frameworks/base/core/jni \ frameworks/native/services \ - external/skia/include/core \ libcore/include \ libcore/include/libsuspend \ $(call include-path-for, libhardware)/hardware \ diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp index fc6de60dbf5e..bc866d3ee13b 100644 --- a/services/core/jni/com_android_server_UsbHostManager.cpp +++ b/services/core/jni/com_android_server_UsbHostManager.cpp @@ -41,7 +41,11 @@ static struct parcel_file_descriptor_offsets_t jmethodID mConstructor; } gParcelFileDescriptorOffsets; -static jmethodID method_usbDeviceAdded; +static jmethodID method_beginUsbDeviceAdded; +static jmethodID method_addUsbConfiguration; +static jmethodID method_addUsbInterface; +static jmethodID method_addUsbEndpoint; +static jmethodID method_endUsbDeviceAdded; static jmethodID method_usbDeviceRemoved; static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { @@ -68,64 +72,69 @@ static int usb_device_added(const char *devname, void* client_data) { Vector<int> endpointValues; const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device); - uint16_t vendorId = usb_device_get_vendor_id(device); - uint16_t productId = usb_device_get_product_id(device); - uint8_t deviceClass = deviceDesc->bDeviceClass; - uint8_t deviceSubClass = deviceDesc->bDeviceSubClass; - uint8_t protocol = deviceDesc->bDeviceProtocol; char *manufacturer = usb_device_get_manufacturer_name(device); char *product = usb_device_get_product_name(device); char *serial = usb_device_get_serial(device); + jstring deviceName = env->NewStringUTF(devname); + jstring manufacturerName = env->NewStringUTF(manufacturer); + jstring productName = env->NewStringUTF(product); + jstring serialNumber = env->NewStringUTF(serial); + + jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded, + deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device), + deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol, + manufacturerName, productName, serialNumber); + + env->DeleteLocalRef(serialNumber); + env->DeleteLocalRef(productName); + env->DeleteLocalRef(manufacturerName); + env->DeleteLocalRef(deviceName); + free(manufacturer); + free(product); + free(serial); + + if (!result) goto fail; + usb_descriptor_iter_init(device, &iter); while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { - if (desc->bDescriptorType == USB_DT_INTERFACE) { + if (desc->bDescriptorType == USB_DT_CONFIG) { + struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc; + char *name = usb_device_get_string(device, config->iConfiguration); + jstring configName = env->NewStringUTF(name); + + env->CallVoidMethod(thiz, method_addUsbConfiguration, + config->bConfigurationValue, configName, config->bmAttributes, + config->bMaxPower); + + env->DeleteLocalRef(configName); + free(name); + } else if (desc->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; + char *name = usb_device_get_string(device, interface->iInterface); + jstring interfaceName = env->NewStringUTF(name); + + env->CallVoidMethod(thiz, method_addUsbInterface, + interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting, + interface->bInterfaceClass, interface->bInterfaceSubClass, + interface->bInterfaceProtocol); - // push class, subclass, protocol and number of endpoints into interfaceValues vector - interfaceValues.add(interface->bInterfaceNumber); - interfaceValues.add(interface->bInterfaceClass); - interfaceValues.add(interface->bInterfaceSubClass); - interfaceValues.add(interface->bInterfaceProtocol); - interfaceValues.add(interface->bNumEndpoints); + env->DeleteLocalRef(interfaceName); + free(name); } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc; - // push address, attributes, max packet size and interval into endpointValues vector - endpointValues.add(endpoint->bEndpointAddress); - endpointValues.add(endpoint->bmAttributes); - endpointValues.add(__le16_to_cpu(endpoint->wMaxPacketSize)); - endpointValues.add(endpoint->bInterval); + env->CallVoidMethod(thiz, method_addUsbEndpoint, + endpoint->bEndpointAddress, endpoint->bmAttributes, + __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval); } } - usb_device_close(device); - - // handle generic device notification - int length = interfaceValues.size(); - jintArray interfaceArray = env->NewIntArray(length); - env->SetIntArrayRegion(interfaceArray, 0, length, interfaceValues.array()); - - length = endpointValues.size(); - jintArray endpointArray = env->NewIntArray(length); - env->SetIntArrayRegion(endpointArray, 0, length, endpointValues.array()); - - jstring deviceName = env->NewStringUTF(devname); - jstring manufacturerName = env->NewStringUTF(manufacturer); - jstring productName = env->NewStringUTF(product); - jstring serialNumber = env->NewStringUTF(serial); - env->CallVoidMethod(thiz, method_usbDeviceAdded, - deviceName, vendorId, productId, deviceClass, - deviceSubClass, protocol, manufacturerName, - productName, serialNumber, interfaceArray, endpointArray); + env->CallVoidMethod(thiz, method_endUsbDeviceAdded); - env->DeleteLocalRef(interfaceArray); - env->DeleteLocalRef(endpointArray); - env->DeleteLocalRef(serialNumber); - env->DeleteLocalRef(productName); - env->DeleteLocalRef(manufacturerName); - env->DeleteLocalRef(deviceName); +fail: + usb_device_close(device); checkAndClearExceptionFromCallback(env, __FUNCTION__); return 0; @@ -191,12 +200,36 @@ int register_android_server_UsbHostManager(JNIEnv *env) ALOGE("Can't find com/android/server/usb/UsbHostManager"); return -1; } - method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I)V"); - if (method_usbDeviceAdded == NULL) { - ALOGE("Can't find usbDeviceAdded"); + method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded", + "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); + if (method_beginUsbDeviceAdded == NULL) { + ALOGE("Can't find beginUsbDeviceAdded"); + return -1; + } + method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration", + "(ILjava/lang/String;II)V"); + if (method_addUsbConfiguration == NULL) { + ALOGE("Can't find addUsbConfiguration"); + return -1; + } + method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface", + "(ILjava/lang/String;IIII)V"); + if (method_addUsbInterface == NULL) { + ALOGE("Can't find addUsbInterface"); + return -1; + } + method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V"); + if (method_addUsbEndpoint == NULL) { + ALOGE("Can't find addUsbEndpoint"); + return -1; + } + method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V"); + if (method_endUsbDeviceAdded == NULL) { + ALOGE("Can't find endUsbDeviceAdded"); return -1; } - method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", "(Ljava/lang/String;)V"); + method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", + "(Ljava/lang/String;)V"); if (method_usbDeviceRemoved == NULL) { ALOGE("Can't find usbDeviceRemoved"); return -1; @@ -205,7 +238,8 @@ int register_android_server_UsbHostManager(JNIEnv *env) clazz = env->FindClass("android/os/ParcelFileDescriptor"); LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); - gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); + gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", + "(Ljava/io/FileDescriptor;)V"); LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, "Unable to find constructor for android.os.ParcelFileDescriptor"); diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index dfaad0bcece9..7ae54606cb00 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -17,6 +17,7 @@ package com.android.server.usb; import android.content.Context; +import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbEndpoint; @@ -30,6 +31,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashMap; /** @@ -48,6 +50,13 @@ public class UsbHostManager { private final Context mContext; private final Object mLock = new Object(); + private UsbDevice mNewDevice; + private UsbConfiguration mNewConfiguration; + private UsbInterface mNewInterface; + private ArrayList<UsbConfiguration> mNewConfigurations; + private ArrayList<UsbInterface> mNewInterfaces; + private ArrayList<UsbEndpoint> mNewEndpoints; + @GuardedBy("mLock") private UsbSettingsManager mCurrentSettings; @@ -93,69 +102,103 @@ public class UsbHostManager { return false; } - /* Called from JNI in monitorUsbHostBus() to report new USB devices */ - private void usbDeviceAdded(String deviceName, int vendorID, int productID, + /* Called from JNI in monitorUsbHostBus() to report new USB devices + Returns true if successful, in which case the JNI code will continue adding configurations, + interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors + have been processed + */ + private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID, int deviceClass, int deviceSubclass, int deviceProtocol, - String manufacturerName, String productName, String serialNumber, - /* array of quintuples containing id, class, subclass, protocol - and number of endpoints for each interface */ - int[] interfaceValues, - /* array of quadruples containing address, attributes, max packet size - and interval for each endpoint */ - int[] endpointValues) { + String manufacturerName, String productName, String serialNumber) { if (isBlackListed(deviceName) || isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) { - return; + return false; } synchronized (mLock) { if (mDevices.get(deviceName) != null) { Slog.w(TAG, "device already on mDevices list: " + deviceName); - return; + return false; } - int numInterfaces = interfaceValues.length / 5; - Parcelable[] interfaces = new UsbInterface[numInterfaces]; - try { - // repackage interfaceValues as an array of UsbInterface - int intf, endp, ival = 0, eval = 0; - for (intf = 0; intf < numInterfaces; intf++) { - int interfaceId = interfaceValues[ival++]; - int interfaceClass = interfaceValues[ival++]; - int interfaceSubclass = interfaceValues[ival++]; - int interfaceProtocol = interfaceValues[ival++]; - int numEndpoints = interfaceValues[ival++]; - - Parcelable[] endpoints = new UsbEndpoint[numEndpoints]; - for (endp = 0; endp < numEndpoints; endp++) { - int address = endpointValues[eval++]; - int attributes = endpointValues[eval++]; - int maxPacketSize = endpointValues[eval++]; - int interval = endpointValues[eval++]; - endpoints[endp] = new UsbEndpoint(address, attributes, - maxPacketSize, interval); - } - - // don't allow if any interfaces are blacklisted - if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) { - return; - } - interfaces[intf] = new UsbInterface(interfaceId, interfaceClass, - interfaceSubclass, interfaceProtocol, endpoints); - } - } catch (Exception e) { - // beware of index out of bound exceptions, which might happen if - // a device does not set bNumEndpoints correctly - Slog.e(TAG, "error parsing USB descriptors", e); - return; + if (mNewDevice != null) { + Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded"); + return false; } - UsbDevice device = new UsbDevice(deviceName, vendorID, productID, + mNewDevice = new UsbDevice(deviceName, vendorID, productID, deviceClass, deviceSubclass, deviceProtocol, - manufacturerName, productName, serialNumber, interfaces); - mDevices.put(deviceName, device); - getCurrentSettings().deviceAttached(device); + manufacturerName, productName, serialNumber); + + mNewConfigurations = new ArrayList<UsbConfiguration>(); + mNewInterfaces = new ArrayList<UsbInterface>(); + mNewEndpoints = new ArrayList<UsbEndpoint>(); + } + return true; + } + + /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device + currently being added. Returns true if successful, false in case of error. + */ + private void addUsbConfiguration(int id, String name, int attributes, int maxPower) { + if (mNewConfiguration != null) { + mNewConfiguration.setInterfaces( + mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()])); + mNewInterfaces.clear(); + } + + mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower); + mNewConfigurations.add(mNewConfiguration); + } + + /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device + currently being added. Returns true if successful, false in case of error. + */ + private void addUsbInterface(int id, String name, int altSetting, + int Class, int subClass, int protocol) { + if (mNewInterface != null) { + mNewInterface.setEndpoints( + mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()])); + mNewEndpoints.clear(); + } + + mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol); + mNewInterfaces.add(mNewInterface); + } + + /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device + currently being added. Returns true if successful, false in case of error. + */ + private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) { + mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval)); + } + + /* Called from JNI in monitorUsbHostBus() to finish adding a new device */ + private void endUsbDeviceAdded() { + if (mNewInterface != null) { + mNewInterface.setEndpoints( + mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()])); + } + if (mNewConfiguration != null) { + mNewConfiguration.setInterfaces( + mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()])); + } + + synchronized (mLock) { + if (mNewDevice != null) { + mNewDevice.setConfigurations( + mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()])); + mDevices.put(mNewDevice.getDeviceName(), mNewDevice); + Slog.d(TAG, "Added device " + mNewDevice); + getCurrentSettings().deviceAttached(mNewDevice); + } else { + Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded"); + } + mNewDevice = null; + mNewConfigurations = null; + mNewInterfaces = null; + mNewEndpoints = null; } } diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath index 2e4274da5afd..aef3efa0452e 100644 --- a/tools/layoutlib/bridge/.classpath +++ b/tools/layoutlib/bridge/.classpath @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry excluding="org/kxml2/io/" kind="src" path="src"/> + <classpathentry kind="src" path="tests/src"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar"/> + <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar" sourcepath="/ANDROID_SRC/tools/base/layoutlib-api/src/main"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java index fd594f79c237..5f0d98b35431 100644 --- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java +++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java @@ -33,11 +33,6 @@ public class SystemClock_Delegate { private static long sBootTime = System.currentTimeMillis(); private static long sBootTimeNano = System.nanoTime(); - @LayoutlibDelegate - /*package*/ static boolean setCurrentTimeMillis(long millis) { - return true; - } - /** * Returns milliseconds since boot, not counting time spent in deep sleep. * <b>Note:</b> This value may get reset occasionally (before it would |