Merge "Define audio attributes"
diff --git a/api/current.txt b/api/current.txt
index eb079db..9c142d44 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4849,6 +4849,7 @@
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 @@
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 @@
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 66b82eb..b4b3c99 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3618,13 +3618,15 @@
}
// 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 347de97..8ab9ac3 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -43,4 +43,5 @@
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 aab6ed8..db91742a 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -44,8 +44,8 @@
* 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 9405325..64e3484 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -26,6 +26,7 @@
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.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 @@
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 fa40286..81bcb39 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -23,6 +23,7 @@
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.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 @@
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 @@
}
@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 cec90cd..e58c54d 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -156,6 +156,9 @@
// 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 @@
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
blockScreenOn = other.blockScreenOn;
+ lowPowerMode = other.lowPowerMode;
}
@Override
@@ -218,7 +222,8 @@
&& screenBrightness == other.screenBrightness
&& screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
&& useAutoBrightness == other.useAutoBrightness
- && blockScreenOn == other.blockScreenOn;
+ && blockScreenOn == other.blockScreenOn
+ && lowPowerMode == other.lowPowerMode;
}
@Override
@@ -233,7 +238,8 @@
+ ", 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 8b7467f..4857533 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@
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.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 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 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 @@
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 @@
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 @@
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 @@
this.shortValues = shortValues;
}
}
-
+
public abstract int getHistoryTotalSize();
public abstract int getHistoryUsedSize();
@@ -2958,10 +3016,14 @@
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 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 @@
(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 @@
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 @@
if (startIteratingOldHistoryLocked()) {
try {
+ final HistoryItem rec = new HistoryItem();
pw.println("Old battery History:");
HistoryPrinter hprinter = new HistoryPrinter();
long baseTime = -1;
@@ -3348,7 +3460,6 @@
(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 @@
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 a675821..be3b6ce 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -21,6 +21,8 @@
import android.graphics.Paint;
import android.util.SparseIntArray;
+import com.android.internal.util.VirtualRefBasePtr;
+
import java.lang.ref.WeakReference;
/**
@@ -70,28 +72,32 @@
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 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 @@
}
}
- @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 @@
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 e1c6f52..be0c27d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -49,7 +49,6 @@
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 @@
* 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 25bcd44..ac12357 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -50,28 +50,6 @@
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 f4cd5fc..565ea13 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3267,7 +3267,7 @@
}
}
- 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 @@
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 @@
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 @@
(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 @@
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 @@
break;
case TOUCH_MODE_SCROLL:
case TOUCH_MODE_OVERSCROLL:
- scrollIfNeeded(y, vtev);
+ scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev);
break;
}
}
@@ -4022,8 +4033,8 @@
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 @@
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 @@
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 fa37443..83fbe8f 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 @@
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 @@
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 static final float SIN_45 = (float) Math.sin(Math.PI / 4);
- private float mEdgeAlpha;
- private float mEdgeScaleY;
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 @@
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 @@
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 @@
* @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 @@
* 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 @@
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 @@
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 @@
}
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 @@
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 boolean draw(Canvas canvas) {
update();
- mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
+ final int count = canvas.save();
- 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 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);
+
+ 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();
}
+ 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);
- mGlow.draw(canvas);
-
- 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);
- }
- mEdge.draw(canvas);
-
- if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+ 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 @@
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 @@
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 @@
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 25d4f42..0c65c50 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -616,12 +616,14 @@
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 0fa75a6..fd04890 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -669,12 +669,14 @@
} 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 882bec9..41f3337 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1108,13 +1108,6 @@
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 1aff190..7bd5b12 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -188,8 +188,7 @@
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 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 @@
}
}
+ 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 52281d9..34f62ba 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -450,6 +450,7 @@
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 @@
// 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 0000000..0bd4d3a
--- /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 51e2871..26f77b5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -155,7 +155,8 @@
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 66fbb8e..9941cd9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -181,6 +181,7 @@
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 @@
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 e0fa9ba4..0328517 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 70e2db5..cfa9cd8 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 @@
#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 @@
#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 3be013b..4787d28 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -101,7 +101,6 @@
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 @@
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 @@
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 @@
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 @@
{ "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 0000000..ce6f207
--- /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 28e75e6..7a6832e 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 5a96ba1..e2326ec 100644
--- a/docs/html/guide/topics/resources/string-resource.jd
+++ b/docs/html/guide/topics/resources/string-resource.jd
@@ -20,9 +20,6 @@
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 @@
-<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 @@
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 3b1292e..59c2269 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -16,6 +16,7 @@
<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 @@
{@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
new file mode 100644
index 0000000..17b1703
--- /dev/null
+++ b/docs/html/wear/images/notif_summary_framed.png
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index 7f955f6..a2d34ce 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,8 +2,8 @@
@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 @@
<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 @@
<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();
+<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>
+
+<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 will not appear in your stack of notifications on the wearable, but
-appears as the only notification on the handheld device.
+<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 99ea9b1..be86060 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 @@
}
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 0b074cc..86fc7c3 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 2e1d176..6074394 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 eaeb772..b2ead5b 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 159903c..bc62ee1 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 d22cb8a..08e9a1a 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -214,18 +214,28 @@
int dstY = y + glyph->mBitmapTop;
CacheTexture* cacheTexture = glyph->mCacheTexture;
-
- uint32_t cacheWidth = cacheTexture->getWidth();
- uint32_t startY = glyph->mStartY * cacheWidth;
- uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
-
PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
+
+ uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
+ uint32_t cacheWidth = cacheTexture->getWidth();
+ uint32_t srcStride = formatSize * cacheWidth;
+ uint32_t startY = glyph->mStartY * srcStride;
+ uint32_t endY = startY + (glyph->mBitmapHeight * srcStride);
+
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 b545aab..0000000
--- 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 b2b2bd8..9069a55 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -436,6 +436,8 @@
@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 546ddd4..0d943ed 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
deleted file mode 100644
index 3b1944d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 693abf5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index 807f607..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 15340d3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index e562bc2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e3cc9b0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index a2e8fe1..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e15981a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
deleted file mode 100644
index 7cf3175..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_quicksettings_normal" />
- <item
- android:drawable="@drawable/ic_notify_quicksettings_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_settings.xml b/packages/SystemUI/res/drawable/ic_notify_settings.xml
deleted file mode 100644
index 9303ca4..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_settings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_settings_normal" />
- <item
- android:drawable="@drawable/ic_notify_settings_normal" />
-</selector>
-
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 0000000..5c38a22
--- /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 c5ba18b..09d0d7d 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/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
new file mode 100644
index 0000000..c015cc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1" >
+
+ <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/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
new file mode 100644
index 0000000..9c93db9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1" >
+
+ <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 e4954e7..7d9cfa1 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 b7df51d..1efda8c 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 f7df18eb..bda6431 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 7308626..f045da4 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 3759f82..89fa988 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>
+ <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: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_alignParentEnd="true"
- android:layout_marginEnd="16dp"
+ 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 f4d7033..0000000
--- 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 e6d7c93..0e84762 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 e95f3c3..26616cd 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 bc56cf6..70c5042 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 b7becac..d4a99866 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 f5674d2..8fd1206 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 c78ff8e..c1a4e26 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 c0376f0..21eb41c 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 50df706..ab34030 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 8ab646d..4f52870 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 3ef8316..19a1b11 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 @@
/** 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 @@
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 @@
}
// 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 95ab8e8..0000000
--- 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 1d6a76c..90998da 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 @@
// 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 463cf74..9afc1cb 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.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 float animationPxMovementPerSecond;
+ public Interpolator defaultBezierInterpolator;
+
public int filteringCurrentViewsMinAnimDuration;
public int filteringNewViewsMinAnimDuration;
public int taskBarEnterAnimDuration;
@@ -121,7 +125,6 @@
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 @@
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 c64ca54..1ca0476 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 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 @@
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 @@
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 @@
// 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 0d3ee38..8d82883 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.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.util.Pair;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Random;
@@ -54,7 +54,7 @@
IPackageManager mIpm;
UserManager mUm;
SearchManager mSm;
- String mPackage;
+ String mRecentsPackage;
ComponentName mAssistComponent;
Bitmap mDummyIcon;
@@ -67,7 +67,7 @@
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 @@
}
/** 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 @@
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 b602f84..46e6ee9 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 @@
import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
/* Common code */
public class Utilities {
@@ -54,12 +55,15 @@
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 c6cb812..07caa1b 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 @@
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 @@
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 @@
// 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 @@
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 c6c29a6..f1c362a 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.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 @@
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 @@
.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 55c38a9..b64225e 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.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 @@
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 @@
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 @@
}
}
+ @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 @@
@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 @@
@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 b03f389..5fad629 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.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 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 @@
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 @@
.scaleY(toTransform.scale)
.alpha(toTransform.alpha)
.setDuration(duration)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.withLayer()
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -221,8 +225,8 @@
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 @@
mBarView.animate()
.alpha(0f)
.setStartDelay(0)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.setDuration(config.taskBarExitAnimDuration)
.withLayer()
.withEndAction(new Runnable() {
@@ -252,7 +256,7 @@
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 @@
mInfoView.animate()
.alpha(0f)
.setDuration(config.taskViewInfoPaneAnimDuration)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.withLayer()
.withEndAction(new Runnable() {
@Override
@@ -380,6 +384,7 @@
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 @@
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 0748bbb..e6391a8 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 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 @@
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 @@
@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 327e715..1747e6e 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 @@
}
};
mBrightnessObserver = new BrightnessObserver(mHandler);
- mBrightnessObserver.startObserving();
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
@@ -128,13 +127,6 @@
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 @@
// 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 bd5e5e8..27881c4 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 @@
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 036bd4f..f8ff616 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 @@
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 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 7d38058..4b78072 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 @@
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 0000000..c26f15e
--- /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 c74911f..8387e36 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 @@
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 @@
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 @@
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 a9a504e..4d09d6a 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.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 @@
LocationController mLocationController;
NetworkController mNetworkController;
RotationLockController mRotationLockController;
+ UserInfoController mUserInfoController;
int mNaturalBarHeight = -1;
int mIconSize = -1;
@@ -221,7 +223,6 @@
int mNotificationPanelGravity;
int mNotificationPanelMarginBottomPx;
float mNotificationPanelMinHeightFrac;
- boolean mNotificationPanelIsFullScreenWidth;
TextView mNotificationPanelDebugText;
// settings
@@ -247,7 +248,6 @@
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
private int mStatusBarHeaderHeight;
- private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -552,8 +552,6 @@
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 @@
(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 @@
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 @@
|| 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 @@
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 @@
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 @@
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 @@
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 e6de057..084bfcf 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 @@
}
@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 e1ef83a..005b0d1 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 @@
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 6b3c94e..1af9a6b 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 @@
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 @@
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 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 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 a4c9df5..8809d18 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 @@
| 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 8ced1c9..55a0bba 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.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.widget.TextView;
import com.android.systemui.DemoMode;
+import com.android.systemui.R;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -52,7 +54,7 @@
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 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 @@
* 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 @@
}
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 0000000..173af40
--- /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 afd5068..27f6619 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 @@
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 @@
* 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 @@
// 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 38b544f..1c37c35 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 @@
* 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 f72947a..034eba6 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 @@
*/
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 @@
* 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 5e4d496..bd9de82 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 @@
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 @@
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 @@
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 @@
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 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 0d1e122..96f9ab0 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -50,6 +50,8 @@
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 @@
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 4f0c9b5..512ebc6 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -171,6 +171,7 @@
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 ea9de1e..82c13e0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -360,8 +360,9 @@
// 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 @@
}
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 3ae0fd5..3d5fb57 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 @@
// 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 6d2e8592..47a8b2e 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 @@
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 637beec..836a19c 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 @@
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 @@
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 @@
!= 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) {