diff options
101 files changed, 2554 insertions, 1631 deletions
diff --git a/api/current.txt b/api/current.txt index eb079dbddd5f..9c142d44d432 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4849,6 +4849,7 @@ package android.app { method public void clearWindowAnimationFrameStats(); method public boolean clearWindowContentFrameStats(int); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; + method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo(); @@ -25827,6 +25828,7 @@ package android.system { method public static boolean isatty(java.io.FileDescriptor); method public static void kill(int, int) throws android.system.ErrnoException; method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException; + method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException; method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException; method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException; method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException; @@ -34923,9 +34925,11 @@ package android.widget { ctor public EdgeEffect(android.content.Context); method public boolean draw(android.graphics.Canvas); method public void finish(); + method public int getMaxHeight(); method public boolean isFinished(); method public void onAbsorb(int); method public void onPull(float); + method public void onPull(float, float); method public void onRelease(); method public void setSize(int, int); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 66b82ebd28da..b4b3c999533a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3618,13 +3618,15 @@ public class Activity extends ContextThemeWrapper } // Get the primary color and update the RecentsActivityValues for this activity - TypedArray a = getTheme().obtainStyledAttributes(com.android.internal.R.styleable.Theme); - int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0); - a.recycle(); - if (colorPrimary != 0) { - ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues(); - v.colorPrimary = colorPrimary; - setRecentsActivityValues(v); + if (theme != null) { + TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme); + int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0); + a.recycle(); + if (colorPrimary != 0) { + ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues(); + v.colorPrimary = colorPrimary; + setRecentsActivityValues(v); + } } } diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 347de973ad8a..8ab9ac3aff06 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -43,4 +43,5 @@ interface IUiAutomationConnection { WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); WindowAnimationFrameStats getWindowAnimationFrameStats(); + void executeShellCommand(String command, in ParcelFileDescriptor fd); } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index aab6ed83b11f..db91742a3b5f 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -44,8 +44,8 @@ public class KeyguardManager { * you to disable / reenable the keyguard. */ public class KeyguardLock { - private IBinder mToken = new Binder(); - private String mTag; + private final IBinder mToken = new Binder(); + private final String mTag; KeyguardLock(String tag) { mTag = tag; diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 94053255175e..64e348400c22 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -26,6 +26,7 @@ import android.graphics.Canvas; import android.graphics.Point; import android.hardware.display.DisplayManagerGlobal; import android.os.Looper; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; @@ -40,7 +41,9 @@ import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; +import libcore.io.IoUtils; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeoutException; @@ -840,6 +843,44 @@ public final class UiAutomation { return null; } + /** + * Executes a shell command. This method returs a file descriptor that points + * to the standard output stream. The command execution is similar to running + * "adb shell <command>" from a host connected to the device. + * <p> + * <strong>Note:</strong> It is your responsibility to close the retunred file + * descriptor once you are done reading. + * </p> + * + * @param command The command to execute. + * @return A file descriptor to the standard output stream. + */ + public ParcelFileDescriptor executeShellCommand(String command) { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + + ParcelFileDescriptor source = null; + ParcelFileDescriptor sink = null; + + try { + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + source = pipe[0]; + sink = pipe[1]; + + // Calling out without a lock held. + mUiAutomationConnection.executeShellCommand(command, sink); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error executing shell command!", ioe); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error executing shell command!", re); + } finally { + IoUtils.closeQuietly(sink); + } + + return source; + } + private static float getDegreesForRotation(int value) { switch (value) { case Surface.ROTATION_90: { diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index fa402863f1b8..81bcb3913aa2 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -23,6 +23,7 @@ import android.graphics.Bitmap; import android.hardware.input.InputManager; import android.os.Binder; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -33,6 +34,12 @@ import android.view.WindowAnimationFrameStats; import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; +import libcore.io.IoUtils; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; /** * This is a remote object that is passed from the shell to an instrumentation @@ -50,8 +57,8 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Service.WINDOW_SERVICE)); - private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface( - ServiceManager.getService(Service.ACCESSIBILITY_SERVICE)); + private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub + .asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE)); private final Object mLock = new Object(); @@ -220,6 +227,41 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } @Override + public void executeShellCommand(String command, ParcelFileDescriptor sink) + throws RemoteException { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + + InputStream in = null; + OutputStream out = null; + + try { + java.lang.Process process = Runtime.getRuntime().exec(command); + + in = process.getInputStream(); + out = new FileOutputStream(sink.getFileDescriptor()); + + final byte[] buffer = new byte[8192]; + while (true) { + final int readByteCount = in.read(buffer); + if (readByteCount < 0) { + break; + } + out.write(buffer, 0, readByteCount); + } + } catch (IOException ioe) { + throw new RuntimeException("Error running shell command", ioe); + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(sink); + } + } + + @Override public void shutdown() { synchronized (mLock) { if (isConnectedLocked()) { diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index cec90cd9262c..e58c54d33c10 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -156,6 +156,9 @@ public abstract class DisplayManagerInternal { // If true, enables automatic brightness control. public boolean useAutoBrightness; + //If true, scales the brightness to half of desired. + public boolean lowPowerMode; + // If true, prevents the screen from completely turning on if it is currently off. // The display does not enter a "ready" state if this flag is true and screen on is // blocked. The window manager policy blocks screen on while it prepares the keyguard to @@ -203,6 +206,7 @@ public abstract class DisplayManagerInternal { screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment; useAutoBrightness = other.useAutoBrightness; blockScreenOn = other.blockScreenOn; + lowPowerMode = other.lowPowerMode; } @Override @@ -218,7 +222,8 @@ public abstract class DisplayManagerInternal { && screenBrightness == other.screenBrightness && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment && useAutoBrightness == other.useAutoBrightness - && blockScreenOn == other.blockScreenOn; + && blockScreenOn == other.blockScreenOn + && lowPowerMode == other.lowPowerMode; } @Override @@ -233,7 +238,8 @@ public abstract class DisplayManagerInternal { + ", screenBrightness=" + screenBrightness + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment + ", useAutoBrightness=" + useAutoBrightness - + ", blockScreenOn=" + blockScreenOn; + + ", blockScreenOn=" + blockScreenOn + + ", lowPowerMode=" + lowPowerMode; } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 8b7467fa1619..4857533a1337 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Formatter; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,6 +31,8 @@ import android.telephony.SignalStrength; import android.text.format.DateFormat; import android.util.Printer; import android.util.SparseArray; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.TimeUtils; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -537,6 +540,7 @@ public abstract class BatteryStats implements Parcelable { public static final byte CMD_START = 4; public static final byte CMD_CURRENT_TIME = 5; public static final byte CMD_OVERFLOW = 6; + public static final byte CMD_RESET = 7; public byte cmd = CMD_NULL; @@ -620,6 +624,8 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_SYNC = 0x0004; // Number of event types. public static final int EVENT_COUNT = 0x0005; + // Mask to extract out only the type part of the event. + public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START; public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH; @@ -684,7 +690,7 @@ public abstract class BatteryStats implements Parcelable { dest.writeInt(eventCode); eventTag.writeToParcel(dest, flags); } - if (cmd == CMD_CURRENT_TIME) { + if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) { dest.writeLong(currentTime); } } @@ -722,7 +728,7 @@ public abstract class BatteryStats implements Parcelable { eventCode = EVENT_NONE; eventTag = null; } - if (cmd == CMD_CURRENT_TIME) { + if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) { currentTime = src.readLong(); } else { currentTime = 0; @@ -833,7 +839,59 @@ public abstract class BatteryStats implements Parcelable { return true; } } - + + public final static class HistoryEventTracker { + private final HashMap<String, SparseIntArray>[] mActiveEvents + = (HashMap<String, SparseIntArray>[]) new HashMap[HistoryItem.EVENT_COUNT]; + + public boolean updateState(int code, String name, int uid, int poolIdx) { + if ((code&HistoryItem.EVENT_FLAG_START) != 0) { + int idx = code&HistoryItem.EVENT_TYPE_MASK; + HashMap<String, SparseIntArray> active = mActiveEvents[idx]; + if (active == null) { + active = new HashMap<String, SparseIntArray>(); + mActiveEvents[idx] = active; + } + SparseIntArray uids = active.get(name); + if (uids == null) { + uids = new SparseIntArray(); + active.put(name, uids); + } + if (uids.indexOfKey(uid) >= 0) { + // Already set, nothing to do! + return false; + } + uids.put(uid, poolIdx); + } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) { + int idx = code&HistoryItem.EVENT_TYPE_MASK; + HashMap<String, SparseIntArray> active = mActiveEvents[idx]; + if (active == null) { + // not currently active, nothing to do. + return false; + } + SparseIntArray uids = active.get(name); + if (uids == null) { + // not currently active, nothing to do. + return false; + } + idx = uids.indexOfKey(uid); + if (idx < 0) { + // not currently active, nothing to do. + return false; + } + uids.removeAt(idx); + if (uids.size() <= 0) { + active.remove(name); + } + } + return true; + } + + public HashMap<String, SparseIntArray> getStateForEvent(int code) { + return mActiveEvents[code]; + } + } + public static final class BitDescription { public final int mask; public final int shift; @@ -861,7 +919,7 @@ public abstract class BatteryStats implements Parcelable { this.shortValues = shortValues; } } - + public abstract int getHistoryTotalSize(); public abstract int getHistoryUsedSize(); @@ -2958,10 +3016,14 @@ public abstract class BatteryStats implements Parcelable { pw.print(":"); } pw.println("START"); - } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { + } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME + || rec.cmd == HistoryItem.CMD_RESET) { if (checkin) { pw.print(":"); } + if (rec.cmd == HistoryItem.CMD_RESET) { + pw.print("RESET:"); + } pw.print("TIME:"); if (checkin) { pw.println(rec.currentTime); @@ -3187,6 +3249,86 @@ public abstract class BatteryStats implements Parcelable { public static final int DUMP_INCLUDE_HISTORY = 1<<3; public static final int DUMP_VERBOSE = 1<<4; + private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) { + final HistoryPrinter hprinter = new HistoryPrinter(); + final HistoryItem rec = new HistoryItem(); + long lastTime = -1; + long baseTime = -1; + boolean printed = false; + HistoryEventTracker tracker = null; + while (getNextHistoryLocked(rec)) { + lastTime = rec.time; + if (baseTime < 0) { + baseTime = lastTime; + } + if (rec.time >= histStart) { + if (histStart >= 0 && !printed) { + if (rec.cmd == HistoryItem.CMD_CURRENT_TIME + || rec.cmd == HistoryItem.CMD_RESET) { + printed = true; + } else if (rec.currentTime != 0) { + printed = true; + byte cmd = rec.cmd; + rec.cmd = HistoryItem.CMD_CURRENT_TIME; + if (checkin) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); + } + hprinter.printNextItem(pw, rec, baseTime, checkin, + (flags&DUMP_VERBOSE) != 0); + rec.cmd = cmd; + } + if (tracker != null) { + int oldCode = rec.eventCode; + HistoryTag oldTag = rec.eventTag; + rec.eventTag = new HistoryTag(); + for (int i=0; i<HistoryItem.EVENT_COUNT; i++) { + HashMap<String, SparseIntArray> active + = tracker.getStateForEvent(i); + if (active == null) { + continue; + } + for (HashMap.Entry<String, SparseIntArray> ent + : active.entrySet()) { + SparseIntArray uids = ent.getValue(); + for (int j=0; j<uids.size(); j++) { + rec.eventCode = i; + rec.eventTag.string = ent.getKey(); + rec.eventTag.uid = uids.keyAt(j); + rec.eventTag.poolIdx = uids.valueAt(j); + if (checkin) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); + } + hprinter.printNextItem(pw, rec, baseTime, checkin, + (flags&DUMP_VERBOSE) != 0); + } + } + } + rec.eventCode = oldCode; + rec.eventTag = oldTag; + tracker = null; + } + } + if (checkin) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); + } + hprinter.printNextItem(pw, rec, baseTime, checkin, + (flags&DUMP_VERBOSE) != 0); + } else if (rec.eventCode != HistoryItem.EVENT_NONE) { + if (tracker == null) { + tracker = new HistoryEventTracker(); + } + tracker.updateState(rec.eventCode, rec.eventTag.string, + rec.eventTag.uid, rec.eventTag.poolIdx); + } + } + if (histStart >= 0) { + pw.print(checkin ? "NEXT: " : " NEXT: "); pw.println(lastTime+1); + } + } + /** * Dumps a human-readable summary of the battery statistics to the given PrintWriter. * @@ -3200,9 +3342,6 @@ public abstract class BatteryStats implements Parcelable { (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0; if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) { - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); - - final HistoryItem rec = new HistoryItem(); final long historyTotalSize = getHistoryTotalSize(); final long historyUsedSize = getHistoryUsedSize(); if (startIteratingHistoryLocked()) { @@ -3218,35 +3357,7 @@ public abstract class BatteryStats implements Parcelable { pw.print(" strings using "); printSizeValue(pw, getHistoryStringPoolBytes()); pw.println("):"); - HistoryPrinter hprinter = new HistoryPrinter(); - long lastTime = -1; - long baseTime = -1; - boolean printed = false; - while (getNextHistoryLocked(rec)) { - lastTime = rec.time; - if (baseTime < 0) { - baseTime = lastTime; - } - if (rec.time >= histStart) { - if (histStart >= 0 && !printed) { - if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { - printed = true; - } else if (rec.currentTime != 0) { - printed = true; - byte cmd = rec.cmd; - rec.cmd = HistoryItem.CMD_CURRENT_TIME; - hprinter.printNextItem(pw, rec, baseTime, false, - (flags&DUMP_VERBOSE) != 0); - rec.cmd = cmd; - } - } - hprinter.printNextItem(pw, rec, baseTime, false, - (flags&DUMP_VERBOSE) != 0); - } - } - if (histStart >= 0) { - pw.print(" NEXT: "); pw.println(lastTime+1); - } + dumpHistoryLocked(pw, flags, histStart, false); pw.println(); } finally { finishIteratingHistoryLocked(); @@ -3255,6 +3366,7 @@ public abstract class BatteryStats implements Parcelable { if (startIteratingOldHistoryLocked()) { try { + final HistoryItem rec = new HistoryItem(); pw.println("Old battery History:"); HistoryPrinter hprinter = new HistoryPrinter(); long baseTime = -1; @@ -3348,7 +3460,6 @@ public abstract class BatteryStats implements Parcelable { (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0; if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) { - final HistoryItem rec = new HistoryItem(); if (startIteratingHistoryLocked()) { try { for (int i=0; i<getHistoryStringPoolSize(); i++) { @@ -3365,37 +3476,7 @@ public abstract class BatteryStats implements Parcelable { pw.print("\""); pw.println(); } - HistoryPrinter hprinter = new HistoryPrinter(); - long lastTime = -1; - long baseTime = -1; - boolean printed = false; - while (getNextHistoryLocked(rec)) { - lastTime = rec.time; - if (baseTime < 0) { - baseTime = lastTime; - } - if (rec.time >= histStart) { - if (histStart >= 0 && !printed) { - if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { - printed = true; - } else if (rec.currentTime != 0) { - printed = true; - byte cmd = rec.cmd; - rec.cmd = HistoryItem.CMD_CURRENT_TIME; - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(HISTORY_DATA); pw.print(','); - hprinter.printNextItem(pw, rec, baseTime, true, false); - rec.cmd = cmd; - } - } - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(HISTORY_DATA); pw.print(','); - hprinter.printNextItem(pw, rec, baseTime, true, false); - } - } - if (histStart >= 0) { - pw.print("NEXT: "); pw.println(lastTime+1); - } + dumpHistoryLocked(pw, flags, histStart, true); } finally { finishIteratingHistoryLocked(); } diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index a675821ba836..be3b6ce97271 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -21,6 +21,8 @@ import android.graphics.CanvasProperty; import android.graphics.Paint; import android.util.SparseIntArray; +import com.android.internal.util.VirtualRefBasePtr; + import java.lang.ref.WeakReference; /** @@ -70,28 +72,32 @@ public final class RenderNodeAnimator { public static final int DELTA_TYPE_DELTA = 1; private RenderNode mTarget; - private long mNativePtr; + private VirtualRefBasePtr mNativePtr; public int mapViewPropertyToRenderProperty(int viewProperty) { return sViewPropertyAnimatorMap.get(viewProperty); } public RenderNodeAnimator(int property, int deltaType, float deltaValue) { - mNativePtr = nCreateAnimator(new WeakReference<RenderNodeAnimator>(this), - property, deltaType, deltaValue); + init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this), + property, deltaType, deltaValue)); } public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) { - mNativePtr = nCreateCanvasPropertyFloatAnimator( + init(nCreateCanvasPropertyFloatAnimator( new WeakReference<RenderNodeAnimator>(this), - property.getNativeContainer(), deltaType, deltaValue); + property.getNativeContainer(), deltaType, deltaValue)); } public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, int deltaType, float deltaValue) { - mNativePtr = nCreateCanvasPropertyPaintAnimator( + init(nCreateCanvasPropertyPaintAnimator( new WeakReference<RenderNodeAnimator>(this), - property.getNativeContainer(), paintField, deltaType, deltaValue); + property.getNativeContainer(), paintField, deltaType, deltaValue)); + } + + private void init(long ptr) { + mNativePtr = new VirtualRefBasePtr(ptr); } public void start(View target) { @@ -115,11 +121,11 @@ public final class RenderNodeAnimator { } public void setDuration(int duration) { - nSetDuration(mNativePtr, duration); + nSetDuration(mNativePtr.get(), duration); } long getNativeAnimator() { - return mNativePtr; + return mNativePtr.get(); } private void onFinished() { @@ -134,16 +140,6 @@ public final class RenderNodeAnimator { } } - @Override - protected void finalize() throws Throwable { - try { - nUnref(mNativePtr); - mNativePtr = 0; - } finally { - super.finalize(); - } - } - private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis, int property, int deltaValueType, float deltaValue); private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis, @@ -151,5 +147,4 @@ public final class RenderNodeAnimator { private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis, long canvasProperty, int paintField, int deltaValueType, float deltaValue); private static native void nSetDuration(long nativePtr, int duration); - private static native void nUnref(long nativePtr); } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index e1c6f522f101..be0c27dc4b2d 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -49,7 +49,6 @@ import android.view.InputEventSender; import android.view.KeyEvent; import android.view.View; import android.view.ViewRootImpl; -import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -322,8 +321,6 @@ public final class InputMethodManager { * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}. */ private final int[] mViewTopLeft = new int[2]; - private final CursorAnchorInfoBuilder mCursorAnchorInfoBuilder = new CursorAnchorInfoBuilder(); - // ----------------------------------------------------------- /** diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 25bcd44a744c..ac12357ffad9 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -50,28 +50,6 @@ public final class WebViewFactory { private static WebViewFactoryProvider sProviderInstance; private static final Object sProviderLock = new Object(); - public static boolean isExperimentalWebViewAvailable() { - // TODO: Remove callers of this method then remove it. - return false; // Hide the toggle in Developer Settings. - } - - /** @hide */ - public static void setUseExperimentalWebView(boolean enable) { - // TODO: Remove callers of this method then remove it. - } - - /** @hide */ - public static boolean useExperimentalWebView() { - // TODO: Remove callers of this method then remove it. - return true; - } - - /** @hide */ - public static boolean isUseExperimentalWebViewSet() { - // TODO: Remove callers of this method then remove it. - return false; // User has not modifed Developer Settings - } - static WebViewFactoryProvider getProvider() { synchronized (sProviderLock) { // For now the main purpose of this function (and the factory abstraction) is to keep diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index f4cd5fcf7b65..565ea130e221 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3267,7 +3267,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - private boolean startScrollIfNeeded(int y, MotionEvent vtev) { + private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) { // Check if we have moved far enough that it looks more like a // scroll than a tap final int deltaY = y - mMotionY; @@ -3296,14 +3296,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } - scrollIfNeeded(y, vtev); + scrollIfNeeded(x, y, vtev); return true; } return false; } - private void scrollIfNeeded(int y, MotionEvent vtev) { + private void scrollIfNeeded(int x, int y, MotionEvent vtev) { int rawDeltaY = y - mMotionY; if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) { rawDeltaY -= mScrollConsumed[1]; @@ -3384,33 +3384,39 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te vtev.offsetLocation(0, mScrollOffset[1]); } } else { - overScrollBy(0, overscroll, 0, mScrollY, 0, 0, - 0, mOverscrollDistance, true); - if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) { - // Don't allow overfling if we're at the edge. - if (mVelocityTracker != null) { - mVelocityTracker.clear(); - } + final boolean atOverscrollEdge = overScrollBy(0, overscroll, + 0, mScrollY, 0, 0, 0, mOverscrollDistance, true); + + if (atOverscrollEdge && mVelocityTracker != null) { + // Don't allow overfling if we're at the edge + mVelocityTracker.clear(); } final int overscrollMode = getOverScrollMode(); if (overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { - mDirection = 0; // Reset when entering overscroll. - mTouchMode = TOUCH_MODE_OVERSCROLL; - if (deltaY > 0) { - mEdgeGlowTop.onPull((float) overscroll / getHeight()); + if (!atOverscrollEdge) { + mDirection = 0; // Reset when entering overscroll. + mTouchMode = TOUCH_MODE_OVERSCROLL; + } + if (incrementalDeltaY > 0) { + mEdgeGlowTop.onPull((float) overscroll / getHeight(), + (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidate(mEdgeGlowTop.getBounds(false)); - } else if (deltaY < 0) { - mEdgeGlowBottom.onPull((float) overscroll / getHeight()); + invalidate(0, 0, getWidth(), + mEdgeGlowTop.getMaxHeight() + getPaddingTop()); + } else if (incrementalDeltaY < 0) { + mEdgeGlowBottom.onPull((float) overscroll / getHeight(), + 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidate(mEdgeGlowBottom.getBounds(true)); + invalidate(0, getHeight() - getPaddingBottom() - + mEdgeGlowBottom.getMaxHeight(), getWidth(), + getHeight()); } } } @@ -3445,17 +3451,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { if (rawDeltaY > 0) { - mEdgeGlowTop.onPull((float) overScrollDistance / getHeight()); + mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(), + (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidate(mEdgeGlowTop.getBounds(false)); + invalidate(0, 0, getWidth(), + mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } else if (rawDeltaY < 0) { - mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight()); + mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(), + 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidate(mEdgeGlowBottom.getBounds(true)); + invalidate(0, getHeight() - getPaddingBottom() - + mEdgeGlowBottom.getMaxHeight(), getWidth(), + getHeight()); } } } @@ -3703,7 +3714,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te case TOUCH_MODE_DONE_WAITING: // Check if we have moved far enough that it looks more like a // scroll than a tap. If so, we'll enter scrolling mode. - if (startScrollIfNeeded(y, vtev)) { + if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) { break; } // Otherwise, check containment within list bounds. If we're @@ -3723,7 +3734,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; case TOUCH_MODE_SCROLL: case TOUCH_MODE_OVERSCROLL: - scrollIfNeeded(y, vtev); + scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev); break; } } @@ -4022,8 +4033,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.translate(leftPadding, edgeY); mEdgeGlowTop.setSize(width, getHeight()); if (mEdgeGlowTop.draw(canvas)) { - mEdgeGlowTop.setPosition(leftPadding, edgeY); - invalidate(mEdgeGlowTop.getBounds(false)); + invalidate(0, 0, getWidth(), + mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } canvas.restoreToCount(restoreCount); } @@ -4040,9 +4051,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { - // Account for the rotation - mEdgeGlowBottom.setPosition(edgeX + width, edgeY); - invalidate(mEdgeGlowBottom.getBounds(true)); + invalidate(0, getHeight() - getPaddingBottom() - + mEdgeGlowBottom.getMaxHeight(), getWidth(), + getHeight()); } canvas.restoreToCount(restoreCount); } @@ -4161,7 +4172,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int y = (int) ev.getY(pointerIndex); initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); - if (startScrollIfNeeded(y, null)) { + if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) { return true; } break; diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index fa37443f70ea..83fbe8f8c627 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -16,7 +16,14 @@ package android.widget; +import android.content.res.TypedArray; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Xfermode; +import android.util.Log; import com.android.internal.R; import android.content.Context; @@ -59,12 +66,10 @@ public class EdgeEffect { private static final int PULL_DECAY_TIME = 1000; private static final float MAX_ALPHA = 1.f; - private static final float HELD_EDGE_SCALE_Y = 0.5f; - private static final float MAX_GLOW_HEIGHT = 4.f; + private static final float MAX_GLOW_HEIGHT = 1.5f; - private static final float PULL_GLOW_BEGIN = 1.f; - private static final float PULL_EDGE_BEGIN = 0.6f; + private static final float PULL_GLOW_BEGIN = 0.f; // Minimum velocity that will be absorbed private static final int MIN_VELOCITY = 100; @@ -73,24 +78,11 @@ public class EdgeEffect { private static final float EPSILON = 0.001f; - private final Drawable mEdge; - private final Drawable mGlow; - private int mWidth; - private int mHeight; - private int mX; - private int mY; - private static final int MIN_WIDTH = 300; - private final int mMinWidth; - - private float mEdgeAlpha; - private float mEdgeScaleY; + private static final float SIN_45 = (float) Math.sin(Math.PI / 4); + private float mGlowAlpha; private float mGlowScaleY; - private float mEdgeAlphaStart; - private float mEdgeAlphaFinish; - private float mEdgeScaleYStart; - private float mEdgeScaleYFinish; private float mGlowAlphaStart; private float mGlowAlphaFinish; private float mGlowScaleYStart; @@ -107,16 +99,11 @@ public class EdgeEffect { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; - // How much dragging should effect the height of the edge image. - // Number determined by user testing. - private static final int PULL_DISTANCE_EDGE_FACTOR = 7; - // How much dragging should effect the height of the glow image. // Number determined by user testing. private static final int PULL_DISTANCE_GLOW_FACTOR = 7; private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; - private static final int VELOCITY_EDGE_FACTOR = 8; private static final int VELOCITY_GLOW_FACTOR = 12; private int mState = STATE_IDLE; @@ -124,30 +111,26 @@ public class EdgeEffect { private float mPullDistance; private final Rect mBounds = new Rect(); - - private final int mEdgeHeight; - private final int mGlowHeight; - private final int mGlowWidth; - private final int mMaxEffectHeight; + private final RectF mArcRect = new RectF(); + private final Paint mPaint = new Paint(); + private float mRadius; + private float mDisplacement = 0.5f; + private float mTargetDisplacement = 0.5f; /** * Construct a new EdgeEffect with a theme appropriate for the provided context. * @param context Context used to provide theming and resource information for the EdgeEffect */ public EdgeEffect(Context context) { - final Resources res = context.getResources(); - mEdge = context.getDrawable(R.drawable.overscroll_edge); - mGlow = context.getDrawable(R.drawable.overscroll_glow); - - mEdgeHeight = mEdge.getIntrinsicHeight(); - mGlowHeight = mGlow.getIntrinsicHeight(); - mGlowWidth = mGlow.getIntrinsicWidth(); - - mMaxEffectHeight = (int) (Math.min( - mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f, - mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f); - - mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f); + mPaint.setAntiAlias(true); + final TypedArray a = context.obtainStyledAttributes( + com.android.internal.R.styleable.EdgeEffect); + final int themeColor = a.getColor( + com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666); + a.recycle(); + mPaint.setColor((themeColor & 0xffffff) | 0x66000000); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); mInterpolator = new DecelerateInterpolator(); } @@ -158,20 +141,12 @@ public class EdgeEffect { * @param height Effect height in pixels */ public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - } + final float r = width * 0.5f / SIN_45; + final float y = SIN_45 * r; + final float h = r - y; + mRadius = r; - /** - * Set the position of this edge effect in pixels. This position is - * only used by {@link #getBounds(boolean)}. - * - * @param x The position of the edge effect on the X axis - * @param y The position of the edge effect on the Y axis - */ - void setPosition(int x, int y) { - mX = x; - mY = y; + mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); } /** @@ -199,17 +174,38 @@ public class EdgeEffect { * The host view should always {@link android.view.View#invalidate()} after this * and draw the results accordingly. * + * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement + * of the pull point is known.</p> + * * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to * 1.f (full length of the view) or negative values to express change * back toward the edge reached to initiate the effect. */ public void onPull(float deltaDistance) { + onPull(deltaDistance, 0.5f); + } + + /** + * A view should call this when content is pulled away from an edge by the user. + * This will update the state of the current visual effect and its associated animation. + * The host view should always {@link android.view.View#invalidate()} after this + * and draw the results accordingly. + * + * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to + * 1.f (full length of the view) or negative values to express change + * back toward the edge reached to initiate the effect. + * @param displacement The displacement from the starting side of the effect of the point + * initiating the pull. In the case of touch this is the finger position. + * Values may be from 0-1. + */ + public void onPull(float deltaDistance, float displacement) { final long now = AnimationUtils.currentAnimationTimeMillis(); + mTargetDisplacement = displacement; if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { return; } if (mState != STATE_PULL) { - mGlowScaleY = PULL_GLOW_BEGIN; + mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY); } mState = STATE_PULL; @@ -217,15 +213,10 @@ public class EdgeEffect { mDuration = PULL_TIME; mPullDistance += deltaDistance; - float distance = Math.abs(mPullDistance); - - mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); - mEdgeScaleY = mEdgeScaleYStart = Math.max( - HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, mGlowAlpha + - (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); + (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); float glowChange = Math.abs(deltaDistance); if (deltaDistance > 0 && mPullDistance < 0) { @@ -239,8 +230,6 @@ public class EdgeEffect { mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); - mEdgeAlphaFinish = mEdgeAlpha; - mEdgeScaleYFinish = mEdgeScaleY; mGlowAlphaFinish = mGlowAlpha; mGlowScaleYFinish = mGlowScaleY; } @@ -259,13 +248,9 @@ public class EdgeEffect { } mState = STATE_RECEDE; - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; @@ -290,30 +275,21 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = 0.15f + (velocity * 0.02f); - // The edge should always be at least partially visible, regardless - // of velocity. - mEdgeAlphaStart = 0.f; - mEdgeScaleY = mEdgeScaleYStart = 0.f; // The glow depends more on the velocity, and therefore starts out // nearly invisible. mGlowAlphaStart = 0.3f; - mGlowScaleYStart = 0.f; + mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); - // Factor the velocity by 8. Testing on device shows this works best to - // reflect the strength of the user's scrolling. - mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); - // Edge should never get larger than the size of its asset. - mEdgeScaleYFinish = Math.max( - HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); // Growth for the size of the glow should be quadratic to properly // respond // to a user's scrolling speed. The faster the scrolling speed, the more // intense the effect should be for both the size and the saturation. - mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); + mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); // Alpha should change for the glow as well as size. mGlowAlphaFinish = Math.max( mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); + mTargetDisplacement = 0.5f; } @@ -330,52 +306,42 @@ public class EdgeEffect { public boolean draw(Canvas canvas) { update(); - mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); - - int glowBottom = (int) Math.min( - mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f, - mGlowHeight * MAX_GLOW_HEIGHT); - if (mWidth < mMinWidth) { - // Center the glow and clip it. - int glowLeft = (mWidth - mMinWidth)/2; - mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); - } else { - // Stretch the glow to fit. - mGlow.setBounds(0, 0, mWidth, glowBottom); - } + final int count = canvas.save(); - mGlow.draw(canvas); + final float y = mBounds.height(); + final float centerY = y - mRadius; + final float centerX = mBounds.centerX(); + mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius); + canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0); - mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); - - int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY); - if (mWidth < mMinWidth) { - // Center the edge and clip it. - int edgeLeft = (mWidth - mMinWidth)/2; - mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); - } else { - // Stretch the edge to fit. - mEdge.setBounds(0, 0, mWidth, edgeBottom); + final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; + float translateX = mBounds.width() * displacement; + float translateY = 0; + if (mGlowScaleY > 1.f) { + translateY = (mGlowScaleY - 1.f) * mBounds.height(); } - mEdge.draw(canvas); - - if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) { + canvas.clipRect(Float.MIN_VALUE, mBounds.top, + Float.MAX_VALUE, Float.MAX_VALUE); + canvas.translate(translateX, translateY); + canvas.drawArc(mArcRect, 0, 180, true, mPaint); + canvas.restoreToCount(count); + + boolean oneLastFrame = false; + if (mState == STATE_RECEDE && mGlowScaleY == 0) { mState = STATE_IDLE; + oneLastFrame = true; } - return mState != STATE_IDLE; + return mState != STATE_IDLE || oneLastFrame; } /** - * Returns the bounds of the edge effect. - * - * @hide + * Return the maximum height that the edge effect will be drawn at given the original + * {@link #setSize(int, int) input size}. + * @return The maximum height of the edge effect */ - public Rect getBounds(boolean reverse) { - mBounds.set(0, 0, mWidth, mMaxEffectHeight); - mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0)); - - return mBounds; + public int getMaxHeight() { + return (int) (mBounds.height() * MAX_GLOW_HEIGHT + 0.5f); } private void update() { @@ -384,10 +350,9 @@ public class EdgeEffect { final float interp = mInterpolator.getInterpolation(t); - mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; - mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; + mDisplacement = (mDisplacement + mTargetDisplacement) / 2; if (t >= 1.f - EPSILON) { switch (mState) { @@ -396,14 +361,10 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = RECEDE_TIME; - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - // After absorb, the glow and edge should fade to nothing. - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; + // After absorb, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; @@ -412,26 +373,14 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = PULL_DECAY_TIME; - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - // After pull, the glow and edge should fade to nothing. - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; + // After pull, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: - // When receding, we want edge to decrease more slowly - // than the glow. - float factor = mGlowScaleYFinish != 0 ? 1 - / (mGlowScaleYFinish * mGlowScaleYFinish) - : Float.MAX_VALUE; - mEdgeScaleY = mEdgeScaleYStart + - (mEdgeScaleYFinish - mEdgeScaleYStart) * - interp * factor; mState = STATE_RECEDE; break; case STATE_RECEDE: diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 25d4f4297042..0c65c5044da3 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -616,12 +616,14 @@ public class HorizontalScrollView extends FrameLayout { if (canOverscroll) { final int pulledToX = oldX + deltaX; if (pulledToX < 0) { - mEdgeGlowLeft.onPull((float) deltaX / getWidth()); + mEdgeGlowLeft.onPull((float) deltaX / getWidth(), + 1.f - ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowRight.isFinished()) { mEdgeGlowRight.onRelease(); } } else if (pulledToX > range) { - mEdgeGlowRight.onPull((float) deltaX / getWidth()); + mEdgeGlowRight.onPull((float) deltaX / getWidth(), + ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowLeft.isFinished()) { mEdgeGlowLeft.onRelease(); } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 0fa75a6f7302..fd048908260c 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -669,12 +669,14 @@ public class ScrollView extends FrameLayout { } else if (canOverscroll) { final int pulledToY = oldY + deltaY; if (pulledToY < 0) { - mEdgeGlowTop.onPull((float) deltaY / getHeight()); + mEdgeGlowTop.onPull((float) deltaY / getHeight(), + ev.getX(activePointerIndex) / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } } else if (pulledToY > range) { - mEdgeGlowBottom.onPull((float) deltaY / getHeight()); + mEdgeGlowBottom.onPull((float) deltaY / getHeight(), + 1.f - ev.getX(activePointerIndex) / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index 882bec913f69..41f33375f5ed 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -1108,13 +1108,6 @@ public final class ProcessStats implements Parcelable { mRuntime = runtime; } } - String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview"; - if (!Objects.equals(webview, mWebView)) { - changed = true; - if (update) { - mWebView = webview; - } - } return changed; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 1aff1909c045..7bd5b12fc791 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -188,8 +188,7 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mShuttingDown; - HashMap<String, SparseBooleanArray>[] mActiveEvents - = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT]; + final HistoryEventTracker mActiveEvents = new HistoryEventTracker(); long mHistoryBaseTime; boolean mHaveBatteryLevel = false; @@ -2297,44 +2296,8 @@ public final class BatteryStatsImpl extends BatteryStats { public void noteEventLocked(int code, String name, int uid) { uid = mapUid(uid); - if ((code&HistoryItem.EVENT_FLAG_START) != 0) { - int idx = code&~HistoryItem.EVENT_FLAG_START; - HashMap<String, SparseBooleanArray> active = mActiveEvents[idx]; - if (active == null) { - active = new HashMap<String, SparseBooleanArray>(); - mActiveEvents[idx] = active; - } - SparseBooleanArray uids = active.get(name); - if (uids == null) { - uids = new SparseBooleanArray(); - active.put(name, uids); - } - if (uids.get(uid)) { - // Already set, nothing to do! - return; - } - uids.put(uid, true); - } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) { - int idx = code&~HistoryItem.EVENT_FLAG_FINISH; - HashMap<String, SparseBooleanArray> active = mActiveEvents[idx]; - if (active == null) { - // not currently active, nothing to do. - return; - } - SparseBooleanArray uids = active.get(name); - if (uids == null) { - // not currently active, nothing to do. - return; - } - idx = uids.indexOfKey(uid); - if (idx < 0 || !uids.valueAt(idx)) { - // not currently active, nothing to do. - return; - } - uids.removeAt(idx); - if (uids.size() <= 0) { - active.remove(name); - } + if (!mActiveEvents.updateState(code, name, uid, 0)) { + return; } final long elapsedRealtime = SystemClock.elapsedRealtime(); final long uptime = SystemClock.uptimeMillis(); @@ -2348,6 +2311,9 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private String mInitialAcquireWakeName; + private int mInitialAcquireWakeUid = -1; + public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type, boolean unimportantForLogging, long elapsedRealtime, long uptime) { uid = mapUid(uid); @@ -2360,8 +2326,9 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " + Integer.toHexString(mHistoryCur.states)); mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName != null ? historyName : name; - mHistoryCur.wakelockTag.uid = uid; + mHistoryCur.wakelockTag.string = mInitialAcquireWakeName + = historyName != null ? historyName : name; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; mWakeLockImportant = !unimportantForLogging; addHistoryRecordLocked(elapsedRealtime, uptime); } else if (!mWakeLockImportant && !unimportantForLogging) { @@ -2369,8 +2336,9 @@ public final class BatteryStatsImpl extends BatteryStats { // We'll try to update the last tag. mHistoryLastWritten.wakelockTag = null; mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName != null ? historyName : name; - mHistoryCur.wakelockTag.uid = uid; + mHistoryCur.wakelockTag.string = mInitialAcquireWakeName + = historyName != null ? historyName : name; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; addHistoryRecordLocked(elapsedRealtime, uptime); } mWakeLockImportant = true; @@ -2395,6 +2363,14 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: " + Integer.toHexString(mHistoryCur.states)); + if ((name != null && !name.equals(mInitialAcquireWakeName)) + || uid != mInitialAcquireWakeUid) { + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = name; + mHistoryCur.wakelockTag.uid = uid; + } + mInitialAcquireWakeName = null; + mInitialAcquireWakeUid = -1; addHistoryRecordLocked(elapsedRealtime, uptime); } } @@ -5699,7 +5675,8 @@ public final class BatteryStatsImpl extends BatteryStats { final long lastRealtime = out.time; final long lastWalltime = out.currentTime; readHistoryDelta(mHistoryBuffer, out); - if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) { + if (out.cmd != HistoryItem.CMD_CURRENT_TIME + && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) { out.currentTime = lastWalltime + (out.time - lastRealtime); } return true; @@ -5845,17 +5822,15 @@ public final class BatteryStatsImpl extends BatteryStats { private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) { for (int i=0; i<HistoryItem.EVENT_COUNT; i++) { - HashMap<String, SparseBooleanArray> active = mActiveEvents[i]; + HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i); if (active == null) { continue; } - for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) { - SparseBooleanArray uids = ent.getValue(); + for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { + SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - if (uids.valueAt(j)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), - uids.keyAt(j)); - } + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), + uids.keyAt(j)); } } } @@ -5971,7 +5946,8 @@ public final class BatteryStatsImpl extends BatteryStats { boolean reset) { mRecordingHistory = true; mHistoryCur.currentTime = System.currentTimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME, + addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, + reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME, mHistoryCur); mHistoryCur.currentTime = 0; if (reset) { diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index 52281d92fd7b..34f62bac29ea 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -450,6 +450,7 @@ public class AsyncChannel { public void disconnect() { if ((mConnection != null) && (mSrcContext != null)) { mSrcContext.unbindService(mConnection); + mConnection = null; } try { // Send the DISCONNECTED, although it may not be received @@ -463,10 +464,12 @@ public class AsyncChannel { // Tell source we're disconnected. if (mSrcHandler != null) { replyDisconnected(STATUS_SUCCESSFUL); + mSrcHandler = null; } // Unlink only when bindService isn't used if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) { mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0); + mDeathMonitor = null; } } diff --git a/core/java/com/android/internal/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java new file mode 100644 index 000000000000..0bd4d3a01bd8 --- /dev/null +++ b/core/java/com/android/internal/util/VirtualRefBasePtr.java @@ -0,0 +1,47 @@ +/* + * 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.internal.util; + +/** + * Helper class that contains a strong reference to a VirtualRefBase native + * object. This will incStrong in the ctor, and decStrong in the finalizer + */ +public final class VirtualRefBasePtr { + private long mNativePtr; + + public VirtualRefBasePtr(long ptr) { + mNativePtr = ptr; + nIncStrong(mNativePtr); + } + + public long get() { + return mNativePtr; + } + + @Override + protected void finalize() throws Throwable { + try { + nDecStrong(mNativePtr); + mNativePtr = 0; + } finally { + super.finalize(); + } + } + + private static native void nIncStrong(long ptr); + private static native void nDecStrong(long ptr); +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 51e2871867e2..26f77b5de827 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -155,7 +155,8 @@ LOCAL_SRC_FILES:= \ android_content_res_Configuration.cpp \ android_animation_PropertyValuesHolder.cpp \ com_android_internal_net_NetworkStatsFactory.cpp \ - com_android_internal_os_Zygote.cpp + com_android_internal_os_Zygote.cpp \ + com_android_internal_util_VirtualRefBasePtr.cpp LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 66fbb8ecb14a..9941cd9dfa41 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -181,6 +181,7 @@ extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env); extern int register_com_android_internal_os_Zygote(JNIEnv *env); +extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); static AndroidRuntime* gCurRuntime = NULL; @@ -1262,6 +1263,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_MemoryFile), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_os_Zygote), + REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), REG_JNI(register_android_hardware_SensorManager), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index e0fa9ba432a5..032851749c40 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1,838 +1,838 @@ -#include "SkBitmap.h"
-#include "SkPixelRef.h"
-#include "SkImageEncoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-#include "SkUnPreMultiply.h"
-#include "SkStream.h"
-
-#include <binder/Parcel.h>
-#include "android_os_Parcel.h"
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#include <Caches.h>
-
-#if 0
- #define TRACE_BITMAP(code) code
-#else
- #define TRACE_BITMAP(code)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Conversions to/from SkColor, for get/setPixels, and the create method, which
-// is basically like setPixels
-
-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
- int x, int y);
-
-static void FromColor_D32(void* dst, const SkColor src[], int width,
- int, int) {
- SkPMColor* d = (SkPMColor*)dst;
-
- for (int i = 0; i < width; i++) {
- *d++ = SkPreMultiplyColor(*src++);
- }
-}
-
-static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
- int, int) {
- // SkColor's ordering may be different from SkPMColor
- if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
- memcpy(dst, src, width * sizeof(SkColor));
- return;
- }
-
- // order isn't same, repack each pixel manually
- SkPMColor* d = (SkPMColor*)dst;
- for (int i = 0; i < width; i++) {
- SkColor c = *src++;
- *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
- SkColorGetG(c), SkColorGetB(c));
- }
-}
-
-static void FromColor_D565(void* dst, const SkColor src[], int width,
- int x, int y) {
- uint16_t* d = (uint16_t*)dst;
-
- DITHER_565_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkColor c = *src++;
- *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
- DITHER_VALUE(x));
- }
-}
-
-static void FromColor_D4444(void* dst, const SkColor src[], int width,
- int x, int y) {
- SkPMColor16* d = (SkPMColor16*)dst;
-
- DITHER_4444_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkPMColor pmc = SkPreMultiplyColor(*src++);
- *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-// *d++ = SkPixel32ToPixel4444(pmc);
- }
-}
-
-static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
- int x, int y) {
- SkPMColor16* d = (SkPMColor16*)dst;
-
- DITHER_4444_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkColor c = *src++;
-
- // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
- SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
- SkColorGetG(c), SkColorGetB(c));
- *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-// *d++ = SkPixel32ToPixel4444(pmc);
- }
-}
-
-// can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
- case SkBitmap::kARGB_4444_Config:
- return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
- case SkBitmap::kRGB_565_Config:
- return FromColor_D565;
- default:
- break;
- }
- return NULL;
-}
-
-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
- int x, int y, int width, int height,
- const SkBitmap& dstBitmap, bool isPremultiplied) {
- SkAutoLockPixels alp(dstBitmap);
- void* dst = dstBitmap.getPixels();
- FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
-
- if (NULL == dst || NULL == proc) {
- return false;
- }
-
- const jint* array = env->GetIntArrayElements(srcColors, NULL);
- const SkColor* src = (const SkColor*)array + srcOffset;
-
- // reset to to actual choice from caller
- dst = dstBitmap.getAddr(x, y);
- // now copy/convert each scanline
- for (int y = 0; y < height; y++) {
- proc(dst, src, width, x, y);
- src += srcStride;
- dst = (char*)dst + dstBitmap.rowBytes();
- }
-
- dstBitmap.notifyPixelsChanged();
-
- env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
- JNI_ABORT);
- return true;
-}
-
-//////////////////// ToColor procs
-
-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
- SkColorTable*);
-
-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
- } while (--width != 0);
-}
-
-static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = *s++;
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = *s++;
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- SkPMColor c = SkPixel4444ToPixel32(*s++);
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- SkPMColor c = SkPixel4444ToPixel32(*s++);
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S565(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const uint16_t* s = (const uint16_t*)src;
- do {
- uint16_t c = *s++;
- *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
- SkPacked16ToB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- SkPMColor c = colors[*s++];
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- SkPMColor c = colors[*s++];
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
- switch (src.config()) {
- case SkBitmap::kARGB_8888_Config:
- if (src.isOpaque()) return ToColor_S32_Opaque;
- return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
- case SkBitmap::kARGB_4444_Config:
- if (src.isOpaque()) return ToColor_S4444_Opaque;
- return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
- case SkBitmap::kRGB_565_Config:
- return ToColor_S565;
- case SkBitmap::kIndex8_Config:
- if (src.getColorTable() == NULL) {
- return NULL;
- }
- if (src.isOpaque()) return ToColor_SI8_Opaque;
- return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
- default:
- break;
- }
- return NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-static int getPremulBitmapCreateFlags(bool isMutable) {
- int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
- if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
- return flags;
-}
-
-static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
- jint offset, jint stride, jint width, jint height,
- jint configHandle, jboolean isMutable) {
- SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (NULL != jColors) {
- size_t n = env->GetArrayLength(jColors);
- if (n < SkAbs32(stride) * (size_t)height) {
- doThrowAIOOBE(env);
- return NULL;
- }
- }
-
- // ARGB_4444 is a deprecated format, convert automatically to 8888
- if (config == SkBitmap::kARGB_4444_Config) {
- config = SkBitmap::kARGB_8888_Config;
- }
-
- SkBitmap bitmap;
- bitmap.setConfig(config, width, height);
-
- jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
- if (NULL == buff) {
- return NULL;
- }
-
- if (jColors != NULL) {
- GraphicsJNI::SetPixels(env, jColors, offset, stride,
- 0, 0, width, height, bitmap, true);
- }
-
- return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
- getPremulBitmapCreateFlags(isMutable), NULL, NULL);
-}
-
-static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
- jint dstConfigHandle, jboolean isMutable) {
- const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
- SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);
- SkBitmap result;
- JavaPixelAllocator allocator(env);
-
+#include "SkBitmap.h" +#include "SkPixelRef.h" +#include "SkImageEncoder.h" +#include "SkColorPriv.h" +#include "GraphicsJNI.h" +#include "SkDither.h" +#include "SkUnPreMultiply.h" +#include "SkStream.h" + +#include <binder/Parcel.h> +#include "android_os_Parcel.h" +#include "android_util_Binder.h" +#include "android_nio_utils.h" +#include "CreateJavaOutputStreamAdaptor.h" + +#include <jni.h> + +#include <Caches.h> + +#if 0 + #define TRACE_BITMAP(code) code +#else + #define TRACE_BITMAP(code) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Conversions to/from SkColor, for get/setPixels, and the create method, which +// is basically like setPixels + +typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, + int x, int y); + +static void FromColor_D32(void* dst, const SkColor src[], int width, + int, int) { + SkPMColor* d = (SkPMColor*)dst; + + for (int i = 0; i < width; i++) { + *d++ = SkPreMultiplyColor(*src++); + } +} + +static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, + int, int) { + // SkColor's ordering may be different from SkPMColor + if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) { + memcpy(dst, src, width * sizeof(SkColor)); + return; + } + + // order isn't same, repack each pixel manually + SkPMColor* d = (SkPMColor*)dst; + for (int i = 0; i < width; i++) { + SkColor c = *src++; + *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), + SkColorGetG(c), SkColorGetB(c)); + } +} + +static void FromColor_D565(void* dst, const SkColor src[], int width, + int x, int y) { + uint16_t* d = (uint16_t*)dst; + + DITHER_565_SCAN(y); + for (int stop = x + width; x < stop; x++) { + SkColor c = *src++; + *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), + DITHER_VALUE(x)); + } +} + +static void FromColor_D4444(void* dst, const SkColor src[], int width, + int x, int y) { + SkPMColor16* d = (SkPMColor16*)dst; + + DITHER_4444_SCAN(y); + for (int stop = x + width; x < stop; x++) { + SkPMColor pmc = SkPreMultiplyColor(*src++); + *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); +// *d++ = SkPixel32ToPixel4444(pmc); + } +} + +static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, + int x, int y) { + SkPMColor16* d = (SkPMColor16*)dst; + + DITHER_4444_SCAN(y); + for (int stop = x + width; x < stop; x++) { + SkColor c = *src++; + + // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied + SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), + SkColorGetG(c), SkColorGetB(c)); + *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); +// *d++ = SkPixel32ToPixel4444(pmc); + } +} + +// can return NULL +static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) { + switch (config) { + case SkBitmap::kARGB_8888_Config: + return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw; + case SkBitmap::kARGB_4444_Config: + return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw; + case SkBitmap::kRGB_565_Config: + return FromColor_D565; + default: + break; + } + return NULL; +} + +bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, + int x, int y, int width, int height, + const SkBitmap& dstBitmap, bool isPremultiplied) { + SkAutoLockPixels alp(dstBitmap); + void* dst = dstBitmap.getPixels(); + FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied); + + if (NULL == dst || NULL == proc) { + return false; + } + + const jint* array = env->GetIntArrayElements(srcColors, NULL); + const SkColor* src = (const SkColor*)array + srcOffset; + + // reset to to actual choice from caller + dst = dstBitmap.getAddr(x, y); + // now copy/convert each scanline + for (int y = 0; y < height; y++) { + proc(dst, src, width, x, y); + src += srcStride; + dst = (char*)dst + dstBitmap.rowBytes(); + } + + dstBitmap.notifyPixelsChanged(); + + env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), + JNI_ABORT); + return true; +} + +//////////////////// ToColor procs + +typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, + SkColorTable*); + +static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + *dst++ = SkUnPreMultiply::PMColorToColor(*s++); + } while (--width != 0); +} + +static void ToColor_S32_Raw(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + SkPMColor c = *s++; + *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), + SkGetPackedG32(c), SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + SkPMColor c = *s++; + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor16* s = (const SkPMColor16*)src; + do { + *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); + } while (--width != 0); +} + +static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor16* s = (const SkPMColor16*)src; + do { + SkPMColor c = SkPixel4444ToPixel32(*s++); + *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), + SkGetPackedG32(c), SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor16* s = (const SkPMColor16*)src; + do { + SkPMColor c = SkPixel4444ToPixel32(*s++); + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S565(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const uint16_t* s = (const uint16_t*)src; + do { + uint16_t c = *s++; + *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), + SkPacked16ToB32(c)); + } while (--width != 0); +} + +static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, + SkColorTable* ctable) { + SkASSERT(width > 0); + const uint8_t* s = (const uint8_t*)src; + const SkPMColor* colors = ctable->lockColors(); + do { + *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); + } while (--width != 0); + ctable->unlockColors(); +} + +static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width, + SkColorTable* ctable) { + SkASSERT(width > 0); + const uint8_t* s = (const uint8_t*)src; + const SkPMColor* colors = ctable->lockColors(); + do { + SkPMColor c = colors[*s++]; + *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), + SkGetPackedG32(c), SkGetPackedB32(c)); + } while (--width != 0); + ctable->unlockColors(); +} + +static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, + SkColorTable* ctable) { + SkASSERT(width > 0); + const uint8_t* s = (const uint8_t*)src; + const SkPMColor* colors = ctable->lockColors(); + do { + SkPMColor c = colors[*s++]; + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); + ctable->unlockColors(); +} + +// can return NULL +static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) { + switch (src.config()) { + case SkBitmap::kARGB_8888_Config: + if (src.isOpaque()) return ToColor_S32_Opaque; + return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw; + case SkBitmap::kARGB_4444_Config: + if (src.isOpaque()) return ToColor_S4444_Opaque; + return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw; + case SkBitmap::kRGB_565_Config: + return ToColor_S565; + case SkBitmap::kIndex8_Config: + if (src.getColorTable() == NULL) { + return NULL; + } + if (src.isOpaque()) return ToColor_SI8_Opaque; + return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha; + default: + break; + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static int getPremulBitmapCreateFlags(bool isMutable) { + int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied; + if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable; + return flags; +} + +static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, + jint offset, jint stride, jint width, jint height, + jint configHandle, jboolean isMutable) { + SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle); + if (NULL != jColors) { + size_t n = env->GetArrayLength(jColors); + if (n < SkAbs32(stride) * (size_t)height) { + doThrowAIOOBE(env); + return NULL; + } + } + + // ARGB_4444 is a deprecated format, convert automatically to 8888 + if (config == SkBitmap::kARGB_4444_Config) { + config = SkBitmap::kARGB_8888_Config; + } + + SkBitmap bitmap; + bitmap.setConfig(config, width, height); + + jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL); + if (NULL == buff) { + return NULL; + } + + if (jColors != NULL) { + GraphicsJNI::SetPixels(env, jColors, offset, stride, + 0, 0, width, height, bitmap, true); + } + + return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, + getPremulBitmapCreateFlags(isMutable), NULL, NULL); +} + +static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, + jint dstConfigHandle, jboolean isMutable) { + const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle); + SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle); + SkBitmap result; + JavaPixelAllocator allocator(env); + if (!src->copyTo(&result, SkBitmapConfigToColorType(dstConfig), &allocator)) { - return NULL;
- }
- return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
- getPremulBitmapCreateFlags(isMutable), NULL, NULL);
-}
-
-static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
- if (android::uirenderer::Caches::hasInstance()) {
- android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
- return;
- }
-#endif // USE_OPENGL_RENDERER
- delete bitmap;
-}
-
-static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
- if (android::uirenderer::Caches::hasInstance()) {
- bool result;
- result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
- return result ? JNI_TRUE : JNI_FALSE;
- }
-#endif // USE_OPENGL_RENDERER
- bitmap->setPixels(NULL, NULL);
- return JNI_TRUE;
-}
-
-static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
- // done in native as there's no way to get BytesPerPixel in Java
- doThrowIAE(env, "Bitmap not large enough to support new configuration");
- return;
- }
- SkPixelRef* ref = bitmap->pixelRef();
- SkSafeRef(ref);
- bitmap->setConfig(config, width, height);
- bitmap->setPixelRef(ref);
-
- // notifyPixelsChanged will increment the generation ID even though the actual pixel data
- // hasn't been touched. This signals the renderer that the bitmap (including width, height,
- // and config) has changed.
- ref->notifyPixelsChanged();
- SkSafeUnref(ref);
-}
-
-// These must match the int values in Bitmap.java
-enum JavaEncodeFormat {
- kJPEG_JavaEncodeFormat = 0,
- kPNG_JavaEncodeFormat = 1,
- kWEBP_JavaEncodeFormat = 2
-};
-
-static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint format, jint quality,
- jobject jstream, jbyteArray jstorage) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkImageEncoder::Type fm;
-
- switch (format) {
- case kJPEG_JavaEncodeFormat:
- fm = SkImageEncoder::kJPEG_Type;
- break;
- case kPNG_JavaEncodeFormat:
- fm = SkImageEncoder::kPNG_Type;
- break;
- case kWEBP_JavaEncodeFormat:
- fm = SkImageEncoder::kWEBP_Type;
- break;
- default:
- return JNI_FALSE;
- }
-
- bool success = false;
- if (NULL != bitmap) {
- SkAutoLockPixels alp(*bitmap);
-
- if (NULL == bitmap->getPixels()) {
- return JNI_FALSE;
- }
-
- SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
- if (NULL == strm) {
- return JNI_FALSE;
- }
-
- SkImageEncoder* encoder = SkImageEncoder::Create(fm);
- if (NULL != encoder) {
- success = encoder->encodeStream(strm, *bitmap, quality);
- delete encoder;
- }
- delete strm;
- }
- return success ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->eraseColor(color);
-}
-
-static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->rowBytes());
-}
-
-static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->config());
-}
-
-static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->getGenerationID());
-}
-
-static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasAlpha, jboolean isPremul) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- if (!hasAlpha) {
- bitmap->setAlphaType(kOpaque_SkAlphaType);
- } else if (isPremul) {
- bitmap->setAlphaType(kPremul_SkAlphaType);
- } else {
- bitmap->setAlphaType(kUnpremul_SkAlphaType);
- }
-}
-
-static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasMipMap) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->setHasHardwareMipMap(hasMipMap);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
- if (parcel == NULL) {
- SkDebugf("-------- unparcel parcel is NULL\n");
- return NULL;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- const bool isMutable = p->readInt32() != 0;
- const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
- const int width = p->readInt32();
- const int height = p->readInt32();
- const int rowBytes = p->readInt32();
- const int density = p->readInt32();
-
- if (SkBitmap::kARGB_8888_Config != config &&
- SkBitmap::kRGB_565_Config != config &&
- SkBitmap::kARGB_4444_Config != config &&
- SkBitmap::kIndex8_Config != config &&
- SkBitmap::kA8_Config != config) {
- SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
- return NULL;
- }
-
- SkBitmap* bitmap = new SkBitmap;
-
- bitmap->setConfig(config, width, height, rowBytes);
-
- SkColorTable* ctable = NULL;
- if (config == SkBitmap::kIndex8_Config) {
- int count = p->readInt32();
- if (count > 0) {
- size_t size = count * sizeof(SkPMColor);
- const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
- ctable = new SkColorTable(src, count);
- }
- }
-
- jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
- if (NULL == buffer) {
- SkSafeUnref(ctable);
- delete bitmap;
- return NULL;
- }
-
- SkSafeUnref(ctable);
-
- size_t size = bitmap->getSize();
-
- android::Parcel::ReadableBlob blob;
- android::status_t status = p->readBlob(size, &blob);
- if (status) {
- doThrowRE(env, "Could not read bitmap from parcel blob.");
- delete bitmap;
- return NULL;
- }
-
- bitmap->lockPixels();
- memcpy(bitmap->getPixels(), blob.data(), size);
- bitmap->unlockPixels();
-
- blob.release();
-
- return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
- NULL, NULL, density);
-}
-
-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
- jlong bitmapHandle,
- jboolean isMutable, jint density,
- jobject parcel) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- if (parcel == NULL) {
- SkDebugf("------- writeToParcel null parcel\n");
- return JNI_FALSE;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- p->writeInt32(isMutable);
- p->writeInt32(bitmap->config());
- p->writeInt32(bitmap->width());
- p->writeInt32(bitmap->height());
- p->writeInt32(bitmap->rowBytes());
- p->writeInt32(density);
-
- if (bitmap->config() == SkBitmap::kIndex8_Config) {
- SkColorTable* ctable = bitmap->getColorTable();
- if (ctable != NULL) {
- int count = ctable->count();
- p->writeInt32(count);
- memcpy(p->writeInplace(count * sizeof(SkPMColor)),
- ctable->lockColors(), count * sizeof(SkPMColor));
- ctable->unlockColors();
- } else {
- p->writeInt32(0); // indicate no ctable
- }
- }
-
- size_t size = bitmap->getSize();
-
- android::Parcel::WritableBlob blob;
- android::status_t status = p->writeBlob(size, &blob);
- if (status) {
- doThrowRE(env, "Could not write bitmap to parcel blob.");
- return JNI_FALSE;
- }
-
- bitmap->lockPixels();
- const void* pSrc = bitmap->getPixels();
- if (pSrc == NULL) {
- memset(blob.data(), 0, size);
- } else {
- memcpy(blob.data(), pSrc, size);
- }
- bitmap->unlockPixels();
-
- blob.release();
- return JNI_TRUE;
-}
-
-static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
- jlong srcHandle, jlong paintHandle,
- jintArray offsetXY) {
- const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
- const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkIPoint offset;
- SkBitmap* dst = new SkBitmap;
- JavaPixelAllocator allocator(env);
-
- src->extractAlpha(dst, paint, &allocator, &offset);
- // If Skia can't allocate pixels for destination bitmap, it resets
- // it, that is set its pixels buffer to NULL, and zero width and height.
- if (dst->getPixels() == NULL && src->getPixels() != NULL) {
- delete dst;
- doThrowOOME(env, "failed to allocate pixels for alpha");
- return NULL;
- }
- if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
- int* array = env->GetIntArrayElements(offsetXY, NULL);
- array[0] = offset.fX;
- array[1] = offset.fY;
- env->ReleaseIntArrayElements(offsetXY, array, 0);
- }
-
- return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
- getPremulBitmapCreateFlags(true), NULL, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
- if (NULL == proc) {
- return 0;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return 0;
- }
-
- SkColor dst[1];
- proc(dst, src, 1, bitmap->getColorTable());
- return static_cast<jint>(dst[0]);
-}
-
-static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
- jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
- if (NULL == proc) {
- return;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return;
- }
-
- SkColorTable* ctable = bitmap->getColorTable();
- jint* dst = env->GetIntArrayElements(pixelArray, NULL);
- SkColor* d = (SkColor*)dst + offset;
- while (--height >= 0) {
- proc(d, src, width, ctable);
- d += stride;
- src = (void*)((const char*)src + bitmap->rowBytes());
- }
- env->ReleaseIntArrayElements(pixelArray, dst, 0);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkColor color = static_cast<SkColor>(colorHandle);
- SkAutoLockPixels alp(*bitmap);
- if (NULL == bitmap->getPixels()) {
- return;
- }
-
- FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
- if (NULL == proc) {
- return;
- }
-
- proc(bitmap->getAddr(x, y), &color, 1, x, y);
- bitmap->notifyPixelsChanged();
-}
-
-static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
- jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
- x, y, width, height, *bitmap, isPremultiplied);
-}
-
-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
- jlong bitmapHandle, jobject jbuffer) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
- const void* src = bitmap->getPixels();
-
- if (NULL != src) {
- android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
-
- // the java side has already checked that buffer is large enough
- memcpy(abp.pointer(), src, bitmap->getSize());
- }
-}
-
-static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
- jlong bitmapHandle, jobject jbuffer) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
- void* dst = bitmap->getPixels();
-
- if (NULL != dst) {
- android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
- // the java side has already checked that buffer is large enough
- memcpy(dst, abp.pointer(), bitmap->getSize());
- bitmap->notifyPixelsChanged();
- }
-}
-
-static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
- jlong bm1Handle) {
- const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
- const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
- if (bm0->width() != bm1->width() ||
- bm0->height() != bm1->height() ||
- bm0->config() != bm1->config()) {
- return JNI_FALSE;
- }
-
- SkAutoLockPixels alp0(*bm0);
- SkAutoLockPixels alp1(*bm1);
-
- // if we can't load the pixels, return false
- if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
- return JNI_FALSE;
- }
-
- if (bm0->config() == SkBitmap::kIndex8_Config) {
- SkColorTable* ct0 = bm0->getColorTable();
- SkColorTable* ct1 = bm1->getColorTable();
- if (NULL == ct0 || NULL == ct1) {
- return JNI_FALSE;
- }
- if (ct0->count() != ct1->count()) {
- return JNI_FALSE;
- }
-
- SkAutoLockColors alc0(ct0);
- SkAutoLockColors alc1(ct1);
- const size_t size = ct0->count() * sizeof(SkPMColor);
- if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
- return JNI_FALSE;
- }
- }
-
- // now compare each scanline. We can't do the entire buffer at once,
- // since we don't care about the pixel values that might extend beyond
- // the width (since the scanline might be larger than the logical width)
- const int h = bm0->height();
- const size_t size = bm0->width() * bm0->bytesPerPixel();
- for (int y = 0; y < h; y++) {
- if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
- return JNI_FALSE;
- }
- }
- return JNI_TRUE;
-}
-
-static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->lockPixels();
- bitmap->unlockPixels();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapMethods[] = {
- { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_creator },
- { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copy },
- { "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
- { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure },
- { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
- (void*)Bitmap_compress },
- { "nativeErase", "(JI)V", (void*)Bitmap_erase },
- { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
- { "nativeConfig", "(J)I", (void*)Bitmap_config },
- { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
- { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
- { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
- { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
- { "nativeCreateFromParcel",
- "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
- (void*)Bitmap_createFromParcel },
- { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
- (void*)Bitmap_writeToParcel },
- { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
- (void*)Bitmap_extractAlpha },
- { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
- { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel },
- { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
- { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel },
- { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
- { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsToBuffer },
- { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsFromBuffer },
- { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
- { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
-};
-
-#define kClassPathName "android/graphics/Bitmap"
-
-int register_android_graphics_Bitmap(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
- gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
-}
+ return NULL; + } + return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), + getPremulBitmapCreateFlags(isMutable), NULL, NULL); +} + +static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); +#ifdef USE_OPENGL_RENDERER + if (android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap); + return; + } +#endif // USE_OPENGL_RENDERER + delete bitmap; +} + +static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); +#ifdef USE_OPENGL_RENDERER + if (android::uirenderer::Caches::hasInstance()) { + bool result; + result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap); + return result ? JNI_TRUE : JNI_FALSE; + } +#endif // USE_OPENGL_RENDERER + bitmap->setPixels(NULL, NULL); + return JNI_TRUE; +} + +static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, + jint width, jint height, jint configHandle, jint allocSize) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle); + if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) { + // done in native as there's no way to get BytesPerPixel in Java + doThrowIAE(env, "Bitmap not large enough to support new configuration"); + return; + } + SkPixelRef* ref = bitmap->pixelRef(); + SkSafeRef(ref); + bitmap->setConfig(config, width, height); + bitmap->setPixelRef(ref); + + // notifyPixelsChanged will increment the generation ID even though the actual pixel data + // hasn't been touched. This signals the renderer that the bitmap (including width, height, + // and config) has changed. + ref->notifyPixelsChanged(); + SkSafeUnref(ref); +} + +// These must match the int values in Bitmap.java +enum JavaEncodeFormat { + kJPEG_JavaEncodeFormat = 0, + kPNG_JavaEncodeFormat = 1, + kWEBP_JavaEncodeFormat = 2 +}; + +static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, + jint format, jint quality, + jobject jstream, jbyteArray jstorage) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkImageEncoder::Type fm; + + switch (format) { + case kJPEG_JavaEncodeFormat: + fm = SkImageEncoder::kJPEG_Type; + break; + case kPNG_JavaEncodeFormat: + fm = SkImageEncoder::kPNG_Type; + break; + case kWEBP_JavaEncodeFormat: + fm = SkImageEncoder::kWEBP_Type; + break; + default: + return JNI_FALSE; + } + + bool success = false; + if (NULL != bitmap) { + SkAutoLockPixels alp(*bitmap); + + if (NULL == bitmap->getPixels()) { + return JNI_FALSE; + } + + SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); + if (NULL == strm) { + return JNI_FALSE; + } + + SkImageEncoder* encoder = SkImageEncoder::Create(fm); + if (NULL != encoder) { + success = encoder->encodeStream(strm, *bitmap, quality); + delete encoder; + } + delete strm; + } + return success ? JNI_TRUE : JNI_FALSE; +} + +static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + bitmap->eraseColor(color); +} + +static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return static_cast<jint>(bitmap->rowBytes()); +} + +static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return static_cast<jint>(bitmap->config()); +} + +static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return static_cast<jint>(bitmap->getGenerationID()); +} + +static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE; +} + +static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, + jboolean hasAlpha, jboolean isPremul) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + if (!hasAlpha) { + bitmap->setAlphaType(kOpaque_SkAlphaType); + } else if (isPremul) { + bitmap->setAlphaType(kPremul_SkAlphaType); + } else { + bitmap->setAlphaType(kUnpremul_SkAlphaType); + } +} + +static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; +} + +static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, + jboolean hasMipMap) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + bitmap->setHasHardwareMipMap(hasMipMap); +} + +/////////////////////////////////////////////////////////////////////////////// + +static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { + if (parcel == NULL) { + SkDebugf("-------- unparcel parcel is NULL\n"); + return NULL; + } + + android::Parcel* p = android::parcelForJavaObject(env, parcel); + + const bool isMutable = p->readInt32() != 0; + const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); + const int width = p->readInt32(); + const int height = p->readInt32(); + const int rowBytes = p->readInt32(); + const int density = p->readInt32(); + + if (SkBitmap::kARGB_8888_Config != config && + SkBitmap::kRGB_565_Config != config && + SkBitmap::kARGB_4444_Config != config && + SkBitmap::kIndex8_Config != config && + SkBitmap::kA8_Config != config) { + SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); + return NULL; + } + + SkBitmap* bitmap = new SkBitmap; + + bitmap->setConfig(config, width, height, rowBytes); + + SkColorTable* ctable = NULL; + if (config == SkBitmap::kIndex8_Config) { + int count = p->readInt32(); + if (count > 0) { + size_t size = count * sizeof(SkPMColor); + const SkPMColor* src = (const SkPMColor*)p->readInplace(size); + ctable = new SkColorTable(src, count); + } + } + + jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); + if (NULL == buffer) { + SkSafeUnref(ctable); + delete bitmap; + return NULL; + } + + SkSafeUnref(ctable); + + size_t size = bitmap->getSize(); + + android::Parcel::ReadableBlob blob; + android::status_t status = p->readBlob(size, &blob); + if (status) { + doThrowRE(env, "Could not read bitmap from parcel blob."); + delete bitmap; + return NULL; + } + + bitmap->lockPixels(); + memcpy(bitmap->getPixels(), blob.data(), size); + bitmap->unlockPixels(); + + blob.release(); + + return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable), + NULL, NULL, density); +} + +static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, + jlong bitmapHandle, + jboolean isMutable, jint density, + jobject parcel) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + if (parcel == NULL) { + SkDebugf("------- writeToParcel null parcel\n"); + return JNI_FALSE; + } + + android::Parcel* p = android::parcelForJavaObject(env, parcel); + + p->writeInt32(isMutable); + p->writeInt32(bitmap->config()); + p->writeInt32(bitmap->width()); + p->writeInt32(bitmap->height()); + p->writeInt32(bitmap->rowBytes()); + p->writeInt32(density); + + if (bitmap->config() == SkBitmap::kIndex8_Config) { + SkColorTable* ctable = bitmap->getColorTable(); + if (ctable != NULL) { + int count = ctable->count(); + p->writeInt32(count); + memcpy(p->writeInplace(count * sizeof(SkPMColor)), + ctable->lockColors(), count * sizeof(SkPMColor)); + ctable->unlockColors(); + } else { + p->writeInt32(0); // indicate no ctable + } + } + + size_t size = bitmap->getSize(); + + android::Parcel::WritableBlob blob; + android::status_t status = p->writeBlob(size, &blob); + if (status) { + doThrowRE(env, "Could not write bitmap to parcel blob."); + return JNI_FALSE; + } + + bitmap->lockPixels(); + const void* pSrc = bitmap->getPixels(); + if (pSrc == NULL) { + memset(blob.data(), 0, size); + } else { + memcpy(blob.data(), pSrc, size); + } + bitmap->unlockPixels(); + + blob.release(); + return JNI_TRUE; +} + +static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, + jlong srcHandle, jlong paintHandle, + jintArray offsetXY) { + const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + SkIPoint offset; + SkBitmap* dst = new SkBitmap; + JavaPixelAllocator allocator(env); + + src->extractAlpha(dst, paint, &allocator, &offset); + // If Skia can't allocate pixels for destination bitmap, it resets + // it, that is set its pixels buffer to NULL, and zero width and height. + if (dst->getPixels() == NULL && src->getPixels() != NULL) { + delete dst; + doThrowOOME(env, "failed to allocate pixels for alpha"); + return NULL; + } + if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { + int* array = env->GetIntArrayElements(offsetXY, NULL); + array[0] = offset.fX; + array[1] = offset.fY; + env->ReleaseIntArrayElements(offsetXY, array, 0); + } + + return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), + getPremulBitmapCreateFlags(true), NULL, NULL); +} + +/////////////////////////////////////////////////////////////////////////////// + +static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, + jint x, jint y, jboolean isPremultiplied) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkAutoLockPixels alp(*bitmap); + + ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied); + if (NULL == proc) { + return 0; + } + const void* src = bitmap->getAddr(x, y); + if (NULL == src) { + return 0; + } + + SkColor dst[1]; + proc(dst, src, 1, bitmap->getColorTable()); + return static_cast<jint>(dst[0]); +} + +static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, + jintArray pixelArray, jint offset, jint stride, + jint x, jint y, jint width, jint height, jboolean isPremultiplied) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkAutoLockPixels alp(*bitmap); + + ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied); + if (NULL == proc) { + return; + } + const void* src = bitmap->getAddr(x, y); + if (NULL == src) { + return; + } + + SkColorTable* ctable = bitmap->getColorTable(); + jint* dst = env->GetIntArrayElements(pixelArray, NULL); + SkColor* d = (SkColor*)dst + offset; + while (--height >= 0) { + proc(d, src, width, ctable); + d += stride; + src = (void*)((const char*)src + bitmap->rowBytes()); + } + env->ReleaseIntArrayElements(pixelArray, dst, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, + jint x, jint y, jint colorHandle, jboolean isPremultiplied) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkColor color = static_cast<SkColor>(colorHandle); + SkAutoLockPixels alp(*bitmap); + if (NULL == bitmap->getPixels()) { + return; + } + + FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied); + if (NULL == proc) { + return; + } + + proc(bitmap->getAddr(x, y), &color, 1, x, y); + bitmap->notifyPixelsChanged(); +} + +static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, + jintArray pixelArray, jint offset, jint stride, + jint x, jint y, jint width, jint height, jboolean isPremultiplied) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + GraphicsJNI::SetPixels(env, pixelArray, offset, stride, + x, y, width, height, *bitmap, isPremultiplied); +} + +static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, + jlong bitmapHandle, jobject jbuffer) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkAutoLockPixels alp(*bitmap); + const void* src = bitmap->getPixels(); + + if (NULL != src) { + android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); + + // the java side has already checked that buffer is large enough + memcpy(abp.pointer(), src, bitmap->getSize()); + } +} + +static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, + jlong bitmapHandle, jobject jbuffer) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkAutoLockPixels alp(*bitmap); + void* dst = bitmap->getPixels(); + + if (NULL != dst) { + android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); + // the java side has already checked that buffer is large enough + memcpy(dst, abp.pointer(), bitmap->getSize()); + bitmap->notifyPixelsChanged(); + } +} + +static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, + jlong bm1Handle) { + const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle); + const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle); + if (bm0->width() != bm1->width() || + bm0->height() != bm1->height() || + bm0->config() != bm1->config()) { + return JNI_FALSE; + } + + SkAutoLockPixels alp0(*bm0); + SkAutoLockPixels alp1(*bm1); + + // if we can't load the pixels, return false + if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) { + return JNI_FALSE; + } + + if (bm0->config() == SkBitmap::kIndex8_Config) { + SkColorTable* ct0 = bm0->getColorTable(); + SkColorTable* ct1 = bm1->getColorTable(); + if (NULL == ct0 || NULL == ct1) { + return JNI_FALSE; + } + if (ct0->count() != ct1->count()) { + return JNI_FALSE; + } + + SkAutoLockColors alc0(ct0); + SkAutoLockColors alc1(ct1); + const size_t size = ct0->count() * sizeof(SkPMColor); + if (memcmp(alc0.colors(), alc1.colors(), size) != 0) { + return JNI_FALSE; + } + } + + // now compare each scanline. We can't do the entire buffer at once, + // since we don't care about the pixel values that might extend beyond + // the width (since the scanline might be larger than the logical width) + const int h = bm0->height(); + const size_t size = bm0->width() * bm0->bytesPerPixel(); + for (int y = 0; y < h; y++) { + if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) { + return JNI_FALSE; + } + } + return JNI_TRUE; +} + +static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + bitmap->lockPixels(); + bitmap->unlockPixels(); +} + +/////////////////////////////////////////////////////////////////////////////// + +#include <android_runtime/AndroidRuntime.h> + +static JNINativeMethod gBitmapMethods[] = { + { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", + (void*)Bitmap_creator }, + { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", + (void*)Bitmap_copy }, + { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, + { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, + { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure }, + { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", + (void*)Bitmap_compress }, + { "nativeErase", "(JI)V", (void*)Bitmap_erase }, + { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, + { "nativeConfig", "(J)I", (void*)Bitmap_config }, + { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, + { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied}, + { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, + { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, + { "nativeCreateFromParcel", + "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", + (void*)Bitmap_createFromParcel }, + { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", + (void*)Bitmap_writeToParcel }, + { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", + (void*)Bitmap_extractAlpha }, + { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, + { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel }, + { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels }, + { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel }, + { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels }, + { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", + (void*)Bitmap_copyPixelsToBuffer }, + { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", + (void*)Bitmap_copyPixelsFromBuffer }, + { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, + { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, +}; + +#define kClassPathName "android/graphics/Bitmap" + +int register_android_graphics_Bitmap(JNIEnv* env) +{ + return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, + gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); +} diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp index 70e2db54e889..cfa9cd83488a 100644 --- a/core/jni/android/graphics/CanvasProperty.cpp +++ b/core/jni/android/graphics/CanvasProperty.cpp @@ -18,7 +18,7 @@ #include "GraphicsJNI.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/VirtualLightRefBase.h> +#include <utils/RefBase.h> #include <CanvasProperty.h> namespace android { @@ -27,22 +27,13 @@ using namespace uirenderer; #ifdef USE_OPENGL_RENDERER -static jlong incRef(VirtualLightRefBase* ptr) { - ptr->incStrong(0); - return reinterpret_cast<jlong>(ptr); -} - static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) { - return incRef(new CanvasPropertyPrimitive(initialValue)); + return reinterpret_cast<jlong>(new CanvasPropertyPrimitive(initialValue)); } static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) { const SkPaint* paint = reinterpret_cast<const SkPaint*>(paintPtr); - return incRef(new CanvasPropertyPaint(*paint)); -} - -static void unref(JNIEnv* env, jobject clazz, jlong containerPtr) { - reinterpret_cast<VirtualLightRefBase*>(containerPtr)->decStrong(0); + return reinterpret_cast<jlong>(new CanvasPropertyPaint(*paint)); } #endif @@ -57,7 +48,6 @@ static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER { "nCreateFloat", "(F)J", (void*) createFloat }, { "nCreatePaint", "(J)J", (void*) createPaint }, - { "nUnref", "(J)V", (void*) unref }, #endif }; diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index 3be013b6df3c..4787d28847e3 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -101,7 +101,6 @@ static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis, RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw); BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue); - animator->incStrong(0); animator->setListener(new AnimationListenerBridge(env, weakThis)); return reinterpret_cast<jlong>( animator ); } @@ -111,7 +110,6 @@ static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz, RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw); CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr); BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue); - animator->incStrong(0); animator->setListener(new AnimationListenerBridge(env, weakThis)); return reinterpret_cast<jlong>( animator ); } @@ -124,7 +122,6 @@ static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz, CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw); BaseAnimator* animator = new CanvasPropertyPaintAnimator( canvasProperty, paintField, deltaType, deltaValue); - animator->incStrong(0); animator->setListener(new AnimationListenerBridge(env, weakThis)); return reinterpret_cast<jlong>( animator ); } @@ -135,11 +132,6 @@ static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint dura animator->setDuration(duration); } -static void unref(JNIEnv* env, jobject clazz, jlong objPtr) { - VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr); - obj->decStrong(0); -} - #endif // ---------------------------------------------------------------------------- @@ -154,7 +146,6 @@ static JNINativeMethod gMethods[] = { { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator }, { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator }, { "nSetDuration", "(JI)V", (void*) setDuration }, - { "nUnref", "(J)V", (void*) unref }, #endif }; diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp new file mode 100644 index 000000000000..ce6f207352a8 --- /dev/null +++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#include "jni.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> + +namespace android { + +static void incStrong(JNIEnv* env, jobject clazz, jlong objPtr) { + VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr); + obj->incStrong(0); +} + +static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) { + VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr); + obj->decStrong(0); +} + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr"; + +static JNINativeMethod gMethods[] = { + { "nIncStrong", "(J)V", (void*) incStrong }, + { "nDecStrong", "(J)V", (void*) decStrong }, +}; + +int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + + +} // namespace android diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 28e75e65b41b..7a6832ec71e6 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6605,4 +6605,8 @@ <attr name="layout_gravity" /> </declare-styleable> + <!-- Used as a filter array on the theme to pull out only the EdgeEffect-relevant bits. --> + <declare-styleable name="EdgeEffect"> + <attr name="colorPrimaryLight" /> + </declare-styleable> </resources> diff --git a/docs/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd index 5a96ba172b4b..e2326eca432b 100644 --- a/docs/html/guide/topics/resources/string-resource.jd +++ b/docs/html/guide/topics/resources/string-resource.jd @@ -20,9 +20,6 @@ your application with strings:</p> information about styling and formatting strings, see the section about <a href="#FormattingAndStyling">Formatting and Styling</a>.</p> - - - <h2 id="String">String</h2> <p>A single string that can be referenced from the application or from other resource files (such @@ -433,7 +430,7 @@ java.lang.Object...)">format</a>(res.getString(R.string.welcome_messages), usern -<h3>Styling with HTML markup</h3> +<h3 id="StylingWithHTML">Styling with HTML markup</h3> <p>You can add styling to your strings with HTML markup. For example:</p> <pre> @@ -497,5 +494,107 @@ java.lang.Object...)">format</a>(res.getString(R.string.welcome_messages), escap CharSequence styledText = Html.fromHtml(text); </pre> +<h2 id="StylingWithSpannables">Styling with Spannables</h2> +<p> +A {@link android.text.Spannable} is a text object that you can style with +typeface properties such as color and font weight. You use +{@link android.text.SpannableStringBuilder} to build +your text and then apply styles defined in the {@link android.text.style} +package to the text. +</p> + +<p>You can use the following helper methods to set up much of the work +of creating spannable text:</p> + +<pre style="pretty-print"> +/** + * Returns a CharSequence that concatenates the specified array of CharSequence + * objects and then applies a list of zero or more tags to the entire range. + * + * @param content an array of character sequences to apply a style to + * @param tags the styled span objects to apply to the content + * such as android.text.style.StyleSpan + * + */ +private static CharSequence apply(CharSequence[] content, Object... tags) { + SpannableStringBuilder text = new SpannableStringBuilder(); + openTags(text, tags); + for (CharSequence item : content) { + text.append(item); + } + closeTags(text, tags); + return text; +} + +/** + * Iterates over an array of tags and applies them to the beginning of the specified + * Spannable object so that future text appended to the text will have the styling + * applied to it. Do not call this method directly. + */ +private static void openTags(Spannable text, Object[] tags) { + for (Object tag : tags) { + text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK); + } +} + +/** + * "Closes" the specified tags on a Spannable by updating the spans to be + * endpoint-exclusive so that future text appended to the end will not take + * on the same styling. Do not call this method directly. + */ +private static void closeTags(Spannable text, Object[] tags) { + int len = text.length(); + for (Object tag : tags) { + if (len > 0) { + text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + text.removeSpan(tag); + } + } +} +</pre> +<p> +The following <code>bold</code>, <code>italic</code>, and <code>color</code> +methods show you how to call the helper methods to apply +styles defined in the {@link android.text.style} package. You +can create similar methods to do other types of text styling. +</p> + +<pre style="pretty-print"> +/** + * Returns a CharSequence that applies boldface to the concatenation + * of the specified CharSequence objects. + */ +public static CharSequence bold(CharSequence... content) { + return apply(content, new StyleSpan(Typeface.BOLD)); +} + +/** + * Returns a CharSequence that applies italics to the concatenation + * of the specified CharSequence objects. + */ +public static CharSequence italic(CharSequence... content) { + return apply(content, new StyleSpan(Typeface.ITALIC)); +} + +/** + * Returns a CharSequence that applies a foreground color to the + * concatenation of the specified CharSequence objects. + */ +public static CharSequence color(int color, CharSequence... content) { + return apply(content, new ForegroundColorSpan(color)); +} +</pre> +<p> +Here's an example of how to chain these methods to create a character sequence +with different types of styling applied to individual words: +</p> + +<pre style="pretty-print"> +// Create an italic "hello, " a red "world", +// and bold the entire sequence. +CharSequence text = bold(italic(res.getString(R.string.hello)), + color(Color.RED, res.getString(R.string.world))); +</pre>
\ No newline at end of file diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd index 3b1292e5c7dc..59c2269a4f40 100644 --- a/docs/html/guide/topics/ui/notifiers/notifications.jd +++ b/docs/html/guide/topics/ui/notifiers/notifications.jd @@ -16,6 +16,7 @@ page.title=Notifications <li><a href="#Required">Required notification contents</a></li> <li><a href="#Optional">Optional notification contents and settings</a></li> <li><a href="#Actions">Notification actions</a></li> + <li><a href="#Priority">Notification priority</a></li> <li><a href="#SimpleNotification">Creating a simple notification</a></li> <li><a href="#ApplyStyle">Applying a big view style to a notification</a></li> <li><a href="#Compatibility">Handling compatibility</a></li> @@ -290,6 +291,26 @@ page.title=Notifications {@link android.support.v4.app.NotificationCompat.Builder}. </p> <!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Priority">Notification priority</h3> +<p> + If you wish, you can set the priority of a notification. The priority acts + as a hint to the device UI about how the notification should be displayed. + To set a notification's priority, call {@link + android.support.v4.app.NotificationCompat.Builder#setPriority(int) + NotificationCompat.Builder.setPriority()} and pass in one of the {@link + android.support.v4.app.NotificationCompat} priority constants. There are + five priority levels, ranging from {@link + android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link + android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the + priority defaults to {@link + android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0). +</p> +<p> For information about setting an appropriate priority level, see "Correctly + set and manage notification priority" in the <a + href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design + guide. +</p> +<!-- ------------------------------------------------------------------------------------------ --> <h3 id="SimpleNotification">Creating a simple notification</h3> <p> The following snippet illustrates a simple notification that specifies an activity to open when diff --git a/docs/html/wear/images/notif_summary_framed.png b/docs/html/wear/images/notif_summary_framed.png Binary files differnew file mode 100644 index 000000000000..17b17039f7c4 --- /dev/null +++ b/docs/html/wear/images/notif_summary_framed.png diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd index 7f955f67634e..a2d34ce9b847 100644 --- a/docs/html/wear/notifications/stacks.jd +++ b/docs/html/wear/notifications/stacks.jd @@ -2,8 +2,8 @@ page.title=Stacking Notifications @jd:body -<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" /> -<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" /> +<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" /> +<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" /> <p>When creating notifications for a handheld device, you should always aggregate similar notifications into a single summary notification. For example, if your app creates notifications @@ -29,20 +29,44 @@ Wear</a>.</p> <p>To create a stack, call <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)"> -<code>setGroup()</code></a> for each notification you want in the stack, passing the same -group key. For example:</p> +<code>setGroup()</code></a> for each notification you want in the stack and specify a +group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p> <pre style="clear:right"> final static String GROUP_KEY_EMAILS = "group_key_emails"; +// Build the notification and pass this builder to WearableNotifications.Builder NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext) - .setContentTitle("New mail from " + sender) - .setContentText(subject) + .setContentTitle("New mail from " + sender1) + .setContentText(subject1) .setSmallIcon(R.drawable.new_mail); -Notification notif = new WearableNotifications.Builder(builder) +Notification notif1 = new WearableNotifications.Builder(builder) .setGroup(GROUP_KEY_EMAILS) .build(); + +// Issue the notification +NotificationManagerCompat notificationManager = + NotificationManagerCompat.from(this); +notificationManager.notify(notificationId1, notif); +</pre> + +<p>Later on, when you create another notification, specify +the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears +in the same stack as the previous notification, instead of as a new card:</p> + +<pre style="clear:right"> +builder = new NotificationCompat.Builder(mContext) + .setContentTitle("New mail from " + sender2) + .setContentText(subject2) + .setSmallIcon(R.drawable.new_mail); + +// Use the same group as the previous notification +Notification notif2 = new WearableNotifications.Builder(builder) + .setGroup(GROUP_KEY_EMAILS) + .build(); + +notificationManager.notify(notificationId2, notif); </pre> <p>By default, notifications appear in the order in which you added them, with the most recent @@ -54,19 +78,55 @@ href="{@docRoot}reference/android/preview/support/wearable/notifications/Wearabl <h2 id="AddSummary">Add a Summary Notification</h2> +<img src="{@docRoot}wear/images/notif_summary_framed.png" height="242" width="330" style="float:right;margin:0 0 20px 40px" alt="" /> + <p>It's important that you still provide a summary notification that appears on handheld devices. So in addition to adding each unique notification to the same stack group, also add a summary notification, but set its order position to be <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p> -<pre> -Notification summaryNotification = new WearableNotifications.Builder(builder) - .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY) - .build(); -</pre> +<p>This notification does not appear in your stack of notifications on the wearable, but +appears as the only notification on the handheld device.</p> -<p>This notification will not appear in your stack of notifications on the wearable, but -appears as the only notification on the handheld device. +<pre style="clear:right"> +Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), + R.drawable.ic_large_icon); + +builder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_small_icon) + .setLargeIcon(largeIcon); + +// Use the same group key and pass this builder to InboxStyle notification +WearableNotifications.Builder wearableBuilder = new WearableNotifications + .Builder(builder) + .setGroup(GROUP_KEY_EMAILS, + WearableNotifications.GROUP_ORDER_SUMMARY); + +// Build the final notification to show on the handset +Notification summaryNotification = new NotificationCompat.InboxStyle( + wearableBuilder.getCompatBuilder()) + .addLine("Alex Faaborg Check this out") + .addLine("Jeff Chang Launch Party") + .setBigContentTitle("2 new messages") + .setSummaryText("johndoe@gmail.com") + .build(); + +notificationManager.notify(notificationId3, summaryNotification); +</pre> +<p> +This notification uses {@link android.support.v4.app.NotificationCompat.InboxStyle}, +which gives you an easy way to create notifications for email or messaging apps. +You can use this style, another one defined in {@link android.support.v4.app.NotificationCompat}, +or no style for the summary notification. +</p> + +<p class="note"><b>Tip:</b> +To style the text like in the example screenshot, see +<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithHTML">Styling +with HTML markup</a> and +<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithSpannables">Styling +with Spannables</a>. +</p> </body> -</html> +</html>
\ No newline at end of file diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java index 99ea9b1c979d..be860601e8af 100644 --- a/graphics/java/android/graphics/CanvasProperty.java +++ b/graphics/java/android/graphics/CanvasProperty.java @@ -16,12 +16,15 @@ package android.graphics; +import com.android.internal.util.VirtualRefBasePtr; + /** * TODO: Make public? * @hide */ public final class CanvasProperty<T> { - private long mNativeContainer; + + private VirtualRefBasePtr mProperty; public static CanvasProperty<Float> createFloat(float initialValue) { return new CanvasProperty<Float>(nCreateFloat(initialValue)); @@ -32,25 +35,14 @@ public final class CanvasProperty<T> { } private CanvasProperty(long nativeContainer) { - mNativeContainer = nativeContainer; + mProperty = new VirtualRefBasePtr(nativeContainer); } /** @hide */ public long getNativeContainer() { - return mNativeContainer; - } - - @Override - protected void finalize() throws Throwable { - try { - nUnref(mNativeContainer); - mNativeContainer = 0; - } finally { - super.finalize(); - } + return mProperty.get(); } private static native long nCreateFloat(float initialValue); private static native long nCreatePaint(long initialValuePaintPtr); - private static native void nUnref(long ptr); } diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 0b074ccd0922..86fc7c325473 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -17,13 +17,13 @@ #define ANIMATOR_H #include <cutils/compiler.h> +#include <utils/RefBase.h> #include <utils/StrongPointer.h> #include "CanvasProperty.h" #include "Interpolator.h" #include "TreeInfo.h" #include "utils/Macros.h" -#include "utils/VirtualLightRefBase.h" namespace android { namespace uirenderer { diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h index 2e1d17650b36..6074394d0720 100644 --- a/libs/hwui/CanvasProperty.h +++ b/libs/hwui/CanvasProperty.h @@ -16,8 +16,9 @@ #ifndef CANVASPROPERTY_H #define CANVASPROPERTY_H +#include <utils/RefBase.h> + #include "utils/Macros.h" -#include "utils/VirtualLightRefBase.h" #include <SkPaint.h> diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index eaeb7721f1ae..b2ead5bda170 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -41,7 +41,6 @@ #include "Matrix.h" #include "DeferredDisplayList.h" #include "RenderProperties.h" -#include "utils/VirtualLightRefBase.h" class SkBitmap; class SkPaint; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 159903ca790d..bc62ee19f6e5 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -45,7 +45,6 @@ #include "DisplayList.h" #include "RenderProperties.h" #include "TreeInfo.h" -#include "utils/VirtualLightRefBase.h" class SkBitmap; class SkPaint; diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index d22cb8ad6624..08e9a1a876a3 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -214,18 +214,28 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* int dstY = y + glyph->mBitmapTop; CacheTexture* cacheTexture = glyph->mCacheTexture; + PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); + uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat()); uint32_t cacheWidth = cacheTexture->getWidth(); - uint32_t startY = glyph->mStartY * cacheWidth; - uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth); + uint32_t srcStride = formatSize * cacheWidth; + uint32_t startY = glyph->mStartY * srcStride; + uint32_t endY = startY + (glyph->mBitmapHeight * srcStride); - PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); const uint8_t* cacheBuffer = pixelBuffer->map(); for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY; - cacheY += cacheWidth, bitmapY += bitmapWidth) { - memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + cacheY += srcStride, bitmapY += bitmapWidth) { + + if (formatSize == 1) { + memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + } else { + for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) { + bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize]; + } + } } + } void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/VirtualLightRefBase.h deleted file mode 100644 index b545aabac802..000000000000 --- a/libs/hwui/utils/VirtualLightRefBase.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ -#ifndef VIRTUALLIGHTREFBASE_H -#define VIRTUALLIGHTREFBASE_H - -#include <utils/RefBase.h> - -namespace android { -namespace uirenderer { - -// This is a wrapper around LightRefBase that simply enforces a virtual -// destructor to eliminate the template requirement of LightRefBase -class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> { -public: - virtual ~VirtualLightRefBase() {} -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif /* VIRTUALLIGHTREFBASE_H */ diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index b2b2bd85f783..9069a55404ee 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -436,6 +436,8 @@ public class DirectoryFragment extends Fragment { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.mode_directory, menu); + mode.setTitle(getResources() + .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount())); return true; } diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml index 546ddd4fb3e8..0d943ed4303f 100644 --- a/packages/Keyguard/res/layout/keyguard_status_view.xml +++ b/packages/Keyguard/res/layout/keyguard_status_view.xml @@ -28,7 +28,7 @@ androidprv:layout_maxWidth="@dimen/keyguard_security_width" androidprv:layout_maxHeight="@dimen/keyguard_security_height" android:gravity="center_horizontal|top" - android:layout_marginTop="32dp" + android:layout_marginTop="48dp" android:layout_marginBottom="32dp" android:contentDescription="@string/keyguard_accessibility_status"> <LinearLayout diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png Binary files differdeleted file mode 100644 index 3b1944db7af2..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png Binary files differdeleted file mode 100644 index 693abf54bdd2..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png Binary files differdeleted file mode 100644 index 807f607e8b20..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png Binary files differdeleted file mode 100644 index 15340d37d9c6..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png Binary files differdeleted file mode 100644 index e562bc28749c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png Binary files differdeleted file mode 100644 index e3cc9b0307f6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png Binary files differdeleted file mode 100644 index a2e8fe1b2d25..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png Binary files differdeleted file mode 100644 index e15981adfbf6..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml new file mode 100644 index 000000000000..5c38a22221ac --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > +<size +android:width="24dp" +android:height="24dp"/> + + <viewport android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + +<group> +<path + android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" + android:fill="#ffffffff" + /> +</group> +</vector> diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml index c5ba18b584f5..09d0d7d443a1 100644 --- a/packages/SystemUI/res/drawable/notification_header_bg.xml +++ b/packages/SystemUI/res/drawable/notification_header_bg.xml @@ -18,13 +18,13 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape> - <solid android:color="#ff54656e" /> + <solid android:color="@color/background_color_1_press" /> <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> </shape> </item> <item> <shape> - <solid android:color="#ff374248" /> + <solid android:color="@color/background_color_1" /> <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> </shape> </item> diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml index 7cf317565145..c015cc84a910 100644 --- a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml +++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project +<!-- 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. @@ -13,11 +13,23 @@ See the License for the specific language governing permissions and limitations under the License. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:versionCode="1" > -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/ic_notify_quicksettings_normal" /> - <item - android:drawable="@drawable/ic_notify_quicksettings_normal" /> -</selector> + <size + android:height="16dp" + android:width="16dp" /> + <viewport + android:viewportHeight="100" + android:viewportWidth="100" /> + + <group> + <path + android:name="x" + android:pathData="M0,0L100,100M0,100L100,0z" + android:stroke="@color/recents_task_bar_dark_dismiss_color" + android:strokeWidth="8.0" + android:strokeLineCap="square" /> + </group> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_notify_settings.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml index 9303ca4c3d60..9c93db95e5c5 100644 --- a/packages/SystemUI/res/drawable/ic_notify_settings.xml +++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project +<!-- 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. @@ -13,11 +13,23 @@ See the License for the specific language governing permissions and limitations under the License. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:versionCode="1" > -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/ic_notify_settings_normal" /> - <item - android:drawable="@drawable/ic_notify_settings_normal" /> -</selector> + <size + android:height="16dp" + android:width="16dp" /> + <viewport + android:viewportHeight="100" + android:viewportWidth="100" /> + + <group> + <path + android:name="x" + android:pathData="M0,0L100,100M0,100L100,0z" + android:stroke="@color/recents_task_bar_light_dismiss_color" + android:strokeWidth="8.0" + android:strokeLineCap="square" /> + </group> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml index e4954e781bbd..7d9cfa1c49f0 100644 --- a/packages/SystemUI/res/layout/heads_up.xml +++ b/packages/SystemUI/res/layout/heads_up.xml @@ -20,7 +20,7 @@ <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:layout_width="match_parent" android:id="@+id/content_holder" android:background="@drawable/notification_panel_bg" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml index b7df51d3777b..1efda8c54065 100644 --- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml @@ -29,7 +29,7 @@ <com.android.systemui.settings.ToggleSlider android:id="@+id/brightness_slider" android:layout_width="0dp" - android:layout_height="40dp" + android:layout_height="44dp" android:layout_gravity="center_vertical" android:layout_weight="1" systemui:text="@string/status_bar_settings_auto_brightness_label" /> diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index f7df18eb322f..bda6431fc7a9 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -63,6 +63,13 @@ android:maxLines="2" android:ellipsize="marquee" android:fadingEdge="horizontal" /> + <ImageView + android:id="@+id/dismiss_task" + android:layout_width="@dimen/recents_task_view_application_icon_size" + android:layout_height="@dimen/recents_task_view_application_icon_size" + android:layout_gravity="center_vertical|end" + android:padding="23dp" + android:src="@drawable/recents_dismiss_dark" /> </com.android.systemui.recents.views.TaskBarView> </com.android.systemui.recents.views.TaskView> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 730862622de7..f045da47a2cb 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -22,7 +22,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/notification_panel" - android:layout_width="0dp" + android:layout_width="match_parent" android:layout_height="match_parent" > @@ -34,15 +34,6 @@ android:layout_gravity="bottom" /> - <com.android.keyguard.CarrierText - android:id="@+id/keyguard_carrier_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="2dp" - android:layout_marginLeft="8dp" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceMedium" /> - <include layout="@layout/keyguard_status_view" android:layout_height="wrap_content" @@ -59,9 +50,8 @@ /> <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer + style="@style/NotificationsQuickSettings" android:id="@+id/notification_container_parent" - android:layout_width="match_parent" - android:layout_height="wrap_content" android:clipToPadding="false" android:clipChildren="false"> @@ -98,13 +88,7 @@ </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer> - - <include layout="@layout/status_bar_expanded_header" - android:layout_width="match_parent" - android:layout_height="@dimen/status_bar_header_height" - android:layout_marginLeft="@dimen/notification_side_padding" - android:layout_marginRight="@dimen/notification_side_padding" - /> + <include layout="@layout/status_bar_expanded_header" /> <include layout="@layout/keyguard_bottom_area" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 3759f826ac90..89fa988bc8a5 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -20,12 +20,12 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/header" - android:layout_width="match_parent" + style="@style/StatusBarHeader" android:layout_height="@dimen/status_bar_header_height" - android:orientation="horizontal" - android:gravity="center_vertical" + android:paddingStart="@dimen/notification_side_padding" + android:paddingEnd="@dimen/notification_side_padding" android:baselineAligned="false" - android:elevation="14dp" + android:elevation="10dp" > <View @@ -38,10 +38,12 @@ <RelativeLayout android:id="@+id/datetime" android:layout_width="wrap_content" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_gravity="start" - android:paddingStart="8dp" - android:paddingEnd="8dp" + android:paddingTop="16dp" + android:paddingBottom="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:background="@drawable/ic_notify_button_bg" android:enabled="false" > @@ -49,10 +51,9 @@ android:id="@+id/clock" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="8dp" android:singleLine="true" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock" - android:layout_centerVertical="true" + systemui:amPmStyle="normal" /> <com.android.systemui.statusbar.policy.DateView android:id="@+id/date" @@ -60,17 +61,49 @@ android:layout_height="wrap_content" android:singleLine="true" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" - android:layout_toEndOf="@id/clock" - android:layout_alignBaseline="@id/clock" + android:layout_below="@id/clock" /> </RelativeLayout> - <FrameLayout android:id="@+id/system_icons_container" + <com.android.keyguard.CarrierText + android:id="@+id/keyguard_carrier_text" android:layout_width="wrap_content" + android:layout_height="@dimen/status_bar_header_height_keyguard" + android:layout_marginLeft="8dp" + android:gravity="center_vertical" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" + android:layout_width="40dp" android:layout_height="@dimen/status_bar_header_height" android:layout_alignParentEnd="true" - android:layout_marginEnd="16dp" + android:background="@null" + android:scaleType="centerInside" + android:padding="6dp" /> + + <ImageButton android:id="@+id/settings_button" + style="@android:style/Widget.Quantum.Button.Borderless" + android:layout_toStartOf="@id/multi_user_switch" + android:layout_width="56dp" + android:layout_height="@dimen/status_bar_header_height" + android:src="@drawable/ic_settings_24dp" + android:contentDescription="@string/accessibility_desc_quick_settings"/> + + <FrameLayout android:id="@+id/system_icons_container" + android:layout_width="wrap_content" + android:layout_height="@dimen/status_bar_header_height" + android:layout_toStartOf="@id/multi_user_switch" + android:layout_marginEnd="4dp" + /> + + <include + layout="@layout/quick_settings_brightness_dialog" + android:id="@+id/brightness_container" + android:layout_width="match_parent" + /> + <TextView android:id="@+id/header_debug_info" android:visibility="invisible" diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml deleted file mode 100644 index f4d70331dd16..000000000000 --- a/packages/SystemUI/res/layout/status_bar_flip_button.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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 - --> - -<ImageView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/settings_button" - android:layout_width="50dp" - android:layout_height="50dp" - android:scaleType="center" - android:src="@drawable/ic_notify_quicksettings" - android:background="@drawable/ic_notify_button_bg" - android:contentDescription="@string/accessibility_desc_quick_settings"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml index e6d7c9302764..0e84762055ae 100644 --- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml +++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml @@ -28,6 +28,7 @@ android:layout_alignParentTop="true" android:layout_alignParentBottom="true" android:button="@null" + android:background="@*android:drawable/switch_track_quantum" /> <com.android.systemui.settings.ToggleSeekBar android:id="@+id/slider" diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index e95f3c3aa772..26616cd29756 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -35,9 +35,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/status_bar_expanded" - android:layout_width="@dimen/notification_panel_width" + android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_gravity="start|top" android:visibility="gone" /> </com.android.systemui.statusbar.phone.PanelHolder> diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml index bc56cf67e705..70c5042d07d8 100644 --- a/packages/SystemUI/res/layout/user_switcher_host.xml +++ b/packages/SystemUI/res/layout/user_switcher_host.xml @@ -22,7 +22,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#dd000000"> + android:background="#dd000000" + android:elevation="12dp"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index b7becac57010..d4a99866335c 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -18,4 +18,15 @@ <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer"> <item name="android:layout_width">480dp</item> </style> + + <style name="NotificationsQuickSettings"> + <item name="android:layout_width">@dimen/notification_panel_width</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_gravity">top|center_horizontal</item> + </style> + + <style name="StatusBarHeader"> + <item name="android:layout_width">@dimen/notification_panel_width</item> + <item name="android:layout_gravity">center_horizontal</item> + </style> </resources> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index f5674d296c2e..8fd120689b63 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -51,6 +51,13 @@ <enum name="end" value="1" /> </attr> </declare-styleable> + <declare-styleable name="Clock"> + <attr name="amPmStyle" format="enum"> + <enum name="normal" value="0" /> + <enum name="small" value="1" /> + <enum name="gone" value="2" /> + </attr> + </declare-styleable> <attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index c78ff8eec550..c1a4e26adc91 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -52,10 +52,18 @@ <!-- The default recents task bar background color. --> <color name="recents_task_bar_default_background_color">#e6444444</color> <!-- The default recents task bar text color. --> - <color name="recents_task_bar_default_text_color">#ffffffff</color> + <color name="recents_task_bar_default_text_color">#ffeeeeee</color> <!-- The recents task bar light text color to be drawn on top of dark backgrounds. --> - <color name="recents_task_bar_light_text_color">#ffffffff</color> + <color name="recents_task_bar_light_text_color">#ffeeeeee</color> <!-- The recents task bar dark text color to be drawn on top of light backgrounds. --> <color name="recents_task_bar_dark_text_color">#ff222222</color> + <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. --> + <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color> + <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. --> + <color name="recents_task_bar_dark_dismiss_color">#ff333333</color> + <!-- Our quantum color palette (deep teal) --> + <color name="primary_color">#ff7fcac3</color> + <color name="background_color_1">#ff384248</color> + <color name="background_color_1_press">#ff54656e</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index c0376f00ccd6..21eb41c6867f 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -119,7 +119,7 @@ <!-- The animation duration for animating in the info pane. --> <integer name="recents_animate_task_view_info_pane_duration">150</integer> <!-- The animation duration for animating the removal of a task view. --> - <integer name="recents_animate_task_view_remove_duration">150</integer> + <integer name="recents_animate_task_view_remove_duration">250</integer> <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. --> <integer name="recents_max_task_stack_view_dim">96</integer> <!-- Transposes the search bar layout in landscape --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 50df706383f2..ab3403057049 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -158,6 +158,9 @@ <!-- Height of the status bar header bar when expanded --> <dimen name="status_bar_header_height_expanded">144dp</dimen> + <!-- Height of the status bar header bar when on Keyguard --> + <dimen name="status_bar_header_height_keyguard">40dp</dimen> + <!-- Gravity for the notification panel --> <!-- 0x37 = fill_horizontal|top --> <integer name="notification_panel_layout_gravity">0x37</integer> @@ -196,9 +199,6 @@ <!-- Quick Settings CA Cert Warning tile geometry: gap between icon and text --> <dimen name="qs_cawarn_tile_margin_below_icon">3dp</dimen> - <!-- The width of the notification panel window: match_parent below sw600dp --> - <dimen name="notification_panel_width">-1dp</dimen> - <!-- used by DessertCase --> <dimen name="dessert_case_cell_size">192dp</dimen> @@ -224,7 +224,7 @@ <dimen name="recents_task_view_z_increment">5dp</dimen> <!-- The amount to translate when animating the removal of a task. --> - <dimen name="recents_task_view_remove_anim_translation_x">75dp</dimen> + <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen> <!-- The amount of space a user has to scroll to dismiss any info panes. --> <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen> @@ -243,7 +243,10 @@ <dimen name="top_stack_peek_amount">12dp</dimen> <!-- Space reserved for the cards behind the top card in the bottom stack --> - <dimen name="bottom_stack_peek_amount">18dp</dimen> + <dimen name="bottom_stack_peek_amount">12dp</dimen> + + <!-- The height of the area before the bottom stack in which the notifications slow down --> + <dimen name="bottom_stack_slow_down_length">12dp</dimen> <!-- The side padding of the notifications--> <dimen name="notification_side_padding">8dp</dimen> @@ -251,8 +254,11 @@ <!-- Z distance between notifications if they are in the stack --> <dimen name="z_distance_between_notifications">2dp</dimen> + <!-- The padding between the individual notification cards when dimmed. --> + <dimen name="notification_padding_dimmed">0dp</dimen> + <!-- The padding between the individual notification cards. --> - <dimen name="notification_padding">3dp</dimen> + <dimen name="notification_padding">4dp</dimen> <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) --> <dimen name="collapsed_stack_height">94dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 8ab646d2f766..4f5287054c3f 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -69,8 +69,7 @@ <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" /> <style name="TextAppearance.StatusBar.Expanded.Clock"> - <item name="android:textSize">32dp</item> - <item name="android:fontFamily">sans-serif-light</item> + <item name="android:textSize">18dp</item> <item name="android:textStyle">normal</item> <item name="android:textColor">#ffffff</item> </style> @@ -78,8 +77,7 @@ <style name="TextAppearance.StatusBar.Expanded.Date"> <item name="android:textSize">12dp</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">#cccccc</item> - <item name="android:textAllCaps">true</item> + <item name="android:textColor">#afb3b6</item> </style> <style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date"> @@ -138,6 +136,7 @@ <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:padding">16dp</item> + <item name="android:layout_alignParentBottom">true</item> </style> <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" /> @@ -169,6 +168,16 @@ <item name="android:textSize">14dp</item> </style> - <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" /> + <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault"> + <item name="android:colorPrimary">@color/primary_color</item> + </style> + <style name="NotificationsQuickSettings"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">match_parent</item> + </style> + + <style name="StatusBarHeader"> + <item name="android:layout_width">match_parent</item> + </style> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 3ef8316ca8e2..19a1b11cd468 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -255,15 +255,10 @@ public class AlternateRecentsComponent { /** Loads the first task thumbnail */ Bitmap loadFirstTaskThumbnail() { SystemServicesProxy ssp = mSystemServicesProxy; - List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, - UserHandle.CURRENT.getIdentifier()); - for (ActivityManager.RecentTaskInfo t : tasks) { - // Skip tasks in the home stack - if (ssp.isInHomeStack(t.persistentId)) { - return null; - } + List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1); - return ssp.getTaskThumbnail(t.persistentId); + for (ActivityManager.RunningTaskInfo t : tasks) { + return ssp.getTaskThumbnail(t.id); } return null; } @@ -286,17 +281,6 @@ public class AlternateRecentsComponent { return (tasks.size() > 1); } - /** Returns whether the base intent of the top task stack was launched with the flag - * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */ - boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) { - if (tasks.size() > 0) { - ActivityManager.RecentTaskInfo t = tasks.get(0); - Console.log(t.baseIntent.toString()); - return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; - } - return false; - } - /** Converts from the device rotation to the degree */ float getDegreesForRotation(int value) { switch (value) { @@ -416,16 +400,14 @@ public class AlternateRecentsComponent { } // Otherwise, Recents is not the front-most activity and we should animate into it. If - // the activity at the root of the top task stack is excluded from recents, or if that - // task stack is in the home stack, then we just do a simple transition. Otherwise, we - // animate to the rects defined by the Recents service, which can differ depending on the - // number of items in the list. + // the activity at the root of the top task stack in the home stack, then we just do a + // simple transition. Otherwise, we animate to the rects defined by the Recents service, + // which can differ depending on the number of items in the list. List<ActivityManager.RecentTaskInfo> recentTasks = - ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier()); + ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier()); Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect; - boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks); - boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents && + boolean useThumbnailTransition = !isTopTaskHome && hasValidTaskRects(); if (useThumbnailTransition) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java deleted file mode 100644 index 95ab8e83db75..000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.android.systemui.recents; - -import android.animation.TimeInterpolator; - -/** - * A pre-baked bezier-curved interpolator for quantum-paper transitions. - */ -public class BakedBezierInterpolator implements TimeInterpolator { - public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator(); - - /** - * Use the INSTANCE variable instead of instantiating. - */ - private BakedBezierInterpolator() { - super(); - } - - /** - * Lookup table values. - * Generated using a Bezier curve from (0,0) to (1,1) with control points: - * P0 (0,0) - * P1 (0.4, 0) - * P2 (0.2, 1.0) - * P3 (1.0, 1.0) - * - * Values sampled with x at regular intervals between 0 and 1. - */ - private static final float[] VALUES = new float[] { - 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f, - 0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f, - 0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f, - 0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f, - 0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f, - 0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f, - 0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f, - 0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f, - 0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f, - 0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f - }; - - private static final float STEP_SIZE = 1.0f / (VALUES.length - 1); - - @Override - public float getInterpolation(float input) { - if (input >= 1.0f) { - return 1.0f; - } - - if (input <= 0f) { - return 0f; - } - - int position = Math.min( - (int)(input * (VALUES.length - 1)), - VALUES.length - 2); - - float quantized = position * STEP_SIZE; - float difference = input - quantized; - float weight = difference / STEP_SIZE; - - return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]); - } - -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 1d6a76c47d3c..90998da26459 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -32,7 +32,7 @@ public class Constants { // Enables the use of theme colors as the task bar background public static final boolean EnableTaskBarThemeColors = true; // Enables the info pane on long-press - public static final boolean EnableInfoPane = true; + public static final boolean EnableInfoPane = false; // Enables the search bar layout public static final boolean EnableSearchLayout = true; // Enables the dynamic shadows behind each task diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 463cf748842c..9afc1cbc0f66 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -23,6 +23,8 @@ import android.content.res.Resources; import android.graphics.Rect; import android.util.DisplayMetrics; import android.util.TypedValue; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import com.android.systemui.R; @@ -42,6 +44,8 @@ public class RecentsConfiguration { public float animationPxMovementPerSecond; + public Interpolator defaultBezierInterpolator; + public int filteringCurrentViewsMinAnimDuration; public int filteringNewViewsMinAnimDuration; public int taskBarEnterAnimDuration; @@ -121,7 +125,6 @@ public class RecentsConfiguration { res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment); searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); - taskBarViewDefaultBackgroundColor = res.getColor(R.color.recents_task_bar_default_background_color); taskBarViewDefaultTextColor = @@ -131,6 +134,9 @@ public class RecentsConfiguration { taskBarViewDarkTextColor = res.getColor(R.color.recents_task_bar_dark_text_color); + defaultBezierInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); + // Update the search widget id SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0); searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index c64ca5456762..1ca0476cf517 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -35,7 +35,6 @@ import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -362,7 +361,7 @@ public class RecentsTaskLoader { return mSystemServicesProxy; } - private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) { + private List<ActivityManager.RecentTaskInfo> getRecentTasks() { long t1 = System.currentTimeMillis(); SystemServicesProxy ssp = mSystemServicesProxy; @@ -375,23 +374,6 @@ public class RecentsTaskLoader { Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|tasks]", "" + tasks.size()); - // Remove home/recents tasks - Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); - while (iter.hasNext()) { - ActivityManager.RecentTaskInfo t = iter.next(); - - // Skip tasks in the home stack - if (ssp.isInHomeStack(t.persistentId)) { - iter.remove(); - continue; - } - // Skip tasks from this Recents package - if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) { - iter.remove(); - continue; - } - } - return tasks; } @@ -408,7 +390,7 @@ public class RecentsTaskLoader { // Get the recent tasks SystemServicesProxy ssp = mSystemServicesProxy; - List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context); + List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(); // Add each task to the task stack t1 = System.currentTimeMillis(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index 0d3ee382da0b..8d828835e1f1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -30,7 +30,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.graphics.Bitmap; -import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -40,6 +39,7 @@ import android.os.UserManager; import android.util.Pair; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Random; @@ -54,7 +54,7 @@ public class SystemServicesProxy { IPackageManager mIpm; UserManager mUm; SearchManager mSm; - String mPackage; + String mRecentsPackage; ComponentName mAssistComponent; Bitmap mDummyIcon; @@ -67,7 +67,7 @@ public class SystemServicesProxy { mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mIpm = AppGlobals.getPackageManager(); mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); - mPackage = context.getPackageName(); + mRecentsPackage = context.getPackageName(); // Resolve the assist intent Intent assist = mSm.getAssistIntent(context, false); @@ -83,14 +83,14 @@ public class SystemServicesProxy { } /** Returns a list of the recents tasks */ - public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) { + public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId) { if (mAm == null) return null; // If we are mocking, then create some recent tasks if (Constants.DebugFlags.App.EnableSystemServicesProxy) { ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<ActivityManager.RecentTaskInfo>(); - int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); + int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); for (int i = 0; i < count; i++) { // Create a dummy component name int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount; @@ -114,9 +114,43 @@ public class SystemServicesProxy { return tasks; } - return mAm.getRecentTasksForUser(numTasks, + // Remove home/recents/excluded tasks + int minNumTasksToQuery = 10; + int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks); + List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery, ActivityManager.RECENT_IGNORE_UNAVAILABLE | - ActivityManager.RECENT_INCLUDE_PROFILES, userId); + ActivityManager.RECENT_INCLUDE_PROFILES | + ActivityManager.RECENT_WITH_EXCLUDED, userId); + boolean isFirstValidTask = true; + Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); + while (iter.hasNext()) { + ActivityManager.RecentTaskInfo t = iter.next(); + + // NOTE: The order of these checks happens in the expected order of the traversal of the + // tasks + + // Skip tasks from this Recents package + if (t.baseIntent.getComponent().getPackageName().equals(mRecentsPackage)) { + iter.remove(); + continue; + } + // Check the first non-recents task, include this task even if it is marked as excluded + // from recents. In other words, only remove excluded tasks if it is not the first task + boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; + if (isExcluded && !isFirstValidTask) { + iter.remove(); + continue; + } + isFirstValidTask = false; + // Skip tasks in the home stack + if (isInHomeStack(t.persistentId)) { + iter.remove(); + continue; + } + } + + return tasks.subList(0, Math.min(tasks.size(), numLatestTasks)); } /** Returns a list of the running tasks */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java index b602f84acdb5..46e6ee9c8ece 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java @@ -18,6 +18,7 @@ package com.android.systemui.recents; import android.graphics.Color; import android.graphics.Rect; +import android.graphics.drawable.Drawable; /* Common code */ public class Utilities { @@ -54,12 +55,15 @@ public class Utilities { 0.0722f * Color.blue(color)); } - /** Returns the ideal text color to draw on top of a specified background color. */ - public static int getIdealTextColorForBackgroundColor(int color) { - RecentsConfiguration configuration = RecentsConfiguration.getInstance(); + /** Returns the ideal color to draw on top of a specified background color. */ + public static int getIdealColorForBackgroundColor(int color, int lightRes, int darkRes) { int greyscale = colorToGreyscale(color); - return (greyscale < 128) ? configuration.taskBarViewLightTextColor : - configuration.taskBarViewDarkTextColor; - + return (greyscale < 128) ? lightRes : darkRes; + } + /** Returns the ideal drawable to draw on top of a specified background color. */ + public static Drawable getIdealResourceForBackgroundColor(int color, Drawable lightRes, + Drawable darkRes) { + int greyscale = colorToGreyscale(color); + return (greyscale < 128) ? lightRes : darkRes; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java index c6cb81269dec..07caa1b57ad8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java @@ -16,7 +16,10 @@ package com.android.systemui.recents.views; +import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.FrameLayout; import android.widget.ImageView; @@ -32,9 +35,13 @@ import com.android.systemui.recents.model.Task; class TaskBarView extends FrameLayout { Task mTask; + ImageView mDismissButton; ImageView mApplicationIcon; TextView mActivityDescription; + Drawable mLightDismissDrawable; + Drawable mDarkDismissDrawable; + public TaskBarView(Context context) { this(context, null); } @@ -49,6 +56,9 @@ class TaskBarView extends FrameLayout { public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + Resources res = context.getResources(); + mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light); + mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark); } @Override @@ -56,6 +66,28 @@ class TaskBarView extends FrameLayout { // Initialize the icon and description views mApplicationIcon = (ImageView) findViewById(R.id.application_icon); mActivityDescription = (TextView) findViewById(R.id.activity_description); + mDismissButton = (ImageView) findViewById(R.id.dismiss_task); + } + + /** Synchronizes this bar view's properties with the task's transform */ + void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform, + TaskViewTransform toTransform, int duration) { + RecentsConfiguration config = RecentsConfiguration.getInstance(); + if (duration > 0) { + if (animateFromTransform != null) { + mDismissButton.setAlpha(animateFromTransform.dismissAlpha); + } + mDismissButton.animate() + .alpha(toTransform.dismissAlpha) + .setStartDelay(0) + .setDuration(duration) + .setInterpolator(config.defaultBezierInterpolator) + .withLayer() + .start(); + } else { + mDismissButton.setAlpha(toTransform.dismissAlpha); + } + mDismissButton.invalidate(); } /** Binds the bar view to the task */ @@ -74,7 +106,10 @@ class TaskBarView extends FrameLayout { int tint = t.colorPrimary; if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) { setBackgroundColor(tint); - mActivityDescription.setTextColor(Utilities.getIdealTextColorForBackgroundColor(tint)); + mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint, + configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor)); + mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint, + mLightDismissDrawable, mDarkDismissDrawable)); } else { setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor); mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java index c6c29a61b00f..f1c362ab3e99 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java @@ -30,7 +30,6 @@ import android.util.AttributeSet; import android.widget.Button; import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.Utilities; @@ -111,7 +110,8 @@ class TaskInfoView extends FrameLayout { int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius); mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius); mCircularClipAnimator.setDuration(duration); - mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mCircularClipAnimator.setInterpolator( + RecentsConfiguration.getInstance().defaultBezierInterpolator); mCircularClipAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -143,7 +143,7 @@ class TaskInfoView extends FrameLayout { .scaleX(1f) .scaleY(1f) .setDuration(duration) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator) .withLayer() .start(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 55c38a9aa62e..b64225e883a8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -37,7 +37,6 @@ import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.OverScroller; import com.android.systemui.R; -import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; @@ -170,6 +169,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset); } + // Set the alphas + transform.dismissAlpha = Math.max(-1f, Math.min(0f, t)) + 1f; + // Update the rect and visibility transform.rect.set(mTaskRect); if (t < -(numPeekCards + 1)) { @@ -338,7 +340,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll); mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll - curScroll, 250)); - mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator); mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { @@ -1036,6 +1038,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + @Override + public void onTaskDismissed(TaskView tv) { + Task task = tv.getTask(); + // Remove the task from the view + mStack.removeTask(task); + // Notify the callback that we've removed the task and it can clean up after it + mCb.onTaskRemoved(task); + } + /**** View.OnClickListener Implementation ****/ @Override @@ -1095,6 +1106,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onComponentRemoved(Set<ComponentName> cns) { + RecentsConfiguration config = RecentsConfiguration.getInstance(); // For other tasks, just remove them directly if they no longer exist ArrayList<Task> tasks = mStack.getTasks(); for (int i = tasks.size() - 1; i >= 0; i--) { @@ -1477,13 +1489,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { @Override public void onChildDismissed(View v) { TaskView tv = (TaskView) v; - Task task = tv.getTask(); - - // Remove the task from the view - mSv.mStack.removeTask(task); - - // Notify the callback that we've removed the task and it can clean up after it - mSv.mCb.onTaskRemoved(task); + mSv.onTaskDismissed(tv); // Disable HW layers mSv.decHwLayersRefCount("swipeComplete"); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index b03f389eb5b4..5fad6298640b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -31,7 +31,6 @@ import android.view.View; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.model.Task; @@ -46,6 +45,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, public void onTaskInfoPanelShown(TaskView tv); public void onTaskInfoPanelHidden(TaskView tv); public void onTaskAppInfoClicked(TaskView tv); + public void onTaskDismissed(TaskView tv); // public void onTaskViewReboundToTask(TaskView tv, Task t); } @@ -143,6 +143,10 @@ public class TaskView extends FrameLayout implements View.OnClickListener, int minZ = config.taskViewTranslationZMinPx; int incZ = config.taskViewTranslationZIncrementPx; + // Update the bar view + mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration); + + // Update this task view if (duration > 0) { if (animateFromTransform != null) { setTranslationY(animateFromTransform.translationY); @@ -161,7 +165,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, .scaleY(toTransform.scale) .alpha(toTransform.alpha) .setDuration(duration) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setInterpolator(config.defaultBezierInterpolator) .withLayer() .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override @@ -221,8 +225,8 @@ public class TaskView extends FrameLayout implements View.OnClickListener, mBarView.setAlpha(0f); mBarView.animate() .alpha(1f) - .setStartDelay(235) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setStartDelay(250) + .setInterpolator(config.defaultBezierInterpolator) .setDuration(config.taskBarEnterAnimDuration) .withLayer() .start(); @@ -234,7 +238,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, mBarView.animate() .alpha(0f) .setStartDelay(0) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setInterpolator(config.defaultBezierInterpolator) .setDuration(config.taskBarExitAnimDuration) .withLayer() .withEndAction(new Runnable() { @@ -252,7 +256,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, animate().translationX(config.taskViewRemoveAnimTranslationXPx) .alpha(0f) .setStartDelay(0) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setInterpolator(config.defaultBezierInterpolator) .setDuration(config.taskViewRemoveAnimDuration) .withLayer() .withEndAction(new Runnable() { @@ -310,7 +314,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, mInfoView.animate() .alpha(0f) .setDuration(config.taskViewInfoPaneAnimDuration) - .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setInterpolator(config.defaultBezierInterpolator) .withLayer() .withEndAction(new Runnable() { @Override @@ -380,6 +384,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, mInfoView.rebindToTask(mTask, reloadingTaskData); // Rebind any listeners mBarView.mApplicationIcon.setOnClickListener(this); + mBarView.mDismissButton.setOnClickListener(this); mInfoView.mAppInfoButton.setOnClickListener(this); } mTaskDataLoaded = true; @@ -405,6 +410,15 @@ public class TaskView extends FrameLayout implements View.OnClickListener, hideInfoPane(); } else if (v == mBarView.mApplicationIcon) { mCb.onTaskIconClicked(this); + } else if (v == mBarView.mDismissButton) { + // Animate out the view and call the callback + final TaskView tv = this; + animateRemoval(new Runnable() { + @Override + public void run() { + mCb.onTaskDismissed(tv); + } + }); } else if (v == mInfoView.mAppInfoButton) { mCb.onTaskAppInfoClicked(this); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index 0748bbb681dc..e6391a8cd1b8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -24,6 +24,7 @@ public class TaskViewTransform { public int translationY = 0; public float scale = 1f; public float alpha = 1f; + public float dismissAlpha = 1f; public boolean visible = false; public Rect rect = new Rect(); float t; @@ -36,6 +37,7 @@ public class TaskViewTransform { translationY = o.translationY; scale = o.scale; alpha = o.alpha; + dismissAlpha = o.dismissAlpha; visible = o.visible; rect.set(o.rect); t = o.t; @@ -44,6 +46,6 @@ public class TaskViewTransform { @Override public String toString() { return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha + - " visible: " + visible + " rect: " + rect; + " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha; } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 327e7158ee14..1747e6e53985 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -119,7 +119,6 @@ public class BrightnessController implements ToggleSlider.Listener { } }; mBrightnessObserver = new BrightnessObserver(mHandler); - mBrightnessObserver.startObserving(); PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mMinimumBacklight = pm.getMinimumScreenBrightnessSetting(); @@ -128,13 +127,6 @@ public class BrightnessController implements ToggleSlider.Listener { mAutomaticAvailable = context.getResources().getBoolean( com.android.internal.R.bool.config_automatic_brightness_available); mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power")); - - // Update the slider and mode before attaching the listener so we don't receive the - // onChanged notifications for the initial values. - updateMode(); - updateSlider(); - - control.setOnChangedListener(this); } public void addStateChangedCallback(BrightnessStateChangeCallback cb) { @@ -150,11 +142,24 @@ public class BrightnessController implements ToggleSlider.Listener { // Do nothing } + public void registerCallbacks() { + mBrightnessObserver.startObserving(); + mUserTracker.startTracking(); + + // Update the slider and mode before attaching the listener so we don't receive the + // onChanged notifications for the initial values. + updateMode(); + updateSlider(); + + mControl.setOnChangedListener(this); + } + /** Unregister all call backs, both to and from the controller */ public void unregisterCallbacks() { mBrightnessObserver.stopObserving(); mChangeCallbacks.clear(); mUserTracker.stopTracking(); + mControl.setOnChangedListener(null); } public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) { diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java index bd5e5e8dffc8..27881c4f7d06 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java @@ -92,6 +92,7 @@ public class BrightnessDialog extends Dialog implements mBrightnessController = new BrightnessController(getContext(), (ImageView) findViewById(R.id.brightness_icon), (ToggleSlider) findViewById(R.id.brightness_slider)); + mBrightnessController.registerCallbacks(); dismissBrightnessDialog(mBrightnessDialogLongTimeout); mBrightnessController.addStateChangedCallback(this); } diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java index 036bd4ff3dc9..f8ff616599cf 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java +++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java @@ -29,9 +29,6 @@ public abstract class CurrentUserTracker extends BroadcastReceiver { private int mCurrentUserId; public CurrentUserTracker(Context context) { - IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); - context.registerReceiver(this, filter); - mCurrentUserId = ActivityManager.getCurrentUser(); mContext = context; } @@ -50,6 +47,12 @@ public abstract class CurrentUserTracker extends BroadcastReceiver { } } + public void startTracking() { + mCurrentUserId = ActivityManager.getCurrentUser(); + IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); + mContext.registerReceiver(this, filter); + } + public void stopTracking() { mContext.unregisterReceiver(this); } diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java index 7d380583810a..4b780728168d 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java +++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java @@ -62,7 +62,6 @@ public class ToggleSlider extends RelativeLayout { mToggle = (CompoundButton) findViewById(R.id.toggle); mToggle.setOnCheckedChangeListener(mCheckListener); - mToggle.setBackground(res.getDrawable(R.drawable.status_bar_toggle_button)); mSlider = (SeekBar) findViewById(R.id.slider); mSlider.setOnSeekBarChangeListener(mSeekListener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java new file mode 100644 index 000000000000..c26f15ef3366 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -0,0 +1,90 @@ +/* + * 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.content.Intent; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.ContactsContract; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; + +import com.android.systemui.R; +import com.android.systemui.settings.UserSwitcherHostView; +import com.android.systemui.statusbar.policy.UserInfoController; + +/** + * Image button for the multi user switcher. + */ +public class MultiUserSwitch extends ImageButton implements View.OnClickListener, + UserInfoController.OnUserInfoChangedListener { + + private ViewGroup mOverlayParent; + + public MultiUserSwitch(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + setOnClickListener(this); + } + + public void setOverlayParent(ViewGroup parent) { + mOverlayParent = parent; + } + + @Override + public void onClick(View v) { + final UserManager um = UserManager.get(getContext()); + if (um.isUserSwitcherEnabled()) { + final UserSwitcherHostView switcher = + (UserSwitcherHostView) LayoutInflater.from(getContext()).inflate( + R.layout.user_switcher_host, mOverlayParent, false); + switcher.setFinishRunnable(new Runnable() { + @Override + public void run() { + mOverlayParent.removeView(switcher); + } + }); + switcher.refreshUsers(); + mOverlayParent.addView(switcher); + } else { + Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent( + getContext(), v, ContactsContract.Profile.CONTENT_URI, + ContactsContract.QuickContact.MODE_LARGE, null); + getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + } + } + + public void setUserInfoController(UserInfoController userInfoController) { + userInfoController.addListener(this); + } + + @Override + public void onUserInfoChanged(String name, Drawable picture) { + setImageDrawable(picture); + } +} 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 c74911f85e4a..8387e366cc02 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -95,6 +95,7 @@ public class NotificationPanelView extends PanelView implements super.onFinishInflate(); mHeader = (StatusBarHeaderView) findViewById(R.id.header); mHeader.getBackgroundView().setOnClickListener(this); + mHeader.setOverlayParent(this); mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mStackScrollerContainer = findViewById(R.id.notification_container_parent); mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container); @@ -413,11 +414,8 @@ public class NotificationPanelView extends PanelView implements if (!mQsExpansionEnabled) { return false; } - View headerView = mStatusBar.getBarState() == StatusBarState.KEYGUARD && !mQsExpanded - ? mKeyguardStatusView - : mHeader; - boolean onHeader = x >= headerView.getLeft() && x <= headerView.getRight() - && y >= headerView.getTop() && y <= headerView.getBottom(); + boolean onHeader = x >= mHeader.getLeft() && x <= mHeader.getRight() + && y >= mHeader.getTop() && y <= mHeader.getBottom(); if (mQsExpanded) { return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0); } else { @@ -449,6 +447,7 @@ public class NotificationPanelView extends PanelView implements if (toHeader) { mHeader.attachSystemIcons(systemIcons); } else { + mHeader.onSystemIconsDetached(); mStatusBar.reattachSystemIcons(); } } 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 a9a504ee3446..4d09d6ab5c66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -111,6 +111,7 @@ import com.android.systemui.statusbar.policy.HeadsUpNotificationView; import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener; import com.android.systemui.statusbar.stack.StackScrollState.ViewState; @@ -184,6 +185,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, LocationController mLocationController; NetworkController mNetworkController; RotationLockController mRotationLockController; + UserInfoController mUserInfoController; int mNaturalBarHeight = -1; int mIconSize = -1; @@ -221,7 +223,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, int mNotificationPanelGravity; int mNotificationPanelMarginBottomPx; float mNotificationPanelMinHeightFrac; - boolean mNotificationPanelIsFullScreenWidth; TextView mNotificationPanelDebugText; // settings @@ -247,7 +248,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private int mCarrierLabelHeight; private TextView mEmergencyCallLabel; private int mStatusBarHeaderHeight; - private View mKeyguardCarrierLabel; private boolean mShowCarrierInPanel = false; @@ -552,8 +552,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( R.id.notification_panel); mNotificationPanel.setStatusBar(this); - mNotificationPanelIsFullScreenWidth = - (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT); // make the header non-responsive to clicks mNotificationPanel.findViewById(R.id.header).setOnTouchListener( @@ -626,13 +624,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); mKeyguardIconOverflowContainer.setOnActivatedListener(this); - mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text); mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); mStackScroller.addView(mKeyguardIconOverflowContainer); mExpandedContents = mStackScroller; mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); + mHeader.setActivityStarter(this); mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); mKeyguardBottomArea = (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); @@ -647,11 +645,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mDateTimeView.setEnabled(true); } - if (!mNotificationPanelIsFullScreenWidth) { - mNotificationPanel.setSystemUiVisibility( - View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS | - View.STATUS_BAR_DISABLE_CLOCK); - } + mNotificationPanel.setSystemUiVisibility( + View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS | + View.STATUS_BAR_DISABLE_CLOCK); mTicker = new MyTicker(context, mStatusBarView); @@ -672,6 +668,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, || QuickSettings.DEBUG_GONE_TILES) { mRotationLockController = new RotationLockController(mContext); } + mUserInfoController = new UserInfoController(mContext); final SignalClusterView signalCluster = (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); @@ -726,11 +723,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mFlipSettingsView = mSettingsContainer; if (mSettingsContainer != null) { mQS = new QuickSettings(mContext, mSettingsContainer); - if (!mNotificationPanelIsFullScreenWidth) { - mSettingsContainer.setSystemUiVisibility( - View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS - | View.STATUS_BAR_DISABLE_SYSTEM_INFO); - } mQS.setService(this); mQS.setBar(mStatusBarView); mQS.setup(mNetworkController, mBluetoothController, mBatteryController, @@ -739,6 +731,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mQS = null; // fly away, be free } + // User info. Trigger first load. + mHeader.setUserInfoController(mUserInfoController); + mUserInfoController.reloadUserInfo(); + PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBroadcastReceiver.onReceive(mContext, new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); @@ -1864,13 +1860,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void checkBarModes() { if (mDemoMode) return; - int sbMode = mStatusBarMode; - if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0 - && mState != StatusBarState.KEYGUARD) { - // if panels are expandable, force the status bar opaque on any interaction - sbMode = MODE_OPAQUE; - } - checkBarMode(sbMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); + checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); if (mNavigationBarView != null) { checkBarMode(mNavigationBarMode, mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); @@ -2717,14 +2707,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardBottomArea.setVisibility(View.VISIBLE); mKeyguardIndicationTextView.setVisibility(View.VISIBLE); mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase); - mKeyguardCarrierLabel.setVisibility(View.VISIBLE); mNotificationPanel.closeQs(); } else { mKeyguardStatusView.setVisibility(View.GONE); mKeyguardBottomArea.setVisibility(View.GONE); mKeyguardIndicationTextView.setVisibility(View.GONE); - mKeyguardCarrierLabel.setVisibility(View.GONE); } mSettingsContainer.setKeyguardShowing(mState == StatusBarState.KEYGUARD); mHeader.setKeyguardShowing(mState == StatusBarState.KEYGUARD); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index e6de0572abdf..084bfcf1d2e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -63,7 +63,7 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void onAttachedToWindow() { + public void onFinishInflate() { mBarTransitions.init(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java index e1ef83a9e754..005b0d14dcf3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java @@ -460,6 +460,7 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, rebindMediaRouterAsCurrentUser(); } }; + mUserTracker.startTracking(); mNextAlarmObserver = new NextAlarmObserver(mHandler); mNextAlarmObserver.startObserving(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 6b3c94e0ef21..1af9a6b80057 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -17,26 +17,47 @@ package com.android.systemui.statusbar.phone; import android.content.Context; +import android.content.Intent; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.android.systemui.R; +import com.android.systemui.settings.BrightnessController; +import com.android.systemui.settings.ToggleSlider; +import com.android.systemui.statusbar.policy.UserInfoController; /** * The view to manage the header area in the expanded status bar. */ -public class StatusBarHeaderView extends RelativeLayout { +public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener { private boolean mExpanded; + private boolean mKeyguardShowing; + private View mBackground; private ViewGroup mSystemIconsContainer; private View mDateTime; + private View mKeyguardCarrierText; + private MultiUserSwitch mMultiUserSwitch; + private View mDate; + private View mStatusIcons; + private View mSignalCluster; + private View mSettingsButton; + private View mBrightnessContainer; private int mCollapsedHeight; private int mExpandedHeight; + private int mKeyguardHeight; + + private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT; + private int mNormalWidth; + + private ActivityStarter mActivityStarter; + private BrightnessController mBrightnessController; public StatusBarHeaderView(Context context, AttributeSet attrs) { super(context, attrs); @@ -48,6 +69,15 @@ public class StatusBarHeaderView extends RelativeLayout { mBackground = findViewById(R.id.background); mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container); mDateTime = findViewById(R.id.datetime); + mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text); + mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); + mDate = findViewById(R.id.date); + mSettingsButton = findViewById(R.id.settings_button); + mSettingsButton.setOnClickListener(this); + mBrightnessContainer = findViewById(R.id.brightness_container); + mBrightnessController = new BrightnessController(getContext(), + (ImageView) findViewById(R.id.brightness_icon), + (ToggleSlider) findViewById(R.id.brightness_slider)); loadDimens(); } @@ -55,10 +85,17 @@ public class StatusBarHeaderView extends RelativeLayout { mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height); mExpandedHeight = getResources().getDimensionPixelSize( R.dimen.status_bar_header_height_expanded); + mKeyguardHeight = getResources().getDimensionPixelSize( + R.dimen.status_bar_header_height_keyguard); + mNormalWidth = getLayoutParams().width; + } + + public void setActivityStarter(ActivityStarter activityStarter) { + mActivityStarter = activityStarter; } public int getCollapsedHeight() { - return mCollapsedHeight; + return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight; } public int getExpandedHeight() { @@ -66,11 +103,81 @@ public class StatusBarHeaderView extends RelativeLayout { } public void setExpanded(boolean expanded) { - if (expanded != mExpanded) { - ViewGroup.LayoutParams lp = getLayoutParams(); - lp.height = expanded ? mExpandedHeight : mCollapsedHeight; + boolean changed = expanded != mExpanded; + mExpanded = expanded; + if (changed) { + updateHeights(); + updateVisibilities(); + updateSystemIconsLayoutParams(); + updateBrightnessControllerState(); + } + } + + private void updateHeights() { + boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; + int height; + if (mExpanded) { + height = mExpandedHeight; + } else if (onKeyguardAndCollapsed) { + height = mKeyguardHeight; + } else { + height = mCollapsedHeight; + } + ViewGroup.LayoutParams lp = getLayoutParams(); + if (lp.height != height) { + lp.height = height; setLayoutParams(lp); - mExpanded = expanded; + } + int systemIconsContainerHeight = onKeyguardAndCollapsed ? mKeyguardHeight : mCollapsedHeight; + lp = mSystemIconsContainer.getLayoutParams(); + if (lp.height != systemIconsContainerHeight) { + lp.height = systemIconsContainerHeight; + mSystemIconsContainer.setLayoutParams(lp); + } + lp = mMultiUserSwitch.getLayoutParams(); + if (lp.height != systemIconsContainerHeight) { + lp.height = systemIconsContainerHeight; + mMultiUserSwitch.setLayoutParams(lp); + } + } + + private void updateWidth() { + int width = mKeyguardShowing ? mKeyguardWidth : mNormalWidth; + ViewGroup.LayoutParams lp = getLayoutParams(); + if (width != lp.width) { + lp.width = width; + setLayoutParams(lp); + } + } + + private void updateVisibilities() { + boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; + mBackground.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); + mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); + mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE); + mDate.setVisibility(mExpanded ? View.VISIBLE : View.GONE); + mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.GONE); + mBrightnessContainer.setVisibility(mExpanded ? View.VISIBLE : View.GONE); + if (mStatusIcons != null) { + mStatusIcons.setVisibility(!mExpanded ? View.VISIBLE : View.GONE); + } + if (mSignalCluster != null) { + mSignalCluster.setVisibility(!mExpanded ? View.VISIBLE : View.GONE); + } + } + + private void updateSystemIconsLayoutParams() { + RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams(); + lp.addRule(RelativeLayout.START_OF, mExpanded + ? mSettingsButton.getId() + : mMultiUserSwitch.getId()); + } + + private void updateBrightnessControllerState() { + if (mExpanded) { + mBrightnessController.registerCallbacks(); + } else { + mBrightnessController.unregisterCallbacks(); } } @@ -94,15 +201,49 @@ public class StatusBarHeaderView extends RelativeLayout { public void attachSystemIcons(LinearLayout systemIcons) { mSystemIconsContainer.addView(systemIcons); + mStatusIcons = systemIcons.findViewById(R.id.statusIcons); + mSignalCluster = systemIcons.findViewById(R.id.signal_cluster); + } + + public void onSystemIconsDetached() { + if (mStatusIcons != null) { + mStatusIcons.setVisibility(View.VISIBLE); + } + if (mSignalCluster != null) { + mSignalCluster.setVisibility(View.VISIBLE); + } + mStatusIcons = null; + mSignalCluster = null; } public void setKeyguardShowing(boolean keyguardShowing) { - mBackground.setVisibility(keyguardShowing ? View.INVISIBLE : View.VISIBLE); - mDateTime.setVisibility(keyguardShowing ? View.INVISIBLE : View.VISIBLE); + mKeyguardShowing = keyguardShowing; if (keyguardShowing) { setZ(0); } else { setTranslationZ(0); } + updateHeights(); + updateWidth(); + updateVisibilities(); + } + + public void setUserInfoController(UserInfoController userInfoController) { + mMultiUserSwitch.setUserInfoController(userInfoController); + } + + public void setOverlayParent(ViewGroup parent) { + mMultiUserSwitch.setOverlayParent(parent); + } + + @Override + public void onClick(View v) { + if (v == mSettingsButton) { + startSettingsActivity(); + } + } + + private void startSettingsActivity() { + mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index a4c9df56ac78..8809d18cd5b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -78,9 +78,8 @@ public class StatusBarWindowManager { | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, PixelFormat.TRANSLUCENT); - mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - mLp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + mLp.gravity = Gravity.TOP; mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index 8ced1c9cc2c6..55a0bba6a61d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.TypedArray; import android.os.Bundle; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -30,6 +31,7 @@ import android.util.AttributeSet; import android.widget.TextView; import com.android.systemui.DemoMode; +import com.android.systemui.R; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -52,7 +54,7 @@ public class Clock extends TextView implements DemoMode { private static final int AM_PM_STYLE_SMALL = 1; private static final int AM_PM_STYLE_GONE = 2; - private static final int AM_PM_STYLE = AM_PM_STYLE_GONE; + private final int mAmPmStyle; public Clock(Context context) { this(context, null); @@ -64,6 +66,15 @@ public class Clock extends TextView implements DemoMode { public Clock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.Clock, + 0, 0); + try { + mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE); + } finally { + a.recycle(); + } } @Override @@ -145,7 +156,7 @@ public class Clock extends TextView implements DemoMode { * add dummy characters around it to let us find it again after * formatting and change its size. */ - if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { + if (mAmPmStyle != AM_PM_STYLE_NORMAL) { int a = -1; boolean quoted = false; for (int i = 0; i < format.length(); i++) { @@ -177,15 +188,15 @@ public class Clock extends TextView implements DemoMode { } String result = sdf.format(mCalendar.getTime()); - if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { + if (mAmPmStyle != AM_PM_STYLE_NORMAL) { int magic1 = result.indexOf(MAGIC1); int magic2 = result.indexOf(MAGIC2); if (magic1 >= 0 && magic2 > magic1) { SpannableStringBuilder formatted = new SpannableStringBuilder(result); - if (AM_PM_STYLE == AM_PM_STYLE_GONE) { + if (mAmPmStyle == AM_PM_STYLE_GONE) { formatted.delete(magic1, magic2+1); } else { - if (AM_PM_STYLE == AM_PM_STYLE_SMALL) { + if (mAmPmStyle == AM_PM_STYLE_SMALL) { CharacterStyle style = new RelativeSizeSpan(0.7f); formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java new file mode 100644 index 000000000000..173af409f554 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java @@ -0,0 +1,215 @@ +/* + * 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.policy; + +import android.app.ActivityManagerNative; +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.hardware.display.DisplayManager; +import android.os.AsyncTask; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.ContactsContract; +import android.security.KeyChain; +import android.util.Log; +import android.util.Pair; + +import com.android.internal.view.RotationPolicy; +import com.android.systemui.R; + +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; + +public final class UserInfoController { + + private static final String TAG = "UserInfoController"; + + private final Context mContext; + private final ArrayList<OnUserInfoChangedListener> mCallbacks = + new ArrayList<OnUserInfoChangedListener>(); + private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask; + + private boolean mUseDefaultAvatar; + private String mUserName; + private Drawable mUserDrawable; + + public UserInfoController(Context context) { + mContext = context; + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + mContext.registerReceiver(mReceiver, filter); + + IntentFilter profileFilter = new IntentFilter(); + profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); + profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); + mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, + null, null); + } + + public void addListener(OnUserInfoChangedListener callback) { + mCallbacks.add(callback); + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + reloadUserInfo(); + } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + if (mUseDefaultAvatar) { + reloadUserInfo(); + } + } + } + }; + + private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || + Intent.ACTION_USER_INFO_CHANGED.equals(action)) { + try { + final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; + final int changedUser = + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); + if (changedUser == currentUser) { + reloadUserInfo(); + } + } catch (RemoteException e) { + Log.e(TAG, "Couldn't get current user id for profile change", e); + } + } + } + }; + + public void reloadUserInfo() { + if (mUserInfoTask != null) { + mUserInfoTask.cancel(false); + mUserInfoTask = null; + } + queryForUserInformation(); + } + + private Bitmap circularClip(Bitmap input) { + Bitmap output = Bitmap.createBitmap(input.getWidth(), + input.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final Paint paint = new Paint(); + paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + paint.setAntiAlias(true); + canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2, paint); + return output; + } + + private void queryForUserInformation() { + Context currentUserContext; + UserInfo userInfo; + try { + userInfo = ActivityManagerNative.getDefault().getCurrentUser(); + currentUserContext = mContext.createPackageContextAsUser("android", 0, + new UserHandle(userInfo.id)); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Couldn't create user context", e); + throw new RuntimeException(e); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't get user info", e); + throw new RuntimeException(e); + } + final int userId = userInfo.id; + final String userName = userInfo.name; + + final Context context = currentUserContext; + mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() { + @Override + protected Pair<String, Drawable> doInBackground(Void... params) { + final UserManager um = UserManager.get(mContext); + + // Fall back to the UserManager nickname if we can't read the name from the local + // profile below. + String name = userName; + Drawable avatar = null; + Bitmap rawAvatar = um.getUserIcon(userId); + if (rawAvatar != null) { + avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar)); + } else { + avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user); + mUseDefaultAvatar = true; + } + + // If it's a single-user device, get the profile name, since the nickname is not + // usually valid + if (um.getUsers().size() <= 1) { + // Try and read the display name from the local profile + final Cursor cursor = context.getContentResolver().query( + ContactsContract.Profile.CONTENT_URI, new String[] { + ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME}, + null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + name = cursor.getString(cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + } + } finally { + cursor.close(); + } + } + } + return new Pair<String, Drawable>(name, avatar); + } + + @Override + protected void onPostExecute(Pair<String, Drawable> result) { + mUserName = result.first; + mUserDrawable = result.second; + mUserInfoTask = null; + notifyChanged(); + } + }; + mUserInfoTask.execute(); + } + + private void notifyChanged() { + for (OnUserInfoChangedListener listener : mCallbacks) { + listener.onUserInfoChanged(mUserName, mUserDrawable); + } + } + + public interface OnUserInfoChangedListener { + public void onUserInfoChanged(String name, Drawable picture); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index afd506844550..27f661992cb1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -153,7 +153,10 @@ public class NotificationStackScrollLayout extends ViewGroup if (DEBUG) { int y = mCollapsedSize; canvas.drawLine(0, y, getWidth(), y, mDebugPaint); - y = (int) (getLayoutHeight() - mBottomStackPeekSize - mCollapsedSize); + y = (int) (getLayoutHeight() - mBottomStackPeekSize + - mStackScrollAlgorithm.getBottomStackSlowDownLength()); + canvas.drawLine(0, y, getWidth(), y, mDebugPaint); + y = (int) (getLayoutHeight() - mBottomStackPeekSize); canvas.drawLine(0, y, getWidth(), y, mDebugPaint); y = (int) getLayoutHeight(); canvas.drawLine(0, y, getWidth(), y, mDebugPaint); @@ -1226,6 +1229,7 @@ public class NotificationStackScrollLayout extends ViewGroup * See {@link AmbientState#setDimmed}. */ public void setDimmed(boolean dimmed, boolean animate) { + mStackScrollAlgorithm.setDimmed(dimmed); mAmbientState.setDimmed(dimmed); if (animate) { mDimmedNeedsAnimation = true; @@ -1311,6 +1315,7 @@ public class NotificationStackScrollLayout extends ViewGroup // ANIMATION_TYPE_DIMMED new AnimationFilter() + .animateY() .animateScale() .animateDimmed() }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java index 38b544f2cc01..1c37c35d49dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java @@ -38,27 +38,26 @@ public class PiecewiseLinearIndentationFunctor extends StackIndentationFunctor { * the actual visual distance below the top card but is a maximum, * achieved when the next card just starts transitioning into the stack and * the stack is full. - * If totalTransitionDistance is equal to this, we directly start at the peek, - * otherwise the first element transitions between 0 and - * totalTransitionDistance - peekSize. + * If distanceToPeekStart is 0, we directly start at the peek, otherwise the + * first element transitions between 0 and distanceToPeekStart. * Visualization: * --------------------------------------------------- --- * | | | - * | FIRST ITEM | | <- totalTransitionDistance + * | FIRST ITEM | | <- distanceToPeekStart * | | | - * |---------------------------------------------------| | --- - * |__________________SECOND ITEM______________________| | | <- peekSize - * |===================================================| _|_ _|_ + * |---------------------------------------------------| --- --- + * |__________________SECOND ITEM______________________| | <- peekSize + * |===================================================| _|_ * - * @param totalTransitionDistance The total transition distance an element has to go through + * @param distanceToPeekStart The distance to the start of the peak. * @param linearPart The interpolation factor between the linear and the quadratic amount taken. * This factor must be somewhere in [0 , 1] */ PiecewiseLinearIndentationFunctor(int maxItemsInStack, int peekSize, - int totalTransitionDistance, + int distanceToPeekStart, float linearPart) { - super(maxItemsInStack, peekSize, totalTransitionDistance); + super(maxItemsInStack, peekSize, distanceToPeekStart); mBaseValues = new ArrayList<Float>(maxItemsInStack+1); initBaseValues(); mLinearPart = linearPart; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java index f72947a6476a..034eba6836ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java @@ -21,8 +21,8 @@ package com.android.systemui.statusbar.stack; */ public abstract class StackIndentationFunctor { - protected final int mTotalTransitionDistance; - protected final int mDistanceToPeekStart; + protected int mTotalTransitionDistance; + protected int mDistanceToPeekStart; protected int mMaxItemsInStack; protected int mPeekSize; protected boolean mStackStartsAtPeek; @@ -37,31 +37,41 @@ public abstract class StackIndentationFunctor { * the actual visual distance below the top card but is a maximum, * achieved when the next card just starts transitioning into the stack and * the stack is full. - * If totalTransitionDistance is equal to this, we directly start at the peek, - * otherwise the first element transitions between 0 and - * totalTransitionDistance - peekSize. + * If distanceToPeekStart is 0, we directly start at the peek, otherwise the + * first element transitions between 0 and distanceToPeekStart. * Visualization: * --------------------------------------------------- --- * | | | - * | FIRST ITEM | | <- totalTransitionDistance + * | FIRST ITEM | | <- distanceToPeekStart * | | | - * |---------------------------------------------------| | --- - * |__________________SECOND ITEM______________________| | | <- peekSize - * |===================================================| _|_ _|_ + * |---------------------------------------------------| --- --- + * |__________________SECOND ITEM______________________| | <- peekSize + * |===================================================| _|_ * - * @param totalTransitionDistance The total transition distance an element has to go through + * @param distanceToPeekStart The distance to the start of the peak. */ - StackIndentationFunctor(int maxItemsInStack, int peekSize, int totalTransitionDistance) { - mTotalTransitionDistance = totalTransitionDistance; - mDistanceToPeekStart = mTotalTransitionDistance - peekSize; + StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) { + mDistanceToPeekStart = distanceToPeekStart; mStackStartsAtPeek = mDistanceToPeekStart == 0; mMaxItemsInStack = maxItemsInStack; mPeekSize = peekSize; + updateTotalTransitionDistance(); } + private void updateTotalTransitionDistance() { + mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize; + } + public void setPeekSize(int mPeekSize) { this.mPeekSize = mPeekSize; + updateTotalTransitionDistance(); + } + + public void setDistanceToPeekStart(int distanceToPeekStart) { + mDistanceToPeekStart = distanceToPeekStart; + mStackStartsAtPeek = mDistanceToPeekStart == 0; + updateTotalTransitionDistance(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 5e4d496ee00f..bd9de8270c68 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -65,13 +65,40 @@ public class StackScrollAlgorithm { private ExpandableView mFirstChildWhileExpanding; private boolean mExpandedOnStart; private int mTopStackTotalSize; + private int mPaddingBetweenElementsDimmed; + private int mPaddingBetweenElementsNormal; + private int mBottomStackSlowDownLength; public StackScrollAlgorithm(Context context) { initConstants(context); + updatePadding(false); + } + + private void updatePadding(boolean dimmed) { + mPaddingBetweenElements = dimmed + ? mPaddingBetweenElementsDimmed + : mPaddingBetweenElementsNormal; + mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements; + mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( + MAX_ITEMS_IN_TOP_STACK, + mTopStackPeekSize, + mTopStackTotalSize - mTopStackPeekSize, + 0.5f); + mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( + MAX_ITEMS_IN_BOTTOM_STACK, + mBottomStackPeekSize, + getBottomStackSlowDownLength(), + 0.5f); + } + + public int getBottomStackSlowDownLength() { + return mBottomStackSlowDownLength + mPaddingBetweenElements; } private void initConstants(Context context) { - mPaddingBetweenElements = context.getResources() + mPaddingBetweenElementsDimmed = context.getResources() + .getDimensionPixelSize(R.dimen.notification_padding_dimmed); + mPaddingBetweenElementsNormal = context.getResources() .getDimensionPixelSize(R.dimen.notification_padding); mCollapsedSize = context.getResources() .getDimensionPixelSize(R.dimen.notification_min_height); @@ -82,17 +109,8 @@ public class StackScrollAlgorithm { mZDistanceBetweenElements = context.getResources() .getDimensionPixelSize(R.dimen.z_distance_between_notifications); mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements; - mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements; - mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( - MAX_ITEMS_IN_TOP_STACK, - mTopStackPeekSize, - mTopStackTotalSize, - 0.5f); - mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( - MAX_ITEMS_IN_BOTTOM_STACK, - mBottomStackPeekSize, - mCollapsedSize + mBottomStackPeekSize + mPaddingBetweenElements, - 0.5f); + mBottomStackSlowDownLength = context.getResources() + .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length); } @@ -206,7 +224,7 @@ public class StackScrollAlgorithm { float bottomPeekStart = mInnerHeight - mBottomStackPeekSize; // The position where the bottom stack starts. - float bottomStackStart = bottomPeekStart - mCollapsedSize; + float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength; // The y coordinate of the current child. float currentYPosition = 0.0f; @@ -352,7 +370,7 @@ public class StackScrollAlgorithm { algorithmState.itemsInBottomStack += algorithmState.partialInBottom; childViewState.yTranslation = transitioningPositionStart + offset - childHeight - mPaddingBetweenElements; - + // We want at least to be at the end of the top stack when collapsing clampPositionToTopStackEnd(childViewState, childHeight); childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA; @@ -621,6 +639,10 @@ public class StackScrollAlgorithm { } } + public void setDimmed(boolean dimmed) { + updatePadding(dimmed); + } + class StackScrollAlgorithmState { /** diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 0d1e122afc25..96f9ab061c10 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -50,6 +50,8 @@ import java.util.LinkedList; final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { private static final boolean LOGD = false; + private final static boolean VDBG = false; + private final String TAG; private String mSocket; @@ -409,7 +411,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); } - log("RMV <- {" + event + "}"); + if (VDBG) log("RMV <- {" + event + "}"); events.add(event); } while (event.isClassContinue()); diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 4f0c9b537ff2..512ebc6599f3 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -171,6 +171,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub { return; } writer.println("Current scorer: " + currentScorer); + writer.flush(); for (INetworkScoreCache scoreCache : getScoreCaches()) { try { diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index ea9de1e83ccc..82c13e0d4394 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -360,8 +360,9 @@ public class VibratorService extends IVibratorService.Stub // Lock held on mVibrations private void startVibrationLocked(final Vibration vib) { try { - if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING) - return; + if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING) { + return; + } int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, vib.mStreamHint, vib.mUid, vib.mOpPkg); @@ -443,7 +444,7 @@ public class VibratorService extends IVibratorService.Stub } mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.LOW_POWER_MODE, 0) != 0; + Settings.Global.LOW_POWER_MODE, 0) != 0; if (mVibrateInputDevicesSetting) { if (!mInputDeviceListenerRegistered) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 3ae0fd54ab9f..3d5fb5700f5d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -518,6 +518,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Brighten quickly. slow = false; } + // If low power mode is enabled, brightness level + // would be scaled down to half + if (mPowerRequest.lowPowerMode) { + target = target/2; + } animateScreenBrightness(clampScreenBrightness(target), slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST); } else { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 6d2e8592183b..47a8b2e58726 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -1634,6 +1634,8 @@ public final class PowerManagerService extends com.android.server.SystemService mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld(); + mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled; + mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity); mRequestWaitForNegativeProximity = false; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 637beec52439..836a19c56382 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5038,6 +5038,10 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires DISABLE_KEYGUARD permission"); } + if (token == null) { + throw new IllegalArgumentException("token == null"); + } + mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage( KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag))); } @@ -5049,6 +5053,10 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires DISABLE_KEYGUARD permission"); } + if (token == null) { + throw new IllegalArgumentException("token == null"); + } + mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage( KeyguardDisableHandler.KEYGUARD_REENABLE, token)); } @@ -5062,6 +5070,11 @@ public class WindowManagerService extends IWindowManager.Stub != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires DISABLE_KEYGUARD permission"); } + + if (callback == null) { + throw new IllegalArgumentException("callback == null"); + } + mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() { @Override public void onKeyguardExitResult(boolean success) { |