Merge "Added frustum plane extraction and sphere culling code."
diff --git a/api/9.xml b/api/9.xml
index 9d8456a..7a4aed0 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -195395,6 +195395,39 @@
<parameter name="defStyle" type="int">
</parameter>
</constructor>
+<field name="CHOICE_MODE_MULTIPLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_SINGLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<method name="afterTextChanged"
return="void"
abstract="false"
@@ -203851,39 +203884,6 @@
<parameter name="y" type="int">
</parameter>
</method>
-<field name="CHOICE_MODE_MULTIPLE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_NONE"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_SINGLE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ListView.FixedViewInfo"
extends="java.lang.Object"
diff --git a/api/current.xml b/api/current.xml
index 4356852..739b0c9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -128150,6 +128150,16 @@
visibility="public"
>
</field>
+<field name="SERIAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TAGS"
type="java.lang.String"
transient="false"
@@ -215125,6 +215135,17 @@
<parameter name="after" type="int">
</parameter>
</method>
+<method name="clearChoices"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="clearTextFilter"
return="void"
abstract="false"
@@ -215147,6 +215168,61 @@
visibility="public"
>
</method>
+<method name="getCheckedItemCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemIds"
+ return="long[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemPositions"
+ return="android.util.SparseBooleanArray"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChoiceMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getListPaddingBottom"
return="int"
abstract="false"
@@ -215290,6 +215366,19 @@
visibility="protected"
>
</method>
+<method name="isItemChecked"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
<method name="isScrollingCacheEnabled"
return="boolean"
abstract="false"
@@ -215490,6 +215579,19 @@
<parameter name="views" type="java.util.List<android.view.View>">
</parameter>
</method>
+<method name="setAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.ListAdapter">
+</parameter>
+</method>
<method name="setCacheColorHint"
return="void"
abstract="false"
@@ -215503,6 +215605,19 @@
<parameter name="color" type="int">
</parameter>
</method>
+<method name="setChoiceMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="choiceMode" type="int">
+</parameter>
+</method>
<method name="setDrawSelectorOnTop"
return="void"
abstract="false"
@@ -215542,6 +215657,34 @@
<parameter name="filterText" type="java.lang.String">
</parameter>
</method>
+<method name="setItemChecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+<parameter name="value" type="boolean">
+</parameter>
+</method>
+<method name="setMultiChoiceModeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.AbsListView.MultiChoiceModeListener">
+</parameter>
+</method>
<method name="setOnScrollListener"
return="void"
abstract="false"
@@ -215758,6 +215901,50 @@
<parameter name="dr" type="android.graphics.drawable.Drawable">
</parameter>
</method>
+<field name="CHOICE_MODE_MULTIPLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_MULTIPLE_MODAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_SINGLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TRANSCRIPT_MODE_ALWAYS_SCROLL"
type="int"
transient="false"
@@ -215849,6 +216036,35 @@
</parameter>
</constructor>
</class>
+<interface name="AbsListView.MultiChoiceModeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.ActionMode.Callback">
+</implements>
+<method name="onItemCheckedStateChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+<parameter name="position" type="int">
+</parameter>
+<parameter name="id" type="long">
+</parameter>
+<parameter name="checked" type="boolean">
+</parameter>
+</method>
+</interface>
<interface name="AbsListView.OnScrollListener"
abstract="true"
static="true"
@@ -222296,19 +222512,6 @@
visibility="public"
>
</method>
-<method name="setAdapter"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="adapter" type="android.widget.ListAdapter">
-</parameter>
-</method>
<method name="setColumnWidth"
return="void"
abstract="false"
@@ -224611,17 +224814,6 @@
<parameter name="v" type="android.view.View">
</parameter>
</method>
-<method name="clearChoices"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="findViewTraversal"
return="android.view.View"
abstract="false"
@@ -224670,61 +224862,6 @@
visibility="public"
>
</method>
-<method name="getCheckedItemCount"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemIds"
- return="long[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemPosition"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemPositions"
- return="android.util.SparseBooleanArray"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getChoiceMode"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getDivider"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -224791,19 +224928,6 @@
visibility="public"
>
</method>
-<method name="isItemChecked"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="position" type="int">
-</parameter>
-</method>
<method name="removeFooterView"
return="boolean"
abstract="false"
@@ -224830,32 +224954,6 @@
<parameter name="v" type="android.view.View">
</parameter>
</method>
-<method name="setAdapter"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="adapter" type="android.widget.ListAdapter">
-</parameter>
-</method>
-<method name="setChoiceMode"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="choiceMode" type="int">
-</parameter>
-</method>
<method name="setDivider"
return="void"
abstract="false"
@@ -224908,21 +225006,6 @@
<parameter name="headerDividersEnabled" type="boolean">
</parameter>
</method>
-<method name="setItemChecked"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="position" type="int">
-</parameter>
-<parameter name="value" type="boolean">
-</parameter>
-</method>
<method name="setItemsCanFocus"
return="void"
abstract="false"
@@ -224936,19 +225019,6 @@
<parameter name="itemsCanFocus" type="boolean">
</parameter>
</method>
-<method name="setMultiChoiceModeListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.widget.ListView.MultiChoiceModeListener">
-</parameter>
-</method>
<method name="setSelection"
return="void"
abstract="false"
@@ -225001,50 +225071,6 @@
<parameter name="offset" type="int">
</parameter>
</method>
-<field name="CHOICE_MODE_MULTIPLE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_MULTIPLE_MODAL"
- type="int"
- transient="false"
- volatile="false"
- value="3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_NONE"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_SINGLE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<class name="ListView.FixedViewInfo"
extends="java.lang.Object"
@@ -225093,35 +225119,6 @@
>
</field>
</class>
-<interface name="ListView.MultiChoiceModeListener"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.view.ActionMode.Callback">
-</implements>
-<method name="onItemCheckedStateChanged"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="mode" type="android.view.ActionMode">
-</parameter>
-<parameter name="position" type="int">
-</parameter>
-<parameter name="id" type="long">
-</parameter>
-<parameter name="checked" type="boolean">
-</parameter>
-</method>
-</interface>
<class name="MediaController"
extends="android.widget.FrameLayout"
abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d66e98b..d5741fc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -365,7 +365,8 @@
/**
* The time when the service was first made active, either by someone
- * starting or binding to it.
+ * starting or binding to it. This
+ * is in units of {@link android.os.SystemClock#elapsedRealtime()}.
*/
public long activeSince;
@@ -387,7 +388,8 @@
/**
* The time when there was last activity in the service (either
- * explicit requests to start it or clients binding to it).
+ * explicit requests to start it or clients binding to it). This
+ * is in units of {@link android.os.SystemClock#uptimeMillis()}.
*/
public long lastActivityTime;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a699388..95f217f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -23,6 +23,7 @@
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.TimeUtils;
/**
* A class providing access to battery usage statistics, including information on
@@ -290,6 +291,11 @@
*/
public static abstract class Proc {
+ public static class ExcessiveWake {
+ public long overTime;
+ public long usedTime;
+ }
+
/**
* Returns the total time (in 1/100 sec) spent executing in user code.
*
@@ -326,6 +332,10 @@
* @see BatteryStats#getCpuSpeedSteps()
*/
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
+
+ public abstract int countExcessiveWakes();
+
+ public abstract ExcessiveWake getExcessiveWake(int i);
}
/**
@@ -421,6 +431,8 @@
public static final int STATE_BLUETOOTH_ON_FLAG = 1<<20;
public static final int STATE_AUDIO_ON_FLAG = 1<<19;
public static final int STATE_VIDEO_ON_FLAG = 1<<18;
+ public static final int STATE_WAKE_LOCK_FLAG = 1<<17;
+ public static final int STATE_SENSOR_ON_FLAG = 1<<16;
public int states;
@@ -470,6 +482,16 @@
batteryVoltage = o.batteryVoltage;
states = o.states;
}
+
+ public boolean same(HistoryItem o) {
+ return batteryLevel == o.batteryLevel
+ && batteryStatus == o.batteryStatus
+ && batteryHealth == o.batteryHealth
+ && batteryPlugType == o.batteryPlugType
+ && batteryTemperature == o.batteryTemperature
+ && batteryVoltage == o.batteryVoltage
+ && states == o.states;
+ }
}
public static final class BitDescription {
@@ -633,6 +655,8 @@
new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth"),
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio"),
new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video"),
+ new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock"),
+ new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor"),
new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness",
SCREEN_BRIGHTNESS_NAMES),
@@ -1376,7 +1400,6 @@
pw.println(getDischargeStartLevel());
pw.print(prefix); pw.print(" Discharge cycle current level: ");
pw.println(getDischargeCurrentLevel());
- } else {
pw.print(prefix); pw.println(" Device is currently plugged into power");
pw.print(prefix); pw.print(" Last discharge cycle start level: ");
pw.println(getDischargeStartLevel());
@@ -1384,6 +1407,13 @@
pw.println(getDischargeCurrentLevel());
}
pw.println(" ");
+ } else {
+ pw.print(prefix); pw.println(" Device battery use since last full charge");
+ pw.print(prefix); pw.print(" Amount discharged (lower bound): ");
+ pw.println(getLowDischargeAmountSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
+ pw.println(getHighDischargeAmountSinceCharge());
+ pw.println(" ");
}
@@ -1524,12 +1554,16 @@
long userTime;
long systemTime;
int starts;
+ int numExcessive;
userTime = ps.getUserTime(which);
systemTime = ps.getSystemTime(which);
starts = ps.getStarts(which);
+ numExcessive = which == STATS_SINCE_CHARGED
+ ? ps.countExcessiveWakes() : 0;
- if (userTime != 0 || systemTime != 0 || starts != 0) {
+ if (userTime != 0 || systemTime != 0 || starts != 0
+ || numExcessive != 0) {
sb.setLength(0);
sb.append(prefix); sb.append(" Proc ");
sb.append(ent.getKey()); sb.append(":\n");
@@ -1539,6 +1573,18 @@
sb.append(prefix); sb.append(" "); sb.append(starts);
sb.append(" proc starts");
pw.println(sb.toString());
+ for (int e=0; e<numExcessive; e++) {
+ Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e);
+ if (ew != null) {
+ pw.print(prefix); pw.print(" * Killed for wake lock use: ");
+ TimeUtils.formatDuration(ew.usedTime, pw);
+ pw.print(" over ");
+ TimeUtils.formatDuration(ew.overTime, pw);
+ pw.print(" (");
+ pw.print((ew.usedTime*100)/ew.overTime);
+ pw.println("%)");
+ }
+ }
uidActivity = true;
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 78ec638..8624467 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -62,6 +62,9 @@
/** The name of the hardware (from the kernel command line or /proc). */
public static final String HARDWARE = getString("ro.hardware");
+ /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
+ public static final String SERIAL = getString("ro.serialno");
+
/** Various version strings. */
public static class VERSION {
/**
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a9d7342..d360140 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -192,10 +192,11 @@
pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
if (mQueue != null) {
synchronized (mQueue) {
+ long now = SystemClock.uptimeMillis();
Message msg = mQueue.mMessages;
int n = 0;
while (msg != null) {
- pw.println(prefix + " Message " + n + ": " + msg);
+ pw.println(prefix + " Message " + n + ": " + msg.toString(now));
n++;
msg = msg.next;
}
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 476da1d..49b72fe 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.TimeUtils;
/**
*
@@ -366,13 +367,17 @@
}
public String toString() {
+ return toString(SystemClock.uptimeMillis());
+ }
+
+ String toString(long now) {
StringBuilder b = new StringBuilder();
b.append("{ what=");
b.append(what);
b.append(" when=");
- b.append(when);
+ TimeUtils.formatDuration(when-now, b);
if (arg1 != 0) {
b.append(" arg1=");
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 0fc70d5..b01a71d 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -24,6 +24,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.TimeZone;
import java.util.Date;
@@ -130,4 +131,128 @@
public static String getTimeZoneDatabaseVersion() {
return ZoneInfoDB.getVersion();
}
+
+ private static final int SECONDS_PER_MINUTE = 60;
+ private static final int SECONDS_PER_HOUR = 60 * 60;
+ private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+ /** @hide Just for debugging; not internationalized. */
+ public static void formatDuration(long duration, StringBuilder builder) {
+ if (duration == 0) {
+ builder.append("0");
+ return;
+ }
+ if (duration > 0) {
+ builder.append("+");
+ } else {
+ builder.append("-");
+ duration = -duration;
+ }
+
+ int millis = (int)(duration%1000);
+ int seconds = (int) Math.floor(duration / 1000);
+ int days = 0, hours = 0, minutes = 0;
+
+ if (seconds > SECONDS_PER_DAY) {
+ days = seconds / SECONDS_PER_DAY;
+ seconds -= days * SECONDS_PER_DAY;
+ }
+ if (seconds > SECONDS_PER_HOUR) {
+ hours = seconds / SECONDS_PER_HOUR;
+ seconds -= hours * SECONDS_PER_HOUR;
+ }
+ if (seconds > SECONDS_PER_MINUTE) {
+ minutes = seconds / SECONDS_PER_MINUTE;
+ seconds -= minutes * SECONDS_PER_MINUTE;
+ }
+
+ boolean doall = false;
+ if (days > 0) {
+ builder.append(days);
+ builder.append('d');
+ doall = true;
+ }
+ if (doall || hours > 0) {
+ builder.append(hours);
+ builder.append('h');
+ doall = true;
+ }
+ if (doall || minutes > 0) {
+ builder.append(minutes);
+ builder.append('m');
+ doall = true;
+ }
+ if (doall || seconds > 0) {
+ builder.append(seconds);
+ builder.append('s');
+ doall = true;
+ }
+ builder.append(millis);
+ builder.append("ms");
+ }
+
+ /** @hide Just for debugging; not internationalized. */
+ public static void formatDuration(long duration, PrintWriter pw) {
+ if (duration == 0) {
+ pw.print("0");
+ return;
+ }
+ if (duration > 0) {
+ pw.print("+");
+ } else {
+ pw.print("-");
+ duration = -duration;
+ }
+
+ int millis = (int)(duration%1000);
+ int seconds = (int) Math.floor(duration / 1000);
+ int days = 0, hours = 0, minutes = 0;
+
+ if (seconds > SECONDS_PER_DAY) {
+ days = seconds / SECONDS_PER_DAY;
+ seconds -= days * SECONDS_PER_DAY;
+ }
+ if (seconds > SECONDS_PER_HOUR) {
+ hours = seconds / SECONDS_PER_HOUR;
+ seconds -= hours * SECONDS_PER_HOUR;
+ }
+ if (seconds > SECONDS_PER_MINUTE) {
+ minutes = seconds / SECONDS_PER_MINUTE;
+ seconds -= minutes * SECONDS_PER_MINUTE;
+ }
+
+ boolean doall = false;
+ if (days > 0) {
+ pw.print(days);
+ pw.print('d');
+ doall = true;
+ }
+ if (doall || hours > 0) {
+ pw.print(hours);
+ pw.print('h');
+ doall = true;
+ }
+ if (doall || minutes > 0) {
+ pw.print(minutes);
+ pw.print('m');
+ doall = true;
+ }
+ if (doall || seconds > 0) {
+ pw.print(seconds);
+ pw.print('s');
+ doall = true;
+ }
+ pw.print(millis);
+ pw.print("ms");
+ }
+
+
+ /** @hide Just for debugging; not internationalized. */
+ public static void formatDuration(long time, long now, PrintWriter pw) {
+ if (time == 0) {
+ pw.print("--");
+ return;
+ }
+ formatDuration(time-now, pw);
+ }
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index fabe5c8..34d7935 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -27,7 +27,8 @@
/**
- * Use the WindowManager interface to create a Display object.
+ * Use {@link android.view.WindowManager#getDefaultDisplay()
+ * WindowManager.getDefaultDisplay()} to create a Display object.
* Display gives you access to some information about a particular display
* connected to the device.
*/
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e572d3d..c155dda 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -34,10 +34,16 @@
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -45,7 +51,6 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -69,6 +74,7 @@
* @attr ref android.R.styleable#AbsListView_cacheColorHint
* @attr ref android.R.styleable#AbsListView_fastScrollEnabled
* @attr ref android.R.styleable#AbsListView_smoothScrollbar
+ * @attr ref android.R.styleable#AbsListView_choiceMode
*/
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
@@ -167,6 +173,57 @@
static final int LAYOUT_MOVE_SELECTION = 6;
/**
+ * Normal list that does not indicate choices
+ */
+ public static final int CHOICE_MODE_NONE = 0;
+
+ /**
+ * The list allows up to one choice
+ */
+ public static final int CHOICE_MODE_SINGLE = 1;
+
+ /**
+ * The list allows multiple choices
+ */
+ public static final int CHOICE_MODE_MULTIPLE = 2;
+
+ /**
+ * The list allows multiple choices in a modal selection mode
+ */
+ public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
+
+ /**
+ * Controls if/how the user may choose/check items in the list
+ */
+ int mChoiceMode = CHOICE_MODE_NONE;
+
+ /**
+ * Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
+ */
+ ActionMode mChoiceActionMode;
+
+ /**
+ * Wrapper for the multiple choice mode callback; AbsListView needs to perform
+ * a few extra actions around what application code does.
+ */
+ MultiChoiceModeWrapper mMultiChoiceModeCallback;
+
+ /**
+ * Running count of how many items are currently checked
+ */
+ int mCheckedItemCount;
+
+ /**
+ * Running state of which positions are currently checked
+ */
+ SparseBooleanArray mCheckStates;
+
+ /**
+ * Running state of which IDs are currently checked
+ */
+ LongSparseArray<Boolean> mCheckedIdStates;
+
+ /**
* Controls how the next layout will happen
*/
int mLayoutMode = LAYOUT_NORMAL;
@@ -577,6 +634,8 @@
});
}
+ setChoiceMode(a.getInt(R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE));
+
a.recycle();
}
@@ -596,6 +655,311 @@
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ if (adapter != null) {
+ if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() &&
+ mCheckedIdStates == null) {
+ mCheckedIdStates = new LongSparseArray<Boolean>();
+ }
+ }
+
+ if (mCheckStates != null) {
+ mCheckStates.clear();
+ }
+
+ if (mCheckedIdStates != null) {
+ mCheckedIdStates.clear();
+ }
+ }
+
+ /**
+ * Returns the number of items currently selected. This will only be valid
+ * if the choice mode is not {@link #CHOICE_MODE_NONE} (default).
+ *
+ * <p>To determine the specific items that are currently selected, use one of
+ * the <code>getChecked*</code> methods.
+ *
+ * @return The number of items currently selected
+ *
+ * @see #getCheckedItemPosition()
+ * @see #getCheckedItemPositions()
+ * @see #getCheckedItemIds()
+ */
+ public int getCheckedItemCount() {
+ return mCheckedItemCount;
+ }
+
+ /**
+ * Returns the checked state of the specified position. The result is only
+ * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
+ * or {@link #CHOICE_MODE_MULTIPLE}.
+ *
+ * @param position The item whose checked state to return
+ * @return The item's checked state or <code>false</code> if choice mode
+ * is invalid
+ *
+ * @see #setChoiceMode(int)
+ */
+ public boolean isItemChecked(int position) {
+ if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
+ return mCheckStates.get(position);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the currently checked item. The result is only valid if the choice
+ * mode has been set to {@link #CHOICE_MODE_SINGLE}.
+ *
+ * @return The position of the currently checked item or
+ * {@link #INVALID_POSITION} if nothing is selected
+ *
+ * @see #setChoiceMode(int)
+ */
+ public int getCheckedItemPosition() {
+ if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
+ return mCheckStates.keyAt(0);
+ }
+
+ return INVALID_POSITION;
+ }
+
+ /**
+ * Returns the set of checked items in the list. The result is only valid if
+ * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
+ *
+ * @return A SparseBooleanArray which will return true for each call to
+ * get(int position) where position is a position in the list,
+ * or <code>null</code> if the choice mode is set to
+ * {@link #CHOICE_MODE_NONE}.
+ */
+ public SparseBooleanArray getCheckedItemPositions() {
+ if (mChoiceMode != CHOICE_MODE_NONE) {
+ return mCheckStates;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the set of checked items ids. The result is only valid if the
+ * choice mode has not been set to {@link #CHOICE_MODE_NONE} and the adapter
+ * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
+ *
+ * @return A new array which contains the id of each checked item in the
+ * list.
+ */
+ public long[] getCheckedItemIds() {
+ if (mChoiceMode == CHOICE_MODE_NONE || mCheckedIdStates == null || mAdapter == null) {
+ return new long[0];
+ }
+
+ final LongSparseArray<Boolean> idStates = mCheckedIdStates;
+ final int count = idStates.size();
+ final long[] ids = new long[count];
+
+ for (int i = 0; i < count; i++) {
+ ids[i] = idStates.keyAt(i);
+ }
+
+ return ids;
+ }
+
+ /**
+ * Clear any choices previously set
+ */
+ public void clearChoices() {
+ if (mCheckStates != null) {
+ mCheckStates.clear();
+ }
+ if (mCheckedIdStates != null) {
+ mCheckedIdStates.clear();
+ }
+ mCheckedItemCount = 0;
+ }
+
+ /**
+ * Sets the checked state of the specified position. The is only valid if
+ * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
+ * {@link #CHOICE_MODE_MULTIPLE}.
+ *
+ * @param position The item whose checked state is to be checked
+ * @param value The new checked state for the item
+ */
+ public void setItemChecked(int position, boolean value) {
+ if (mChoiceMode == CHOICE_MODE_NONE) {
+ return;
+ }
+
+ // Start selection mode if needed. We don't need to if we're unchecking something.
+ if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+ mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
+ }
+
+ if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+ boolean oldValue = mCheckStates.get(position);
+ mCheckStates.put(position, value);
+ if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+ if (value) {
+ mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ } else {
+ mCheckedIdStates.delete(mAdapter.getItemId(position));
+ }
+ }
+ if (oldValue != value) {
+ if (value) {
+ mCheckedItemCount++;
+ } else {
+ mCheckedItemCount--;
+ }
+ }
+ if (mChoiceActionMode != null) {
+ final long id = mAdapter.getItemId(position);
+ mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
+ position, id, value);
+ }
+ } else {
+ boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
+ // Clear all values if we're checking something, or unchecking the currently
+ // selected item
+ if (value || isItemChecked(position)) {
+ mCheckStates.clear();
+ if (updateIds) {
+ mCheckedIdStates.clear();
+ }
+ }
+ // this may end up selecting the value we just cleared but this way
+ // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
+ if (value) {
+ mCheckStates.put(position, true);
+ if (updateIds) {
+ mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ }
+ mCheckedItemCount = 1;
+ } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
+ mCheckedItemCount = 0;
+ }
+ }
+
+ // Do not generate a data change while we are in the layout phase
+ if (!mInLayout && !mBlockLayoutRequests) {
+ mDataChanged = true;
+ rememberSyncState();
+ requestLayout();
+ }
+ }
+
+ @Override
+ public boolean performItemClick(View view, int position, long id) {
+ boolean handled = false;
+
+ if (mChoiceMode != CHOICE_MODE_NONE) {
+ handled = true;
+
+ if (mChoiceMode == CHOICE_MODE_MULTIPLE ||
+ (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null)) {
+ boolean newValue = !mCheckStates.get(position, false);
+ mCheckStates.put(position, newValue);
+ if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+ if (newValue) {
+ mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ } else {
+ mCheckedIdStates.delete(mAdapter.getItemId(position));
+ }
+ }
+ if (newValue) {
+ mCheckedItemCount++;
+ } else {
+ mCheckedItemCount--;
+ }
+ if (mChoiceActionMode != null) {
+ mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
+ position, id, newValue);
+ }
+ } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
+ boolean newValue = !mCheckStates.get(position, false);
+ if (newValue) {
+ mCheckStates.clear();
+ mCheckStates.put(position, true);
+ if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+ mCheckedIdStates.clear();
+ mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ }
+ mCheckedItemCount = 1;
+ } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
+ mCheckedItemCount = 0;
+ }
+ }
+
+ mDataChanged = true;
+ rememberSyncState();
+ requestLayout();
+ }
+
+ handled |= super.performItemClick(view, position, id);
+
+ return handled;
+ }
+
+ /**
+ * @see #setChoiceMode(int)
+ *
+ * @return The current choice mode
+ */
+ public int getChoiceMode() {
+ return mChoiceMode;
+ }
+
+ /**
+ * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
+ * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
+ * List allows up to one item to be in a chosen state. By setting the choiceMode to
+ * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
+ *
+ * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
+ * {@link #CHOICE_MODE_MULTIPLE}
+ */
+ public void setChoiceMode(int choiceMode) {
+ mChoiceMode = choiceMode;
+ if (mChoiceActionMode != null) {
+ mChoiceActionMode.finish();
+ mChoiceActionMode = null;
+ }
+ if (mChoiceMode != CHOICE_MODE_NONE) {
+ if (mCheckStates == null) {
+ mCheckStates = new SparseBooleanArray();
+ }
+ if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
+ mCheckedIdStates = new LongSparseArray<Boolean>();
+ }
+ // Modal multi-choice mode only has choices when the mode is active. Clear them.
+ if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+ clearChoices();
+ setLongClickable(true);
+ }
+ }
+ }
+
+ /**
+ * Set a {@link MultiChoiceModeListener} that will manage the lifecycle of the
+ * selection {@link ActionMode}. Only used when the choice mode is set to
+ * {@link #CHOICE_MODE_MULTIPLE_MODAL}.
+ *
+ * @param listener Listener that will manage the selection mode
+ *
+ * @see #setChoiceMode(int)
+ */
+ public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
+ if (mMultiChoiceModeCallback == null) {
+ mMultiChoiceModeCallback = new MultiChoiceModeWrapper();
+ }
+ mMultiChoiceModeCallback.setWrapped(listener);
+ }
+
+ /**
* Enables fast scrolling by letting the user quickly scroll through lists by
* dragging the fast scroll thumb. The adapter attached to the list may want
* to implement {@link SectionIndexer} if it wishes to display alphabet preview and
@@ -813,6 +1177,8 @@
int position;
int height;
String filter;
+ SparseBooleanArray checkState;
+ LongSparseArray<Boolean> checkIdState;
/**
* Constructor called from {@link AbsListView#onSaveInstanceState()}
@@ -832,6 +1198,13 @@
position = in.readInt();
height = in.readInt();
filter = in.readString();
+ checkState = in.readSparseBooleanArray();
+ long[] idState = in.createLongArray();
+
+ if (idState.length > 0) {
+ checkIdState = new LongSparseArray<Boolean>();
+ checkIdState.setValues(idState, Boolean.TRUE);
+ }
}
@Override
@@ -843,6 +1216,8 @@
out.writeInt(position);
out.writeInt(height);
out.writeString(filter);
+ out.writeSparseBooleanArray(checkState);
+ out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
}
@Override
@@ -854,7 +1229,8 @@
+ " viewTop=" + viewTop
+ " position=" + position
+ " height=" + height
- + " filter=" + filter + "}";
+ + " filter=" + filter
+ + " checkState=" + checkState + "}";
}
public static final Parcelable.Creator<SavedState> CREATOR
@@ -918,6 +1294,9 @@
}
}
+ ss.checkState = mCheckStates;
+ ss.checkIdState = mCheckedIdStates;
+
return ss;
}
@@ -949,6 +1328,14 @@
setFilterText(ss.filter);
+ if (ss.checkState != null) {
+ mCheckStates = ss.checkState;
+ }
+
+ if (ss.checkIdState != null) {
+ mCheckedIdStates = ss.checkIdState;
+ }
+
requestLayout();
}
@@ -1774,8 +2161,19 @@
boolean performLongPress(final View child,
final int longPressPosition, final long longPressId) {
- boolean handled = false;
+ // CHOICE_MODE_MULTIPLE_MODAL takes over long press.
+ if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+ if (mChoiceActionMode == null) {
+ mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
+ setItemChecked(longPressPosition, true);
+ }
+ // TODO Should we select the long pressed item if we were already in
+ // selection mode? (i.e. treat it like an item click?)
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ return true;
+ }
+ boolean handled = false;
if (mOnItemLongClickListener != null) {
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
longPressPosition, longPressId);
@@ -3991,6 +4389,75 @@
}
/**
+ * A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
+ * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
+ * {@link #onItemCheckedStateChanged(ActionMode, int, long, boolean)} events when the user
+ * selects and deselects list items.
+ */
+ public interface MultiChoiceModeListener extends ActionMode.Callback {
+ /**
+ * Called when an item is checked or unchecked during selection mode.
+ *
+ * @param mode The {@link ActionMode} providing the selection mode
+ * @param position Adapter position of the item that was checked or unchecked
+ * @param id Adapter ID of the item that was checked or unchecked
+ * @param checked <code>true</code> if the item is now checked, <code>false</code>
+ * if the item is now unchecked.
+ */
+ public void onItemCheckedStateChanged(ActionMode mode,
+ int position, long id, boolean checked);
+ }
+
+ class MultiChoiceModeWrapper implements MultiChoiceModeListener {
+ private MultiChoiceModeListener mWrapped;
+
+ public void setWrapped(MultiChoiceModeListener wrapped) {
+ mWrapped = wrapped;
+ }
+
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ if (mWrapped.onCreateActionMode(mode, menu)) {
+ // Initialize checked graphic state?
+ setLongClickable(false);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return mWrapped.onPrepareActionMode(mode, menu);
+ }
+
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ return mWrapped.onActionItemClicked(mode, item);
+ }
+
+ public void onDestroyActionMode(ActionMode mode) {
+ mWrapped.onDestroyActionMode(mode);
+ mChoiceActionMode = null;
+
+ // Ending selection mode means deselecting everything.
+ clearChoices();
+
+ mDataChanged = true;
+ rememberSyncState();
+ requestLayout();
+
+ setLongClickable(true);
+ }
+
+ public void onItemCheckedStateChanged(ActionMode mode,
+ int position, long id, boolean checked) {
+ mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
+
+ // If there are no items selected we no longer need the selection mode.
+ if (getCheckedItemCount() == 0) {
+ mode.finish();
+ }
+ }
+ }
+
+ /**
* AbsListView extends LayoutParams to provide a place to hold the view type.
*/
public static class LayoutParams extends ViewGroup.LayoutParams {
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a5b3ed5..ea767f6 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -104,6 +104,26 @@
a.recycle();
}
+ /**
+ * Set how the user may select items from the grid.
+ *
+ * <p>GridView only supports {@link AbsListView#CHOICE_MODE_NONE} and
+ * {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}. Attempting to set an unsupported choice
+ * mode will throw an UnsupportedOperationException.
+ */
+ @Override
+ public void setChoiceMode(int choiceMode) {
+ switch (choiceMode) {
+ case CHOICE_MODE_NONE:
+ case CHOICE_MODE_MULTIPLE_MODAL:
+ super.setChoiceMode(choiceMode);
+ break;
+
+ default:
+ throw new UnsupportedOperationException("Unsupported choice mode " + choiceMode);
+ }
+ }
+
@Override
public ListAdapter getAdapter() {
return mAdapter;
@@ -136,7 +156,10 @@
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
-
+
+ // AbsListView#setAdapter will update choice mode states.
+ super.setAdapter(adapter);
+
if (mAdapter != null) {
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
@@ -1312,6 +1335,12 @@
child.setPressed(isPressed);
}
+ if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
+ if (child instanceof Checkable) {
+ ((Checkable) child).setChecked(mCheckStates.get(position));
+ }
+ }
+
if (needToMeasure) {
int childHeightSpec = ViewGroup.getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 32a9146..e30d4c8 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -53,6 +53,8 @@
* within a larger container.
*
* <p>HorizontalScrollView only supports horizontal scrolling.
+ *
+ * @attr ref android.R.styleable#HorizontalScrollView_fillViewport
*/
public class HorizontalScrollView extends FrameLayout {
private static final int ANIMATED_SCROLL_GAP = ScrollView.ANIMATED_SCROLL_GAP;
@@ -248,20 +250,25 @@
}
/**
- * Indicates whether this ScrollView's content is stretched to fill the viewport.
+ * Indicates whether this HorizontalScrollView's content is stretched to
+ * fill the viewport.
*
* @return True if the content fills the viewport, false otherwise.
+ *
+ * @attr ref android.R.styleable#HorizontalScrollView_fillViewport
*/
public boolean isFillViewport() {
return mFillViewport;
}
/**
- * Indicates this ScrollView whether it should stretch its content width to fill
- * the viewport or not.
+ * Indicates this HorizontalScrollView whether it should stretch its content width
+ * to fill the viewport or not.
*
* @param fillViewport True to stretch the content's width to the viewport's
* boundaries, false otherwise.
+ *
+ * @attr ref android.R.styleable#HorizontalScrollView_fillViewport
*/
public void setFillViewport(boolean fillViewport) {
if (fillViewport != mFillViewport) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 0d0a1ba..de7157b 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -28,17 +28,10 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.util.AttributeSet;
-import android.util.LongSparseArray;
import android.util.SparseBooleanArray;
-import android.view.ActionMode;
import android.view.FocusFinder;
-import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
@@ -67,7 +60,6 @@
* @attr ref android.R.styleable#ListView_entries
* @attr ref android.R.styleable#ListView_divider
* @attr ref android.R.styleable#ListView_dividerHeight
- * @attr ref android.R.styleable#ListView_choiceMode
* @attr ref android.R.styleable#ListView_headerDividersEnabled
* @attr ref android.R.styleable#ListView_footerDividersEnabled
*/
@@ -79,26 +71,6 @@
static final int NO_POSITION = -1;
/**
- * Normal list that does not indicate choices
- */
- public static final int CHOICE_MODE_NONE = 0;
-
- /**
- * The list allows up to one choice
- */
- public static final int CHOICE_MODE_SINGLE = 1;
-
- /**
- * The list allows multiple choices
- */
- public static final int CHOICE_MODE_MULTIPLE = 2;
-
- /**
- * The list allows multiple choices in a modal selection mode
- */
- public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
-
- /**
* When arrow scrolling, ListView will never scroll more than this factor
* times the height of the list.
*/
@@ -141,11 +113,6 @@
private boolean mItemsCanFocus = false;
- private int mChoiceMode = CHOICE_MODE_NONE;
-
- private SparseBooleanArray mCheckStates;
- private LongSparseArray<Boolean> mCheckedIdStates;
-
// used for temporary calculations.
private final Rect mTempRect = new Rect();
private Paint mDividerPaint;
@@ -157,11 +124,6 @@
// Keeps focused children visible through resizes
private FocusSelector mFocusSelector;
- // Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
- private ActionMode mChoiceActionMode;
- private MultiChoiceModeWrapper mMultiChoiceModeCallback;
- private int mCheckedItemCount;
-
public ListView(Context context) {
this(context, null);
}
@@ -196,8 +158,6 @@
setDividerHeight(dividerHeight);
}
- setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE));
-
mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
@@ -457,6 +417,10 @@
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
+
+ // AbsListView#setAdapter will update choice mode states.
+ super.setAdapter(adapter);
+
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
@@ -481,13 +445,6 @@
// Nothing selected
checkSelectionChanged();
}
-
- if (mChoiceMode != CHOICE_MODE_NONE &&
- mAdapter.hasStableIds() &&
- mCheckedIdStates == null) {
- mCheckedIdStates = new LongSparseArray<Boolean>();
- }
-
} else {
mAreAllItemsSelectable = true;
checkFocus();
@@ -495,14 +452,6 @@
checkSelectionChanged();
}
- if (mCheckStates != null) {
- mCheckStates.clear();
- }
-
- if (mCheckedIdStates != null) {
- mCheckedIdStates.clear();
- }
-
requestLayout();
}
@@ -3360,270 +3309,6 @@
}
/**
- * @see #setChoiceMode(int)
- *
- * @return The current choice mode
- */
- public int getChoiceMode() {
- return mChoiceMode;
- }
-
- /**
- * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
- * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
- * List allows up to one item to be in a chosen state. By setting the choiceMode to
- * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
- *
- * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
- * {@link #CHOICE_MODE_MULTIPLE}
- */
- public void setChoiceMode(int choiceMode) {
- mChoiceMode = choiceMode;
- if (mChoiceActionMode != null) {
- mChoiceActionMode.finish();
- mChoiceActionMode = null;
- }
- if (mChoiceMode != CHOICE_MODE_NONE) {
- if (mCheckStates == null) {
- mCheckStates = new SparseBooleanArray();
- }
- if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
- mCheckedIdStates = new LongSparseArray<Boolean>();
- }
- // Modal multi-choice mode only has choices when the mode is active. Clear them.
- if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
- clearChoices();
- setLongClickable(true);
- }
- }
- }
-
- /**
- * Set a {@link MultiChoiceModeListener} that will manage the lifecycle of the
- * selection {@link ActionMode}. Only used when the choice mode is set to
- * {@link #CHOICE_MODE_MULTIPLE_MODAL}.
- *
- * @param listener Listener that will manage the selection mode
- *
- * @see #setChoiceMode(int)
- */
- public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
- if (mMultiChoiceModeCallback == null) {
- mMultiChoiceModeCallback = new MultiChoiceModeWrapper();
- }
- mMultiChoiceModeCallback.setWrapped(listener);
- }
-
- @Override
- boolean performLongPress(final View child,
- final int longPressPosition, final long longPressId) {
- boolean handled = false;
- if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
- handled = true;
- if (mChoiceActionMode == null) {
- mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
- setItemChecked(longPressPosition, true);
- }
- // TODO Should we select the long pressed item if we were already in
- // selection mode? (i.e. treat it like an item click?)
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
- return handled | super.performLongPress(child, longPressPosition, longPressId);
- }
-
- @Override
- public boolean performItemClick(View view, int position, long id) {
- boolean handled = false;
-
- if (mChoiceMode != CHOICE_MODE_NONE) {
- handled = true;
-
- if (mChoiceMode == CHOICE_MODE_MULTIPLE ||
- (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null)) {
- boolean newValue = !mCheckStates.get(position, false);
- mCheckStates.put(position, newValue);
- if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
- if (newValue) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
- } else {
- mCheckedIdStates.delete(mAdapter.getItemId(position));
- }
- }
- if (newValue) {
- mCheckedItemCount++;
- } else {
- mCheckedItemCount--;
- }
- if (mChoiceActionMode != null) {
- mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
- position, id, newValue);
- }
- } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
- boolean newValue = !mCheckStates.get(position, false);
- if (newValue) {
- mCheckStates.clear();
- mCheckStates.put(position, true);
- if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
- mCheckedIdStates.clear();
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
- }
- mCheckedItemCount = 1;
- } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
- mCheckedItemCount = 0;
- }
- }
-
- mDataChanged = true;
- rememberSyncState();
- requestLayout();
- }
-
- handled |= super.performItemClick(view, position, id);
-
- return handled;
- }
-
- /**
- * Sets the checked state of the specified position. The is only valid if
- * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
- * {@link #CHOICE_MODE_MULTIPLE}.
- *
- * @param position The item whose checked state is to be checked
- * @param value The new checked state for the item
- */
- public void setItemChecked(int position, boolean value) {
- if (mChoiceMode == CHOICE_MODE_NONE) {
- return;
- }
-
- // Start selection mode if needed. We don't need to if we're unchecking something.
- if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
- mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
- }
-
- if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
- boolean oldValue = mCheckStates.get(position);
- mCheckStates.put(position, value);
- if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
- if (value) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
- } else {
- mCheckedIdStates.delete(mAdapter.getItemId(position));
- }
- }
- if (oldValue != value) {
- if (value) {
- mCheckedItemCount++;
- } else {
- mCheckedItemCount--;
- }
- }
- if (mChoiceActionMode != null) {
- final long id = mAdapter.getItemId(position);
- mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
- position, id, value);
- }
- } else {
- boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
- // Clear all values if we're checking something, or unchecking the currently
- // selected item
- if (value || isItemChecked(position)) {
- mCheckStates.clear();
- if (updateIds) {
- mCheckedIdStates.clear();
- }
- }
- // this may end up selecting the value we just cleared but this way
- // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
- if (value) {
- mCheckStates.put(position, true);
- if (updateIds) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
- }
- mCheckedItemCount = 1;
- } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
- mCheckedItemCount = 0;
- }
- }
-
- // Do not generate a data change while we are in the layout phase
- if (!mInLayout && !mBlockLayoutRequests) {
- mDataChanged = true;
- rememberSyncState();
- requestLayout();
- }
- }
-
- /**
- * Returns the number of items currently selected. This will only be valid
- * if the choice mode is not {@link #CHOICE_MODE_NONE} (default).
- *
- * <p>To determine the specific items that are currently selected, use one of
- * the <code>getChecked*</code> methods.
- *
- * @return The number of items currently selected
- *
- * @see #getCheckedItemPosition()
- * @see #getCheckedItemPositions()
- * @see #getCheckedItemIds()
- */
- public int getCheckedItemCount() {
- return mCheckedItemCount;
- }
-
- /**
- * Returns the checked state of the specified position. The result is only
- * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
- * or {@link #CHOICE_MODE_MULTIPLE}.
- *
- * @param position The item whose checked state to return
- * @return The item's checked state or <code>false</code> if choice mode
- * is invalid
- *
- * @see #setChoiceMode(int)
- */
- public boolean isItemChecked(int position) {
- if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
- return mCheckStates.get(position);
- }
-
- return false;
- }
-
- /**
- * Returns the currently checked item. The result is only valid if the choice
- * mode has been set to {@link #CHOICE_MODE_SINGLE}.
- *
- * @return The position of the currently checked item or
- * {@link #INVALID_POSITION} if nothing is selected
- *
- * @see #setChoiceMode(int)
- */
- public int getCheckedItemPosition() {
- if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
- return mCheckStates.keyAt(0);
- }
-
- return INVALID_POSITION;
- }
-
- /**
- * Returns the set of checked items in the list. The result is only valid if
- * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
- *
- * @return A SparseBooleanArray which will return true for each call to
- * get(int position) where position is a position in the list,
- * or <code>null</code> if the choice mode is set to
- * {@link #CHOICE_MODE_NONE}.
- */
- public SparseBooleanArray getCheckedItemPositions() {
- if (mChoiceMode != CHOICE_MODE_NONE) {
- return mCheckStates;
- }
- return null;
- }
-
- /**
* Returns the set of checked items ids. The result is only valid if the
* choice mode has not been set to {@link #CHOICE_MODE_NONE}.
*
@@ -3667,185 +3352,4 @@
}
return new long[0];
}
-
- /**
- * Returns the set of checked items ids. The result is only valid if the
- * choice mode has not been set to {@link #CHOICE_MODE_NONE} and the adapter
- * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
- *
- * @return A new array which contains the id of each checked item in the
- * list.
- */
- public long[] getCheckedItemIds() {
- if (mChoiceMode == CHOICE_MODE_NONE || mCheckedIdStates == null || mAdapter == null) {
- return new long[0];
- }
-
- final LongSparseArray<Boolean> idStates = mCheckedIdStates;
- final int count = idStates.size();
- final long[] ids = new long[count];
-
- for (int i = 0; i < count; i++) {
- ids[i] = idStates.keyAt(i);
- }
-
- return ids;
- }
-
- /**
- * Clear any choices previously set
- */
- public void clearChoices() {
- if (mCheckStates != null) {
- mCheckStates.clear();
- }
- if (mCheckedIdStates != null) {
- mCheckedIdStates.clear();
- }
- mCheckedItemCount = 0;
- }
-
- /**
- * A MultiChoiceModeListener receives events for {@link ListView#CHOICE_MODE_MULTIPLE_MODAL}.
- * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
- * {@link #onItemCheckedStateChanged(ActionMode, int, long, boolean)} events when the user
- * selects and deselects list items.
- */
- public interface MultiChoiceModeListener extends ActionMode.Callback {
- /**
- * Called when an item is checked or unchecked during selection mode.
- *
- * @param mode The {@link ActionMode} providing the selection mode
- * @param position Adapter position of the item that was checked or unchecked
- * @param id Adapter ID of the item that was checked or unchecked
- * @param checked <code>true</code> if the item is now checked, <code>false</code>
- * if the item is now unchecked.
- */
- public void onItemCheckedStateChanged(ActionMode mode,
- int position, long id, boolean checked);
- }
-
- private class MultiChoiceModeWrapper implements MultiChoiceModeListener {
- private MultiChoiceModeListener mWrapped;
-
- public void setWrapped(MultiChoiceModeListener wrapped) {
- mWrapped = wrapped;
- }
-
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- if (mWrapped.onCreateActionMode(mode, menu)) {
- // Initialize checked graphic state?
- setLongClickable(false);
- return true;
- }
- return false;
- }
-
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return mWrapped.onPrepareActionMode(mode, menu);
- }
-
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- return mWrapped.onActionItemClicked(mode, item);
- }
-
- public void onDestroyActionMode(ActionMode mode) {
- mWrapped.onDestroyActionMode(mode);
- mChoiceActionMode = null;
-
- // Ending selection mode means deselecting everything.
- clearChoices();
-
- mDataChanged = true;
- rememberSyncState();
- requestLayout();
-
- setLongClickable(true);
- }
-
- public void onItemCheckedStateChanged(ActionMode mode,
- int position, long id, boolean checked) {
- mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
-
- // If there are no items selected we no longer need the selection mode.
- if (getCheckedItemCount() == 0) {
- mode.finish();
- }
- }
- }
-
- static class SavedState extends BaseSavedState {
- SparseBooleanArray checkState;
- LongSparseArray<Boolean> checkIdState;
-
- /**
- * Constructor called from {@link ListView#onSaveInstanceState()}
- */
- SavedState(Parcelable superState, SparseBooleanArray checkState,
- LongSparseArray<Boolean> checkIdState) {
- super(superState);
- this.checkState = checkState;
- this.checkIdState = checkIdState;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- checkState = in.readSparseBooleanArray();
- long[] idState = in.createLongArray();
-
- if (idState.length > 0) {
- checkIdState = new LongSparseArray<Boolean>();
- checkIdState.setValues(idState, Boolean.TRUE);
- }
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeSparseBooleanArray(checkState);
- out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
- }
-
- @Override
- public String toString() {
- return "ListView.SavedState{"
- + Integer.toHexString(System.identityHashCode(this))
- + " checkState=" + checkState + "}";
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR
- = new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState, mCheckStates, mCheckedIdStates);
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
-
- super.onRestoreInstanceState(ss.getSuperState());
-
- if (ss.checkState != null) {
- mCheckStates = ss.checkState;
- }
-
- if (ss.checkIdState != null) {
- mCheckedIdStates = ss.checkIdState;
- }
- }
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 959e982..eb527eb 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -49,6 +49,8 @@
* within a larger container.
*
* <p>ScrollView only supports vertical scrolling.
+ *
+ * @attr ref android.R.styleable#ScrollView_fillViewport
*/
public class ScrollView extends FrameLayout {
static final int ANIMATED_SCROLL_GAP = 250;
@@ -247,6 +249,8 @@
* Indicates whether this ScrollView's content is stretched to fill the viewport.
*
* @return True if the content fills the viewport, false otherwise.
+ *
+ * @attr ref android.R.styleable#ScrollView_fillViewport
*/
public boolean isFillViewport() {
return mFillViewport;
@@ -258,6 +262,8 @@
*
* @param fillViewport True to stretch the content's height to the viewport's
* boundaries, false otherwise.
+ *
+ * @attr ref android.R.styleable#ScrollView_fillViewport
*/
public void setFillViewport(boolean fillViewport) {
if (fillViewport != mFillViewport) {
@@ -566,16 +572,6 @@
}
}
- private int getScrollRange() {
- int scrollRange = 0;
- if (getChildCount() > 0) {
- View child = getChildAt(0);
- scrollRange = Math.max(0,
- child.getHeight() - getHeight() - mPaddingBottom - mPaddingTop);
- }
- return scrollRange;
- }
-
/**
* <p>
* Finds the next focusable component that fits in this View's bounds
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index d040d3f..1620778 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -22,8 +22,8 @@
interface IBatteryStats {
byte[] getStatistics();
- void noteStartWakelock(int uid, String name, int type);
- void noteStopWakelock(int uid, String name, int type);
+ void noteStartWakelock(int uid, int pid, String name, int type);
+ void noteStopWakelock(int uid, int pid, String name, int type);
/* DO NOT CHANGE the position of noteStartSensor without updating
SensorService.cpp */
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index ce5959d..e1c5564 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,17 +18,31 @@
import android.app.Activity;
import android.os.Bundle;
+import android.view.MotionEvent;
import android.widget.ImageView;
+import android.widget.Toast;
public class PlatLogoActivity extends Activity {
+ Toast mToast;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mToast = Toast.makeText(this, "Zombie art by Jack Larson", Toast.LENGTH_SHORT);
+
ImageView content = new ImageView(this);
content.setImageResource(com.android.internal.R.drawable.platlogo);
content.setScaleType(ImageView.ScaleType.FIT_CENTER);
setContentView(content);
}
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
+ mToast.show();
+ }
+ return super.dispatchTouchEvent(ev);
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 13b3033..a70dbf6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -63,7 +63,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 49;
+ private static final int VERSION = 50;
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 1000;
@@ -107,6 +107,7 @@
int mNumHistoryItems;
HistoryItem mHistory;
HistoryItem mHistoryEnd;
+ HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
final HistoryItem mHistoryCur = new HistoryItem();
@@ -451,7 +452,7 @@
* Clear state of this timer. Returns true if the timer is inactive
* so can be completely dropped.
*/
- boolean reset(boolean detachIfReset) {
+ boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
@@ -713,8 +714,8 @@
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
- boolean reset(boolean detachIfReset) {
- super.reset(detachIfReset);
+ boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
+ super.reset(stats, detachIfReset);
setStale();
return true;
}
@@ -749,7 +750,7 @@
long mUpdateTime;
/**
- * The total time at which the timer was acquired, to determine if
+ * The total time at which the timer was acquired, to determine if it
* was actually held for an interesting duration.
*/
long mAcquireTime;
@@ -890,9 +891,14 @@
return mCount;
}
- boolean reset(boolean detachIfReset) {
+ boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
- super.reset(canDetach && detachIfReset);
+ super.reset(stats, canDetach && detachIfReset);
+ if (mNesting > 0) {
+ mUpdateTime = stats.getBatteryRealtimeLocked(
+ SystemClock.elapsedRealtime() * 1000);
+ }
+ mAcquireTime = mTotalTime;
return canDetach;
}
@@ -1115,6 +1121,26 @@
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
+
+ // If the current time is basically the same as the last time,
+ // just collapse into one record.
+ if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
+ && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) {
+ // If the current is the same as the one before, then we no
+ // longer need the entry.
+ if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
+ && mHistoryLastEnd.same(mHistoryCur)) {
+ mHistoryLastEnd.next = null;
+ mHistoryEnd.next = mHistoryCache;
+ mHistoryCache = mHistoryEnd;
+ mHistoryEnd = mHistoryLastEnd;
+ mHistoryLastEnd = null;
+ } else {
+ mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
+ }
+ return;
+ }
+
if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
// Once we've reached the maximum number of items, we only
// record changes to the battery level.
@@ -1123,6 +1149,7 @@
return;
}
}
+
addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
}
@@ -1141,6 +1168,7 @@
void addHistoryRecordLocked(HistoryItem rec) {
mNumHistoryItems++;
rec.next = null;
+ mHistoryLastEnd = mHistoryEnd;
if (mHistoryEnd != null) {
mHistoryEnd.next = rec;
mHistoryEnd = rec;
@@ -1153,7 +1181,7 @@
if (mHistory != null) {
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistory;
- mHistory = mHistoryEnd = null;
+ mHistory = mHistoryLastEnd = mHistoryEnd = null;
}
mNumHistoryItems = 0;
mHistoryBaseTime = 0;
@@ -1211,6 +1239,89 @@
mBluetoothPingStart = -1;
}
+ int mWakeLockNesting;
+
+ public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+ if (type == WAKE_TYPE_PARTIAL) {
+ // Only care about partial wake locks, since full wake locks
+ // will be canceled when the user puts the screen to sleep.
+ if (mWakeLockNesting == 0) {
+ mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ }
+ mWakeLockNesting++;
+ }
+ if (uid >= 0) {
+ getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
+ }
+ }
+
+ public void noteStopWakeLocked(int uid, int pid, String name, int type) {
+ if (type == WAKE_TYPE_PARTIAL) {
+ mWakeLockNesting--;
+ if (mWakeLockNesting == 0) {
+ mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ }
+ }
+ if (uid >= 0) {
+ getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
+ }
+ }
+
+ public void noteProcessDiedLocked(int uid, int pid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.mPids.remove(pid);
+ }
+ }
+
+ public long getProcessWakeTime(int uid, int pid, long realtime) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ Uid.Pid p = u.mPids.get(pid);
+ if (p != null) {
+ return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
+ }
+ }
+ return 0;
+ }
+
+ public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.reportExcessiveWakeLocked(proc, overTime, usedTime);
+ }
+ }
+
+ int mSensorNesting;
+
+ public void noteStartSensorLocked(int uid, int sensor) {
+ if (mSensorNesting == 0) {
+ mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ }
+ mSensorNesting++;
+ getUidStatsLocked(uid).noteStartSensor(sensor);
+ }
+
+ public void noteStopSensorLocked(int uid, int sensor) {
+ mSensorNesting--;
+ if (mSensorNesting == 0) {
+ mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ }
+ getUidStatsLocked(uid).noteStopSensor(sensor);
+ }
+
int mGpsNesting;
public void noteStartGpsLocked(int uid) {
@@ -1246,6 +1357,10 @@
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
}
+
+ // Fake a wake lock, so we consider the device waked as long
+ // as the screen is on.
+ noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
}
}
@@ -1260,6 +1375,8 @@
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
}
+
+ noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
}
}
@@ -1800,6 +1917,11 @@
*/
final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
+ /**
+ * The transient wake stats we have collected for this uid's pids.
+ */
+ final SparseArray<Pid> mPids = new SparseArray<Pid>();
+
public Uid(int uid) {
mUid = uid;
mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
@@ -2083,27 +2205,27 @@
boolean active = false;
if (mWifiTurnedOnTimer != null) {
- active |= !mWifiTurnedOnTimer.reset(false);
+ active |= !mWifiTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiTurnedOn;
}
if (mFullWifiLockTimer != null) {
- active |= !mFullWifiLockTimer.reset(false);
+ active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mFullWifiLockOut;
}
if (mScanWifiLockTimer != null) {
- active |= !mScanWifiLockTimer.reset(false);
+ active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
active |= mScanWifiLockOut;
}
if (mWifiMulticastTimer != null) {
- active |= !mWifiMulticastTimer.reset(false);
+ active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiMulticastEnabled;
}
if (mAudioTurnedOnTimer != null) {
- active |= !mAudioTurnedOnTimer.reset(false);
+ active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mAudioTurnedOn;
}
if (mVideoTurnedOnTimer != null) {
- active |= !mVideoTurnedOnTimer.reset(false);
+ active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mVideoTurnedOn;
}
@@ -2148,6 +2270,14 @@
}
mProcessStats.clear();
}
+ if (mPids.size() > 0) {
+ for (int i=0; !active && i<mPids.size(); i++) {
+ Pid pid = mPids.valueAt(i);
+ if (pid.mWakeStart != 0) {
+ active = true;
+ }
+ }
+ }
if (mPackageStats.size() > 0) {
Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
while (it.hasNext()) {
@@ -2166,6 +2296,8 @@
mPackageStats.clear();
}
+ mPids.clear();
+
if (!active) {
if (mWifiTurnedOnTimer != null) {
mWifiTurnedOnTimer.detach();
@@ -2414,13 +2546,13 @@
boolean reset() {
boolean wlactive = false;
if (mTimerFull != null) {
- wlactive |= !mTimerFull.reset(false);
+ wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
}
if (mTimerPartial != null) {
- wlactive |= !mTimerPartial.reset(false);
+ wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
}
if (mTimerWindow != null) {
- wlactive |= !mTimerWindow.reset(false);
+ wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
}
if (!wlactive) {
if (mTimerFull != null) {
@@ -2488,7 +2620,7 @@
}
boolean reset() {
- if (mTimer.reset(true)) {
+ if (mTimer.reset(BatteryStatsImpl.this, true)) {
mTimer = null;
return true;
}
@@ -2600,6 +2732,8 @@
SamplingCounter[] mSpeedBins;
+ ArrayList<ExcessiveWake> mExcessiveWake;
+
Proc() {
mUnpluggables.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
@@ -2626,6 +2760,58 @@
}
}
+ public int countExcessiveWakes() {
+ return mExcessiveWake != null ? mExcessiveWake.size() : 0;
+ }
+
+ public ExcessiveWake getExcessiveWake(int i) {
+ if (mExcessiveWake != null) {
+ return mExcessiveWake.get(i);
+ }
+ return null;
+ }
+
+ public void addExcessiveWake(long overTime, long usedTime) {
+ if (mExcessiveWake == null) {
+ mExcessiveWake = new ArrayList<ExcessiveWake>();
+ }
+ ExcessiveWake ew = new ExcessiveWake();
+ ew.overTime = overTime;
+ ew.usedTime = usedTime;
+ mExcessiveWake.add(ew);
+ }
+
+ void writeExcessiveWakeToParcelLocked(Parcel out) {
+ if (mExcessiveWake == null) {
+ out.writeInt(0);
+ return;
+ }
+
+ final int N = mExcessiveWake.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ ExcessiveWake ew = mExcessiveWake.get(i);
+ out.writeLong(ew.overTime);
+ out.writeLong(ew.usedTime);
+ }
+ }
+
+ void readExcessiveWakeFromParcelLocked(Parcel in) {
+ final int N = in.readInt();
+ if (N == 0) {
+ mExcessiveWake = null;
+ return;
+ }
+
+ mExcessiveWake = new ArrayList<ExcessiveWake>();
+ for (int i=0; i<N; i++) {
+ ExcessiveWake ew = new ExcessiveWake();
+ ew.overTime = in.readLong();
+ ew.usedTime = in.readLong();
+ mExcessiveWake.add(ew);
+ }
+ }
+
void writeToParcelLocked(Parcel out) {
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
@@ -2650,6 +2836,8 @@
out.writeInt(0);
}
}
+
+ writeExcessiveWakeToParcelLocked(out);
}
void readFromParcelLocked(Parcel in) {
@@ -2678,6 +2866,8 @@
mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
}
}
+
+ readExcessiveWakeFromParcelLocked(in);
}
public BatteryStatsImpl getBatteryStats() {
@@ -3155,6 +3345,11 @@
}
}
+ public class Pid {
+ long mWakeSum;
+ long mWakeStart;
+ }
+
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -3169,6 +3364,15 @@
return ps;
}
+ public Pid getPidStatsLocked(int pid) {
+ Pid p = mPids.get(pid);
+ if (p == null) {
+ p = new Pid();
+ mPids.put(pid, p);
+ }
+ return p;
+ }
+
/**
* Retrieve the statistics object for a particular service, creating
* if needed.
@@ -3261,18 +3465,36 @@
return t;
}
- public void noteStartWakeLocked(String name, int type) {
+ public void noteStartWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.startRunningLocked(BatteryStatsImpl.this);
}
+ if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
+ Pid p = getPidStatsLocked(pid);
+ p.mWakeStart = SystemClock.elapsedRealtime();
+ }
}
- public void noteStopWakeLocked(String name, int type) {
+ public void noteStopWakeLocked(int pid, String name, int type) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
t.stopRunningLocked(BatteryStatsImpl.this);
}
+ if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
+ Pid p = mPids.get(pid);
+ if (p != null) {
+ p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
+ p.mWakeStart = 0;
+ }
+ }
+ }
+
+ public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
+ Proc p = getProcessStatsLocked(proc);
+ if (p != null) {
+ p.addExcessiveWake(overTime, usedTime);
+ }
}
public void noteStartSensor(int sensor) {
@@ -3374,6 +3596,10 @@
return mOnBattery;
}
+ public boolean isScreenOn() {
+ return mScreenOn;
+ }
+
void initTimes() {
mBatteryRealtime = mTrackBatteryPastUptime = 0;
mBatteryUptime = mTrackBatteryPastRealtime = 0;
@@ -3386,24 +3612,24 @@
public void resetAllStatsLocked() {
mStartCount = 0;
initTimes();
- mScreenOnTimer.reset(false);
+ mScreenOnTimer.reset(this, false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i].reset(false);
+ mScreenBrightnessTimer[i].reset(this, false);
}
mInputEventCounter.reset(false);
- mPhoneOnTimer.reset(false);
- mAudioOnTimer.reset(false);
- mVideoOnTimer.reset(false);
+ mPhoneOnTimer.reset(this, false);
+ mAudioOnTimer.reset(this, false);
+ mVideoOnTimer.reset(this, false);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
- mPhoneSignalStrengthsTimer[i].reset(false);
+ mPhoneSignalStrengthsTimer[i].reset(this, false);
}
- mPhoneSignalScanningTimer.reset(false);
+ mPhoneSignalScanningTimer.reset(this, false);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i].reset(false);
+ mPhoneDataConnectionsTimer[i].reset(this, false);
}
- mWifiOnTimer.reset(false);
- mWifiRunningTimer.reset(false);
- mBluetoothOnTimer.reset(false);
+ mWifiOnTimer.reset(this, false);
+ mWifiRunningTimer.reset(this, false);
+ mBluetoothOnTimer.reset(this, false);
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
@@ -4085,6 +4311,7 @@
p.mUserTime = p.mLoadedUserTime = in.readLong();
p.mSystemTime = p.mLoadedSystemTime = in.readLong();
p.mStarts = p.mLoadedStarts = in.readInt();
+ p.readExcessiveWakeFromParcelLocked(in);
}
NP = in.readInt();
@@ -4273,6 +4500,7 @@
out.writeLong(ps.mUserTime);
out.writeLong(ps.mSystemTime);
out.writeInt(ps.mStarts);
+ ps.writeExcessiveWakeToParcelLocked(out);
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index c3c0db2..885ed6d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -163,7 +163,6 @@
LayoutInflater inflater = LayoutInflater.from(context);
mCustomNavView = (View) inflater.inflate(customNavId, null);
mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
- addView(mCustomNavView);
}
mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
@@ -553,7 +552,7 @@
if (mSpinner != null) {
mSpinner.measure(
MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
}
break;
case ActionBar.NAVIGATION_MODE_CUSTOM:
@@ -563,8 +562,16 @@
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
final int customNavWidth = lp.width >= 0 ?
Math.min(lp.width, availableWidth) : availableWidth;
- final int customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
- MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+
+ // If the action bar is wrapping to its content height, don't allow a custom
+ // view to MATCH_PARENT.
+ int customNavHeightMode;
+ if (mContentHeight <= 0) {
+ customNavHeightMode = MeasureSpec.AT_MOST;
+ } else {
+ customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+ MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+ }
final int customNavHeight = lp.height >= 0 ?
Math.min(lp.height, height) : height;
mCustomNavView.measure(
@@ -576,7 +583,7 @@
if (mTabLayout != null) {
mTabLayout.measure(
MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
}
break;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e0608f9..67327b2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1594,6 +1594,26 @@
<attr name="smoothScrollbar" format="boolean" />
<!-- A reference to an XML description of the adapter to attach to the list. -->
<attr name="adapter" format="reference" />
+ <!-- Defines the choice behavior for the view. By default, lists do not have
+ any choice behavior. By setting the choiceMode to singleChoice, the list
+ allows up to one item to be in a chosen state. By setting the choiceMode to
+ multipleChoice, the list allows any number of items to be chosen.
+ Finally, by setting the choiceMode to multipleChoiceModal the list allows
+ any number of items to be chosen in a special selection mode.
+ The application will supply a
+ {@link android.widget.AbsListView.MultiChoiceModeListener} using
+ {@link android.widget.AbsListView#setMultiChoiceModeListener} to control the
+ selection mode. This uses the {@link android.view.ActionMode} API. -->
+ <attr name="choiceMode">
+ <!-- Normal list that does not indicate choices. -->
+ <enum name="none" value="0" />
+ <!-- The list allows up to one choice. -->
+ <enum name="singleChoice" value="1" />
+ <!-- The list allows multiple choices. -->
+ <enum name="multipleChoice" value="2" />
+ <!-- The list allows multiple choices in a custom selection mode. -->
+ <enum name="multipleChoiceModal" value="3" />
+ </attr>
</declare-styleable>
<declare-styleable name="AbsSpinner">
<!-- Reference to an array resource that will populate the Spinner. For static content,
@@ -1800,20 +1820,6 @@
<!-- Height of the divider. Will use the intrinsic height of the divider if this
is not specified. -->
<attr name="dividerHeight" format="dimension" />
- <!-- Defines the choice behavior for the ListView. By default, lists do not have
- any choice behavior. By setting the choiceMode to singleChoice, the List
- allows up to one item to be in a chosen state. By setting the choiceMode to
- multipleChoice, the list allows any number of items to be chosen. -->
- <attr name="choiceMode">
- <!-- Normal list that does not indicate choices. -->
- <enum name="none" value="0" />
- <!-- The list allows up to one choice. -->
- <enum name="singleChoice" value="1" />
- <!-- The list allows multiple choices. -->
- <enum name="multipleChoice" value="2" />
- <!-- The list allows multiple choices in a custom selection mode. -->
- <enum name="multipleChoiceModal" value="3" />
- </attr>
<!-- When set to false, the ListView will not draw the divider after each header view.
The default value is true. -->
<attr name="headerDividersEnabled" format="boolean" />
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2e1e8d8..be96935 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -128,6 +128,12 @@
// Write the first chunk from the given ChunkInfo.
void writeFirstChunk(ChunkInfo* info);
+ // Adjust other track media clock (presumably wall clock)
+ // based on audio track media clock with the drift time.
+ int64_t mDriftTimeUs;
+ void addDriftTimeUs(int64_t driftTimeUs);
+ int64_t getDriftTimeUs();
+
void lock();
void unlock();
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab1fa4f..43354c2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -86,10 +86,10 @@
// Track authoring progress status
// kKeyTrackTimeStatus is used to track progress in elapsed time
- // kKeyTrackFrameStatus is used to track progress in authored frames
- kKeyTrackFrameStatus = 'tkfm', // int32_t
kKeyTrackTimeStatus = 'tktm', // int64_t
+ kKeyNotRealTime = 'ntrt', // bool (int32_t)
+
};
enum {
diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
deleted file mode 100755
index e91bfb4..0000000
--- a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 24ef547..4a4d837 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -44,7 +44,6 @@
private ScriptC_Threshold mScript;
private ScriptC_Vertical_blur mScriptVBlur;
private ScriptC_Horizontal_blur mScriptHBlur;
- private ScriptC_Levels mScriptLevels;
private int mRadius = 0;
private SeekBar mRadiusSeekBar;
@@ -73,7 +72,8 @@
@SuppressWarnings({"FieldCanBeLocal"})
private Allocation mOutPixelsAllocation;
@SuppressWarnings({"FieldCanBeLocal"})
- private Allocation mScratchPixelsAllocation;
+ private Allocation mScratchPixelsAllocation1;
+ private Allocation mScratchPixelsAllocation2;
private SurfaceView mSurfaceView;
private ImageView mDisplayView;
@@ -261,29 +261,29 @@
}
else if(seekBar == mInBlackSeekBar) {
mInBlack = (float)progress;
- mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+ mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
}
else if(seekBar == mOutBlackSeekBar) {
mOutBlack = (float)progress;
- mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+ mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
}
else if(seekBar == mInWhiteSeekBar) {
mInWhite = (float)progress + 127.0f;
- mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+ mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
}
else if(seekBar == mOutWhiteSeekBar) {
mOutWhite = (float)progress + 127.0f;
- mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+ mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
}
else if(seekBar == mGammaSeekBar) {
mGamma = (float)progress/100.0f;
mGamma = Math.max(mGamma, 0.1f);
mGamma = 1.0f / mGamma;
- mScriptLevels.invoke_setGamma(mGamma);
+ mScriptVBlur.invoke_setGamma(mGamma);
}
else if(seekBar == mSaturationSeekBar) {
mSaturation = (float)progress / 50.0f;
- mScriptLevels.invoke_setSaturation(mSaturation);
+ mScriptVBlur.invoke_setSaturation(mSaturation);
}
long t = java.lang.System.currentTimeMillis();
@@ -373,28 +373,32 @@
mInPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapIn);
mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut);
- mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
+
+ Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
+ tb.add(android.renderscript.Dimension.X, mBitmapIn.getWidth());
+ tb.add(android.renderscript.Dimension.Y, mBitmapIn.getHeight());
+ mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
+ mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur, false);
mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur, false);
- mScriptLevels = new ScriptC_Levels(mRS, getResources(), R.raw.levels, false);
mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold, false);
mScript.set_width(mBitmapIn.getWidth());
mScript.set_height(mBitmapIn.getHeight());
mScript.set_radius(mRadius);
- mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
- mScriptLevels.invoke_setGamma(mGamma);
- mScriptLevels.invoke_setSaturation(mSaturation);
+ mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+ mScriptVBlur.invoke_setGamma(mGamma);
+ mScriptVBlur.invoke_setSaturation(mSaturation);
mScript.bind_InPixel(mInPixelsAllocation);
mScript.bind_OutPixel(mOutPixelsAllocation);
- mScript.bind_ScratchPixel(mScratchPixelsAllocation);
+ mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
+ mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
mScript.set_vBlurScript(mScriptVBlur);
mScript.set_hBlurScript(mScriptHBlur);
- mScript.set_levelsScript(mScriptLevels);
}
private Bitmap loadBitmap(int resource) {
@@ -420,15 +424,15 @@
long t = java.lang.System.currentTimeMillis();
- mScript.invoke_filterBenchmark();
+ mScript.invoke_filter();
mRS.finish();
t = java.lang.System.currentTimeMillis() - t;
android.util.Log.v("Img", "Renderscript frame time core ms " + t);
- long javaTime = javaFilter();
- mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms");
- //mBenchmarkResult.setText("RS: " + t + " ms");
+ //long javaTime = javaFilter();
+ //mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms");
+ mBenchmarkResult.setText("RS: " + t + " ms");
mRadius = oldRadius;
mScript.set_radius(mRadius);
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
index 58c9acf..cfffac8 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
@@ -3,16 +3,16 @@
#include "ip.rsh"
void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
- uchar4 *output = (uchar4 *)v_out;
+ float4 *output = (float4 *)v_out;
const FilterStruct *fs = (const FilterStruct *)usrData;
- const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, 0, y);
+ const float4 *input = (const float4 *)rsGetElementAt(fs->ain, 0, y);
float3 blurredPixel = 0;
const float *gPtr = fs->gaussian;
if ((x > fs->radius) && (x < (fs->width - fs->radius))) {
- const uchar4 *i = input + (x - fs->radius);
+ const float4 *i = input + (x - fs->radius);
for(int r = -fs->radius; r <= fs->radius; r ++) {
- blurredPixel += convert_float3(i->xyz) * gPtr[0];
+ blurredPixel += i->xyz * gPtr[0];
gPtr++;
i++;
}
@@ -20,11 +20,11 @@
for(int r = -fs->radius; r <= fs->radius; r ++) {
// Stepping left and right away from the pixel
int validW = rsClamp(x + r, (uint)0, (uint)(fs->width - 1));
- blurredPixel += convert_float3(input[validW].xyz) * gPtr[0];
+ blurredPixel += input[validW].xyz * gPtr[0];
gPtr++;
}
}
- output->xyz = convert_uchar3(blurredPixel);
+ output->xyz = blurredPixel;
}
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
deleted file mode 100644
index bb8a6fc..0000000
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-#pragma version(1)
-
-#include "ip.rsh"
-
-
-static float inBlack;
-static float outBlack;
-static float inWhite;
-static float outWhite;
-static float3 gamma;
-static float saturation;
-
-static float inWMinInB;
-static float outWMinOutB;
-static float overInWMinInB;
-static rs_matrix3x3 colorMat;
-
-//#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
-#pragma rs export_func(setLevels, setSaturation, setGamma);
-
-void setLevels(float iBlk, float oBlk, float iWht, float oWht) {
- inBlack = iBlk;
- outBlack = oBlk;
- inWhite = iWht;
- outWhite = oWht;
-
- inWMinInB = inWhite - inBlack;
- outWMinOutB = outWhite - outBlack;
- overInWMinInB = 1.f / inWMinInB;
-}
-
-void setSaturation(float sat) {
- saturation = sat;
-
- // Saturation
- // Linear weights
- //float rWeight = 0.3086f;
- //float gWeight = 0.6094f;
- //float bWeight = 0.0820f;
-
- // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
- float rWeight = 0.299f;
- float gWeight = 0.587f;
- float bWeight = 0.114f;
-
- float oneMinusS = 1.0f - saturation;
- rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
- rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
- rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
- rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
- rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
- rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
- rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
- rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
- rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
-}
-
-void setGamma(float g) {
- gamma = (float3)g;
-}
-
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
- const uchar4 *input = v_in;
- uchar4 *output = v_out;
-
- float3 currentPixel = 0;
-
- //currentPixel.xyz = convert_float3(input.xyz);
- currentPixel.x = (float)(input->x);
- currentPixel.y = (float)(input->y);
- currentPixel.z = (float)(input->z);
-
- float3 temp = rsMatrixMultiply(&colorMat, currentPixel);
- temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
- if (gamma.x != 1.0f)
- temp = pow(temp, (float3)gamma);
- currentPixel = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
-
- //output.xyz = convert_uchar3(currentPixel.xyz);
- output->x = (uint8_t)currentPixel.x;
- output->y = (uint8_t)currentPixel.y;
- output->z = (uint8_t)currentPixel.z;
- output->w = input->w;
-}
-
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
index 8e198c7..33945a5 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -8,14 +8,14 @@
uchar4 * InPixel;
uchar4 * OutPixel;
-uchar4 * ScratchPixel;
+float4 * ScratchPixel1;
+float4 * ScratchPixel2;
-#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript, levelsScript)
-#pragma rs export_func(filter, filterBenchmark);
+#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel1, ScratchPixel2, vBlurScript, hBlurScript)
+#pragma rs export_func(filter);
rs_script vBlurScript;
rs_script hBlurScript;
-rs_script levelsScript;
const int CMD_FINISHED = 1;
@@ -64,7 +64,21 @@
}
-static void blur() {
+static void copyInput() {
+ RS_DEBUG_MARKER;
+ rs_allocation ain = rsGetAllocation(InPixel);
+ uint32_t dimx = rsAllocationGetDimX(ain);
+ uint32_t dimy = rsAllocationGetDimY(ain);
+ for(uint32_t y = 0; y < dimy; y++) {
+ for(uint32_t x = 0; x < dimx; x++) {
+ ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]);
+ }
+ }
+ RS_DEBUG_MARKER;
+}
+
+void filter() {
+ copyInput();
computeGaussianWeights();
FilterStruct fs;
@@ -73,28 +87,11 @@
fs.height = height;
fs.radius = radius;
- fs.ain = rsGetAllocation(InPixel);
- rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel), &fs);
+ fs.ain = rsGetAllocation(ScratchPixel1);
+ rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel2), &fs);
- fs.ain = rsGetAllocation(ScratchPixel);
+ fs.ain = rsGetAllocation(ScratchPixel2);
rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs);
-}
-
-void filter() {
- //RS_DEBUG(radius);
-
- if(radius > 0) {
- blur();
- rsForEach(levelsScript, rsGetAllocation(OutPixel), rsGetAllocation(OutPixel), 0);
- } else {
- rsForEach(levelsScript, rsGetAllocation(InPixel), rsGetAllocation(OutPixel), 0);
- }
-
- rsSendToClientBlocking(CMD_FINISHED);
-}
-
-void filterBenchmark() {
- blur();
rsSendToClientBlocking(CMD_FINISHED);
}
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index 3c69289..d901d2a 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -2,28 +2,91 @@
#include "ip.rsh"
+static float inBlack;
+static float outBlack;
+static float inWhite;
+static float outWhite;
+static float3 gamma;
+static float saturation;
+
+static float inWMinInB;
+static float outWMinOutB;
+static float overInWMinInB;
+static rs_matrix3x3 colorMat;
+
+#pragma rs export_func(setLevels, setSaturation, setGamma);
+
+void setLevels(float iBlk, float oBlk, float iWht, float oWht) {
+ inBlack = iBlk;
+ outBlack = oBlk;
+ inWhite = iWht;
+ outWhite = oWht;
+
+ inWMinInB = inWhite - inBlack;
+ outWMinOutB = outWhite - outBlack;
+ overInWMinInB = 1.f / inWMinInB;
+}
+
+void setSaturation(float sat) {
+ saturation = sat;
+
+ // Saturation
+ // Linear weights
+ //float rWeight = 0.3086f;
+ //float gWeight = 0.6094f;
+ //float bWeight = 0.0820f;
+
+ // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
+ float rWeight = 0.299f;
+ float gWeight = 0.587f;
+ float bWeight = 0.114f;
+
+ float oneMinusS = 1.0f - saturation;
+ rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
+ rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
+ rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
+ rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
+ rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
+ rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
+ rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
+ rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
+ rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
+}
+
+void setGamma(float g) {
+ gamma = (float3)g;
+}
+
void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
uchar4 *output = (uchar4 *)v_out;
const FilterStruct *fs = (const FilterStruct *)usrData;
- const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, x, 0);
+ const float4 *input = (const float4 *)rsGetElementAt(fs->ain, x, 0);
float3 blurredPixel = 0;
const float *gPtr = fs->gaussian;
if ((y > fs->radius) && (y < (fs->height - fs->radius))) {
- const uchar4 *i = input + ((y - fs->radius) * fs->width);
+ const float4 *i = input + ((y - fs->radius) * fs->width);
for(int r = -fs->radius; r <= fs->radius; r ++) {
- blurredPixel += convert_float3(i->xyz) * gPtr[0];
+ blurredPixel += i->xyz * gPtr[0];
gPtr++;
i += fs->width;
}
} else {
for(int r = -fs->radius; r <= fs->radius; r ++) {
int validH = rsClamp(y + r, (uint)0, (uint)(fs->height - 1));
- const uchar4 *i = input + validH * fs->width;
- blurredPixel += convert_float3(i->xyz) * gPtr[0];
+ const float4 *i = input + validH * fs->width;
+ blurredPixel += i->xyz * gPtr[0];
gPtr++;
}
}
- output->xyz = convert_uchar3(blurredPixel);
+
+ float3 temp = rsMatrixMultiply(&colorMat, blurredPixel);
+ temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
+ if (gamma.x != 1.0f)
+ temp = pow(temp, (float3)gamma);
+ temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
+
+ output->xyz = convert_uchar3(temp);
+ //output->w = input->w;
}
diff --git a/libs/rs/java/ModelViewer/res/drawable/robot.png b/libs/rs/java/ModelViewer/res/drawable/robot.png
index 7c85e56..f7353fd 100644
--- a/libs/rs/java/ModelViewer/res/drawable/robot.png
+++ b/libs/rs/java/ModelViewer/res/drawable/robot.png
Binary files differ
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index ac32810..5a2b6ba 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -239,7 +239,7 @@
return a->getType()->getDimFaces();
}
-const void * SC_getElementAtX(RsAllocation va, uint32_t x)
+static const void * SC_getElementAtX(RsAllocation va, uint32_t x)
{
const Allocation *a = static_cast<const Allocation *>(va);
const Type *t = a->getType();
@@ -247,7 +247,7 @@
return &p[t->getElementSizeBytes() * x];
}
-const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
+static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
{
const Allocation *a = static_cast<const Allocation *>(va);
const Type *t = a->getType();
@@ -255,7 +255,7 @@
return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
}
-const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
+static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
{
const Allocation *a = static_cast<const Allocation *>(va);
const Type *t = a->getType();
@@ -263,6 +263,20 @@
return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
}
+static void SC_setObject(void **vdst, void * vsrc) {
+ static_cast<ObjectBase *>(vsrc)->incSysRef();
+ static_cast<ObjectBase *>(vdst[0])->decSysRef();
+ *vdst = vsrc;
+}
+static void SC_clearObject(void **vdst) {
+ static_cast<ObjectBase *>(vdst[0])->decSysRef();
+ *vdst = NULL;
+}
+static bool SC_isObject(RsAllocation vsrc) {
+ return vsrc != NULL;
+}
+
+
static void SC_debugF(const char *s, float f) {
LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
@@ -405,6 +419,11 @@
{ "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
{ "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
+ { "_Z11rsSetObjectP13rs_allocation13rs_allocation", (void *)&SC_setObject },
+ { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject },
+ { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject },
+
+
// Debug
{ "_Z7rsDebugPKcf", (void *)&SC_debugF },
{ "_Z7rsDebugPKcff", (void *)&SC_debugFv2 },
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index bb4aafb..c842ef1 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -29,6 +29,77 @@
#include "rs_cl.rsh"
#include "rs_core.rsh"
+extern void __attribute__((overloadable))
+ rsSetObject(rs_element *dst, rs_element src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_type *dst, rs_type src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_allocation *dst, rs_allocation src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_sampler *dst, rs_sampler src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_script *dst, rs_script src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_mesh *dst, rs_mesh src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_program_fragment *dst, rs_program_fragment src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_program_vertex *dst, rs_program_vertex src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_program_raster *dst, rs_program_raster src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_program_store *dst, rs_program_store src);
+extern void __attribute__((overloadable))
+ rsSetObject(rs_font *dst, rs_font src);
+
+extern void __attribute__((overloadable))
+ rsClearObject(rs_element *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_type *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_allocation *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_sampler *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_script *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_mesh *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_program_fragment *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_program_vertex *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_program_raster *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_program_store *dst);
+extern void __attribute__((overloadable))
+ rsClearObject(rs_font *dst);
+
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_element);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_type);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_allocation);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_sampler);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_script);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_mesh);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_program_fragment);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_program_vertex);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_program_raster);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_program_store);
+extern bool __attribute__((overloadable))
+ rsIsObject(rs_font);
+
+
+
// Allocations
// Return the rs_allocation associated with a bound data
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index fd9ac16..dd42972 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -14,17 +14,18 @@
typedef uint32_t uint;
typedef uint64_t ulong;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_element;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_type;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_allocation;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_sampler;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_script;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_mesh;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_fragment;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_vertex;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_raster;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_store;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_font;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_element;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_type;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_allocation;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sampler;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_script;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_fragment;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_vertex;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_raster;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_store;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_font;
+
typedef float float2 __attribute__((ext_vector_type(2)));
typedef float float3 __attribute__((ext_vector_type(3)));
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index daa20a8..a616aae 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -731,7 +731,9 @@
encMeta->setInt32(kKeyChannelCount, mAudioChannels);
encMeta->setInt32(kKeySampleRate, mSampleRate);
encMeta->setInt32(kKeyBitRate, mAudioBitRate);
- encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+ if (mAudioTimeScale > 0) {
+ encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+ }
OMXClient client;
CHECK_EQ(client.connect(), OK);
@@ -1032,7 +1034,9 @@
enc_meta->setInt32(kKeyStride, stride);
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
enc_meta->setInt32(kKeyColorFormat, colorFormat);
- enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+ if (mVideoTimeScale > 0) {
+ enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+ }
if (mVideoEncoderProfile != -1) {
enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
}
@@ -1115,7 +1119,9 @@
meta->setInt32(kKeyFileType, mOutputFormat);
meta->setInt32(kKeyBitRate, totalBitRate);
meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
- meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+ if (mMovieTimeScale > 0) {
+ meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+ }
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
@@ -1191,9 +1197,9 @@
mIFramesIntervalSec = 1;
mAudioSourceNode = 0;
mUse64BitFileOffset = false;
- mMovieTimeScale = 1000;
- mAudioTimeScale = 1000;
- mVideoTimeScale = 1000;
+ mMovieTimeScale = -1;
+ mAudioTimeScale = -1;
+ mVideoTimeScale = -1;
mCameraId = 0;
mVideoEncoderProfile = -1;
mVideoEncoderLevel = -1;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 1460f37..f52ec1a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,6 +72,11 @@
bool mIsAudio;
bool mIsMPEG4;
int64_t mTrackDurationUs;
+
+ // For realtime applications, we need to adjust the media clock
+ // for video track based on the audio media clock
+ bool mIsRealTimeRecording;
+ int64_t mMaxTimeStampUs;
int64_t mEstimatedTrackSizeBytes;
int64_t mMaxWriteTimeUs;
int32_t mTimeScale;
@@ -163,6 +168,12 @@
void getCodecSpecificDataFromInputFormatIfPossible();
+ // Determine the track time scale
+ // If it is an audio track, try to use the sampling rate as
+ // the time scale; however, if user chooses the overwrite
+ // value, the user-supplied time scale will be used.
+ void setTimeScale();
+
Track(const Track &);
Track &operator=(const Track &);
};
@@ -429,7 +440,7 @@
mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
mMoovBoxBufferOffset = 0;
CHECK(mMoovBoxBuffer != NULL);
- int32_t duration = (maxDurationUs * mTimeScale) / 1E6;
+ int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6;
beginBox("moov");
@@ -744,10 +755,6 @@
mReachedEOS(false) {
getCodecSpecificDataFromInputFormatIfPossible();
- if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) {
- mTimeScale = 1000;
- }
-
const char *mime;
mMeta->findCString(kKeyMIMEType, &mime);
mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
@@ -755,6 +762,28 @@
mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
+ setTimeScale();
+}
+
+void MPEG4Writer::Track::setTimeScale() {
+ LOGV("setTimeScale");
+ // Default time scale
+ mTimeScale = 90000;
+
+ if (mIsAudio) {
+ // Use the sampling rate as the default time scale for audio track.
+ int32_t sampleRate;
+ bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
+ CHECK(success);
+ mTimeScale = sampleRate;
+ }
+
+ // If someone would like to overwrite the timescale, use user-supplied value.
+ int32_t timeScale;
+ if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
+ mTimeScale = timeScale;
+ }
+
CHECK(mTimeScale > 0);
}
@@ -940,6 +969,7 @@
mDone = false;
mIsFirstChunk = true;
+ mDriftTimeUs = 0;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
ChunkInfo info;
@@ -967,6 +997,14 @@
startTimeUs = 0;
}
+ mIsRealTimeRecording = true;
+ {
+ int32_t isNotRealTime;
+ if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
+ mIsRealTimeRecording = (isNotRealTime == 0);
+ }
+ }
+
initTrackingProgressStatus(params);
sp<MetaData> meta = new MetaData;
@@ -1322,10 +1360,16 @@
int32_t nZeroLengthFrames = 0;
int64_t lastTimestampUs = 0; // Previous sample time stamp in ms
int64_t lastDurationUs = 0; // Between the previous two samples in ms
+ int64_t currDurationTicks = 0; // Timescale based ticks
+ int64_t lastDurationTicks = 0; // Timescale based ticks
int32_t sampleCount = 1; // Sample count in the current stts table entry
uint32_t previousSampleSize = 0; // Size of the previous sample
int64_t previousPausedDurationUs = 0;
int64_t timestampUs;
+
+ int64_t wallClockTimeUs = 0;
+ int64_t lastWallClockTimeUs = 0;
+
sp<MetaData> meta_data;
bool collectStats = collectStatisticalData();
@@ -1429,6 +1473,33 @@
}
timestampUs -= previousPausedDurationUs;
+ if (mIsRealTimeRecording && !mIsAudio) {
+ // The minor adjustment on the timestamp is heuristic/experimental
+ // We are adjusting the timestamp to reduce the fluctuation of the duration
+ // of neighboring samples. This in turn helps reduce the track header size,
+ // especially, the number of entries in the "stts" box.
+ if (mNumSamples > 1) {
+ int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs;
+ int64_t diffUs = (durationUs > lastDurationUs)
+ ? durationUs - lastDurationUs
+ : lastDurationUs - durationUs;
+ if (diffUs <= 5000) { // XXX: Magic number 5ms
+ timestampUs = lastTimestampUs + lastDurationUs;
+ } else {
+ timestampUs += mOwner->getDriftTimeUs();
+ }
+ }
+ }
+ CHECK(timestampUs >= 0);
+ if (mNumSamples > 1) {
+ if (timestampUs <= lastTimestampUs) {
+ LOGW("Drop a frame, since it arrives too late!");
+ copy->release();
+ copy = NULL;
+ continue;
+ }
+ }
+
LOGV("time stamp: %lld and previous paused duration %lld",
timestampUs, previousPausedDurationUs);
if (timestampUs > mTrackDurationUs) {
@@ -1438,7 +1509,16 @@
mSampleSizes.push_back(sampleSize);
++mNumSamples;
if (mNumSamples > 2) {
- if (lastDurationUs != timestampUs - lastTimestampUs) {
+ // We need to use the time scale based ticks, rather than the
+ // timestamp itself to determine whether we have to use a new
+ // stts entry, since we may have rounding errors.
+ // The calculation is intended to reduce the accumulated
+ // rounding errors.
+ currDurationTicks =
+ ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
+ (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+
+ if (currDurationTicks != lastDurationTicks) {
SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
mSttsTableEntries.push_back(sttsEntry);
sampleCount = 1;
@@ -1453,7 +1533,16 @@
previousSampleSize = sampleSize;
}
lastDurationUs = timestampUs - lastTimestampUs;
+ lastDurationTicks = currDurationTicks;
lastTimestampUs = timestampUs;
+ if (mIsRealTimeRecording && mIsAudio) {
+ wallClockTimeUs = systemTime() / 1000;
+ int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs;
+ if (mNumSamples > 2) {
+ mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs);
+ }
+ lastWallClockTimeUs = wallClockTimeUs;
+ }
if (isSync != 0) {
mStssTableEntries.push_back(mNumSamples);
@@ -1679,6 +1768,18 @@
}
}
+void MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) {
+ LOGV("addDriftTimeUs: %lld us", driftTimeUs);
+ Mutex::Autolock autolock(mLock);
+ mDriftTimeUs += driftTimeUs;
+}
+
+int64_t MPEG4Writer::getDriftTimeUs() {
+ LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
+ Mutex::Autolock autolock(mLock);
+ return mDriftTimeUs;
+}
+
void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
LOGV("bufferChunk");
@@ -1709,7 +1810,6 @@
LOGV("%s track time scale: %d",
mIsAudio? "Audio": "Video", mTimeScale);
-
time_t now = time(NULL);
int32_t mvhdTimeScale = mOwner->getTimeScale();
int64_t trakDurationUs = getDurationUs();
@@ -2024,10 +2124,18 @@
mOwner->beginBox("stts");
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(mSttsTableEntries.size());
+ int64_t prevTimestampUs = 0;
for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
it != mSttsTableEntries.end(); ++it) {
mOwner->writeInt32(it->sampleCount);
- int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6;
+
+ // Make sure that we are calculating the sample duration the exactly
+ // same way as we made decision on how to create stts entries.
+ int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
+ int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
+ (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+ prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
+
mOwner->writeInt32(dur);
}
mOwner->endBox(); // stts
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
index 0aaa370..e7b0509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
@@ -185,11 +185,11 @@
final Segment newSegment = new Segment(n, icon, n.notification.tickerText);
// If there's already a notification schedule for this package and id, remove it.
- for (int i=0; i<initialCount; i++) {
+ for (int i=0; i<mSegments.size(); i++) {
Segment seg = mSegments.get(i);
if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
// just update that one to use this new data instead
- mSegments.remove(i);
+ mSegments.remove(i--); // restart iteration here
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a410fa4..6be5546 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -643,17 +643,16 @@
boolean playSoundEffect = false;
final PanelFeatureState st = getPanelState(featureId, true);
- if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null) {
- if (mActionBar.isOverflowReserved()) {
- if (!mActionBar.isOverflowMenuShowing()) {
- final Callback cb = getCallback();
- if (cb != null &&
- cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) {
- playSoundEffect = mActionBar.showOverflowMenu();
- }
- } else {
- playSoundEffect = mActionBar.hideOverflowMenu();
+ if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
+ mActionBar.isOverflowReserved()) {
+ if (!mActionBar.isOverflowMenuShowing()) {
+ final Callback cb = getCallback();
+ if (cb != null &&
+ cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) {
+ playSoundEffect = mActionBar.showOverflowMenu();
}
+ } else {
+ playSoundEffect = mActionBar.hideOverflowMenu();
}
} else {
if (st.isOpen || st.isHandled) {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2fb481c..4ee89cc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -151,6 +151,7 @@
static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
private final int MY_UID;
+ private final int MY_PID;
private boolean mDoneBooting = false;
private boolean mBootCompleted = false;
@@ -309,7 +310,7 @@
long ident = Binder.clearCallingIdentity();
try {
PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
- MY_UID, mTag);
+ MY_UID, MY_PID, mTag);
mHeld = true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -434,11 +435,11 @@
}
}
- PowerManagerService()
- {
+ PowerManagerService() {
// Hack to get our uid... should have a func for this.
long token = Binder.clearCallingIdentity();
- MY_UID = Binder.getCallingUid();
+ MY_UID = Process.myUid();
+ MY_PID = Process.myPid();
Binder.restoreCallingIdentity(token);
// XXX remove this when the kernel doesn't timeout wake locks
@@ -573,13 +574,13 @@
private class WakeLock implements IBinder.DeathRecipient
{
- WakeLock(int f, IBinder b, String t, int u) {
+ WakeLock(int f, IBinder b, String t, int u, int p) {
super();
flags = f;
binder = b;
tag = t;
uid = u == MY_UID ? Process.SYSTEM_UID : u;
- pid = Binder.getCallingPid();
+ pid = p;
if (u != MY_UID || (
!"KEEP_SCREEN_ON_FLAG".equals(tag)
&& !"KeyInputQueue".equals(tag))) {
@@ -631,21 +632,23 @@
public void acquireWakeLock(int flags, IBinder lock, String tag) {
int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
if (uid != Process.myUid()) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
}
long ident = Binder.clearCallingIdentity();
try {
synchronized (mLocks) {
- acquireWakeLockLocked(flags, lock, uid, tag);
+ acquireWakeLockLocked(flags, lock, uid, pid, tag);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
+ public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) {
int acquireUid = -1;
+ int acquirePid = -1;
String acquireName = null;
int acquireType = -1;
@@ -657,7 +660,7 @@
WakeLock wl;
boolean newlock;
if (index < 0) {
- wl = new WakeLock(flags, lock, tag, uid);
+ wl = new WakeLock(flags, lock, tag, uid, pid);
switch (wl.flags & LOCK_MASK)
{
case PowerManager.FULL_WAKE_LOCK:
@@ -730,13 +733,14 @@
}
if (newlock) {
acquireUid = wl.uid;
+ acquirePid = wl.pid;
acquireName = wl.tag;
acquireType = wl.monitorType;
}
if (acquireType >= 0) {
try {
- mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
+ mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType);
} catch (RemoteException e) {
// Ignore
}
@@ -756,6 +760,7 @@
private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
int releaseUid;
+ int releasePid;
String releaseName;
int releaseType;
@@ -800,13 +805,14 @@
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
releaseUid = wl.uid;
+ releasePid = wl.pid;
releaseName = wl.tag;
releaseType = wl.monitorType;
if (releaseType >= 0) {
long origId = Binder.clearCallingIdentity();
try {
- mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
+ mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType);
} catch (RemoteException e) {
// Ignore
} finally {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3f5888b..57f93c4 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8085,12 +8085,12 @@
if (oldHold != newHold) {
try {
if (oldHold != null) {
- mBatteryStats.noteStopWakelock(oldHold.mUid,
+ mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
"window",
BatteryStats.WAKE_TYPE_WINDOW);
}
if (newHold != null) {
- mBatteryStats.noteStartWakelock(newHold.mUid,
+ mBatteryStats.noteStartWakelock(newHold.mUid, -1,
"window",
BatteryStats.WAKE_TYPE_WINDOW);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index df930ad..55ec6aa 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import com.android.internal.R;
-import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
@@ -39,7 +38,6 @@
import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IActivityController;
-import android.app.IActivityManager;
import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
@@ -50,7 +48,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.ResultInfo;
import android.app.Service;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
@@ -95,7 +92,6 @@
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -110,6 +106,7 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.SparseArray;
+import android.util.TimeUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -200,6 +197,9 @@
// The minimum amount of time between successive GC requests for a process.
static final int GC_MIN_INTERVAL = 60*1000;
+ // The rate at which we check for apps using excessive wake locks -- 15 mins.
+ static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000;
+
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_TIMEOUT = 10*1000;
@@ -771,6 +771,11 @@
boolean mDidAppSwitch;
/**
+ * Last time (in realtime) at which we checked for wake lock usage.
+ */
+ long mLastWakeLockCheckTime;
+
+ /**
* Set while we are wanting to sleep, to prevent any
* activities from being started/resumed.
*/
@@ -915,6 +920,7 @@
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
+ static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
AlertDialog mUidAlert;
@@ -1174,6 +1180,16 @@
} catch (RemoteException e) {
}
} break;
+ case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
+ synchronized (ActivityManagerService.this) {
+ checkExcessiveWakeLocksLocked(true);
+ removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+ if (mSleeping) {
+ Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+ sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
+ }
+ }
+ } break;
}
}
};
@@ -2560,6 +2576,11 @@
mProcDeaths[0]++;
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ stats.noteProcessDiedLocked(app.info.uid, pid);
+ }
+
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
@@ -3577,6 +3598,9 @@
}
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ // Start looking for apps that are abusing wake locks.
+ Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+ mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
broadcastIntentLocked(null, null,
@@ -5382,6 +5406,12 @@
} else {
Slog.w(TAG, "goingToSleep with no resumed activity!");
}
+
+ // Initialize the wake times of all processes.
+ checkExcessiveWakeLocksLocked(false);
+ mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+ Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+ mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
}
}
@@ -5431,6 +5461,7 @@
mWindowManager.setEventDispatching(true);
mSleeping = false;
mMainStack.resumeTopActivityLocked(null);
+ mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
}
}
@@ -11287,6 +11318,62 @@
}
}
+ final void checkExcessiveWakeLocksLocked(boolean doKills) {
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ if (mLastWakeLockCheckTime == 0) {
+ doKills = false;
+ }
+ if (stats.isScreenOn()) {
+ doKills = false;
+ }
+ final long curRealtime = SystemClock.elapsedRealtime();
+ final long timeSince = curRealtime - mLastWakeLockCheckTime;
+ mLastWakeLockCheckTime = curRealtime;
+ if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) {
+ doKills = false;
+ }
+ int i = mLruProcesses.size();
+ while (i > 0) {
+ i--;
+ ProcessRecord app = mLruProcesses.get(i);
+ if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+ long wtime;
+ synchronized (stats) {
+ wtime = stats.getProcessWakeTime(app.info.uid,
+ app.pid, curRealtime);
+ }
+ long timeUsed = wtime - app.lastWakeTime;
+ if (false) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Wake for ");
+ app.toShortString(sb);
+ sb.append(": over ");
+ TimeUtils.formatDuration(timeSince, sb);
+ sb.append(" used ");
+ TimeUtils.formatDuration(timeUsed, sb);
+ sb.append(" (");
+ sb.append((timeUsed*100)/timeSince);
+ sb.append("%)");
+ Slog.i(TAG, sb.toString());
+ }
+ // If a process has held a wake lock for more
+ // than 50% of the time during this period,
+ // that sounds pad. Kill!
+ if (doKills && timeSince > 0
+ && ((timeUsed*100)/timeSince) >= 50) {
+ Slog.i(TAG, "Excessive wake lock in " + app.processName
+ + " (pid " + app.pid + "): held " + timeUsed
+ + " during " + timeSince);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "excessive wake lock");
+ Process.killProcessQuiet(app.pid);
+ } else {
+ app.lastWakeTime = wtime;
+ }
+ }
+ }
+ }
+
private final boolean updateOomAdjLocked(
ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
app.hiddenAdj = hiddenAdj;
@@ -11309,6 +11396,12 @@
// Likewise do a gc when an app is moving in to the
// background (such as a service stopping).
scheduleAppGcLocked(app);
+ // And note its current wake lock time.
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
+ app.pid, SystemClock.elapsedRealtime());
+ }
}
app.setRawAdj = app.curRawAdj;
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 37da6f7..7314e04 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -93,31 +93,31 @@
return data;
}
- public void noteStartWakelock(int uid, String name, int type) {
+ public void noteStartWakelock(int uid, int pid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type);
+ mStats.noteStartWakeLocked(uid, pid, name, type);
}
}
- public void noteStopWakelock(int uid, String name, int type) {
+ public void noteStopWakelock(int uid, int pid, String name, int type) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type);
+ mStats.noteStopWakeLocked(uid, pid, name, type);
}
}
public void noteStartSensor(int uid, int sensor) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.getUidStatsLocked(uid).noteStartSensor(sensor);
+ mStats.noteStartSensorLocked(uid, sensor);
}
}
public void noteStopSensor(int uid, int sensor) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.getUidStatsLocked(uid).noteStopSensor(sensor);
+ mStats.noteStopSensorLocked(uid, sensor);
}
}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 18b1acb..6d1fbab 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.Watchdog;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -27,8 +26,9 @@
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.PrintWriterPrinter;
+import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -74,6 +74,7 @@
Bundle instrumentationArguments;// as given to us
ComponentName instrumentationResultClass;// copy of instrumentationClass
BroadcastRecord curReceiver;// receiver currently running in the app
+ long lastWakeTime; // How long proc held wake lock at last check
long lastRequestedGc; // When we last asked the app to do a gc
long lastLowMemory; // When we last told the app that memory is low
boolean reportLowMemory; // Set to true when waiting to report low mem
@@ -128,6 +129,8 @@
ComponentName errorReportReceiver;
void dump(PrintWriter pw, String prefix) {
+ final long now = SystemClock.uptimeMillis();
+
if (info.className != null) {
pw.print(prefix); pw.print("class="); pw.println(info.className);
}
@@ -157,8 +160,9 @@
pw.print(" curReceiver="); pw.println(curReceiver);
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
- pw.print(prefix); pw.print("lastActivityTime="); pw.print(lastActivityTime);
- pw.print(" lruWeight="); pw.println(lruWeight);
+ pw.print(prefix); pw.print("lastActivityTime=");
+ TimeUtils.formatDuration(lastActivityTime, now, pw);
+ pw.print(" lruWeight="); pw.print(lruWeight);
pw.print(" hidden="); pw.print(hidden);
pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
@@ -177,6 +181,12 @@
pw.print(" persistentActivities="); pw.println(persistentActivities);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
+ pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
+ pw.print(" lastRequestedGc=");
+ TimeUtils.formatDuration(lastRequestedGc, now, pw);
+ pw.print(" lastLowMemory=");
+ TimeUtils.formatDuration(lastLowMemory, now, pw);
+ pw.print(" reportLowMemory="); pw.println(reportLowMemory);
if (killedBackground) {
pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 75365ad..ab5a78d 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
+import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -117,7 +118,10 @@
StartItem si = list.get(i);
pw.print(prefix); pw.print("#"); pw.print(i);
pw.print(" id="); pw.print(si.id);
- if (now != 0) pw.print(" dur="); pw.print(now-si.deliveredTime);
+ if (now != 0) {
+ pw.print(" dur=");
+ TimeUtils.formatDuration(si.deliveredTime, now, pw);
+ }
if (si.deliveryCount != 0) {
pw.print(" dc="); pw.print(si.deliveryCount);
}
@@ -140,18 +144,26 @@
pw.print(prefix); pw.print("permission="); pw.println(permission);
}
long now = SystemClock.uptimeMillis();
- pw.print(prefix); pw.print("baseDir="); pw.print(baseDir);
- if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir);
- pw.print(" dataDir="); pw.println(dataDir);
+ long nowReal = SystemClock.elapsedRealtime();
+ pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
+ if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
if (isForeground || foregroundId != 0) {
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
pw.print(" foregroundId="); pw.print(foregroundId);
pw.print(" foregroundNoti="); pw.println(foregroundNoti);
}
- pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now);
- pw.print(" executingStart="); pw.print(executingStart-now);
- pw.print(" restartTime="); pw.println(restartTime);
+ pw.print(prefix); pw.print("createTime=");
+ TimeUtils.formatDuration(createTime, nowReal, pw);
+ pw.print(" lastActivity=");
+ TimeUtils.formatDuration(lastActivity, now, pw);
+ pw.println("");
+ pw.print(prefix); pw.print(" executingStart=");
+ TimeUtils.formatDuration(executingStart, now, pw);
+ pw.print(" restartTime=");
+ TimeUtils.formatDuration(restartTime, now, pw);
+ pw.println("");
if (startRequested || lastStartId != 0) {
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
pw.print(" stopIfKilled="); pw.print(stopIfKilled);
@@ -162,13 +174,15 @@
|| restartDelay != 0 || nextRestartTime != 0) {
pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
pw.print(" restartCount="); pw.print(restartCount);
- pw.print(" restartDelay="); pw.print(restartDelay-now);
- pw.print(" nextRestartTime="); pw.print(nextRestartTime-now);
+ pw.print(" restartDelay=");
+ TimeUtils.formatDuration(restartDelay, now, pw);
+ pw.print(" nextRestartTime=");
+ TimeUtils.formatDuration(nextRestartTime, now, pw);
pw.print(" crashCount="); pw.println(crashCount);
}
if (deliveredStarts.size() > 0) {
pw.print(prefix); pw.println("Delivered Starts:");
- dumpStartList(pw, prefix, deliveredStarts, SystemClock.uptimeMillis());
+ dumpStartList(pw, prefix, deliveredStarts, now);
}
if (pendingStarts.size() > 0) {
pw.print(prefix); pw.println("Pending Starts:");
@@ -213,7 +227,8 @@
dataDir = sInfo.applicationInfo.dataDir;
exported = sInfo.exported;
this.restarter = restarter;
- createTime = lastActivity = SystemClock.uptimeMillis();
+ createTime = SystemClock.elapsedRealtime();
+ lastActivity = SystemClock.uptimeMillis();
}
public AppBindRecord retrieveAppBindingLocked(Intent intent,
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index 3b326df..0f448e0 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -190,7 +190,7 @@
return err;
}
- if (texture->target != GL_TEXTURE_2D)
+ if (texture->target != Texture::TEXTURE_2D)
return INVALID_OPERATION;
glBindTexture(GL_TEXTURE_2D, texture->name);
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index 37ef912..0c63c37 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -304,9 +304,9 @@
int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly);
ret[1] = septets;
if (septets > MAX_USER_DATA_SEPTETS) {
- ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
- ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
- - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+ ret[0] = (septets + (MAX_USER_DATA_SEPTETS_WITH_HEADER - 1)) /
+ MAX_USER_DATA_SEPTETS_WITH_HEADER;
+ ret[2] = (ret[0] * MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;
} else {
ret[0] = 1;
ret[2] = MAX_USER_DATA_SEPTETS - septets;
@@ -318,9 +318,9 @@
ret[1] = messageBody.length();
if (octets > MAX_USER_DATA_BYTES) {
// 6 is the size of the user data header
- ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ ret[0] = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+ MAX_USER_DATA_BYTES_WITH_HEADER;
+ ret[2] = ((ret[0] * MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
} else {
ret[0] = 1;
ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 65d87f5..e95b2f9 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -442,7 +442,7 @@
*/
public static TextEncodingDetails calculateLength(CharSequence messageBody,
boolean use7bitOnly) {
- return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+ return BearerData.calcTextEncodingDetails(messageBody, use7bitOnly);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index e9fea55..cf06dab 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -402,6 +402,7 @@
/**
* Calculate the message text encoding length, fragmentation, and other details.
*
+ * @param msg message text
* @param force7BitEncoding ignore (but still count) illegal characters if true
* @return septet count, or -1 on failure
*/
@@ -424,9 +425,10 @@
ted.codeUnitCount = msg.length();
int octets = ted.codeUnitCount * 2;
if (octets > MAX_USER_DATA_BYTES) {
- ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+ MAX_USER_DATA_BYTES_WITH_HEADER;
+ ted.codeUnitsRemaining = ((ted.msgCount *
+ MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
@@ -801,7 +803,7 @@
*
* @param bData an instance of BearerData.
*
- * @return data byte array of raw encoded SMS bearer data.
+ * @return byte array of raw encoded SMS bearer data.
*/
public static byte[] encode(BearerData bData) {
bData.hasUserDataHeader = ((bData.userData != null) &&
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 278e1ba..a77484a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -795,9 +795,10 @@
int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
ted.codeUnitCount = septets;
if (septets > MAX_USER_DATA_SEPTETS) {
- ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
- - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+ ted.msgCount = (septets + (MAX_USER_DATA_SEPTETS_WITH_HEADER - 1)) /
+ MAX_USER_DATA_SEPTETS_WITH_HEADER;
+ ted.codeUnitsRemaining = (ted.msgCount *
+ MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
@@ -807,9 +808,10 @@
int octets = msgBody.length() * 2;
ted.codeUnitCount = msgBody.length();
if (octets > MAX_USER_DATA_BYTES) {
- ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+ MAX_USER_DATA_BYTES_WITH_HEADER;
+ ted.codeUnitsRemaining = ((ted.msgCount *
+ MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
new file mode 100644
index 0000000..b214887
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2010 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.telephony;
+
+import android.telephony.SmsMessage;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
+
+public class SmsMessageBodyTest extends AndroidTestCase {
+
+ private static final String sAsciiChars = "@$_ !\"#%&'()*+,-./0123456789" +
+ ":;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\r";
+ private static final String sGsmBasicChars = "\u00a3\u00a5\u00e8\u00e9" +
+ "\u00f9\u00ec\u00f2\u00c7\u00d8\u00f8\u00c5\u00e5\u0394\u03a6" +
+ "\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u00c6\u00e6" +
+ "\u00df\u00c9\u00a4\u00a1\u00c4\u00d6\u00d1\u00dc\u00a7\u00bf" +
+ "\u00e4\u00f6\u00f1\u00fc\u00e0";
+ private static final String sGsmExtendedAsciiChars = "{|}\\[~]^\f";
+ private static final String sGsmExtendedEuroSymbol = "\u20ac";
+ private static final String sUnicodeChars = "\u4e00\u4e01\u4e02\u4e03" +
+ "\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d" +
+ "\u4e0e\u4e0f\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048" +
+ "\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8" +
+ "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18" +
+ "\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78" +
+ "\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408" +
+ "\u00a2\u00a9\u00ae\u2122";
+
+ private static final int sTestLengthCount = 12;
+
+ private static final int[] sSeptetTestLengths =
+ { 0, 1, 2, 80, 159, 160, 161, 240, 305, 306, 307, 320};
+
+ private static final int[] sUnicodeTestLengths =
+ { 0, 1, 2, 35, 69, 70, 71, 100, 133, 134, 135, 160};
+
+ private static final int[] sTestMsgCounts =
+ { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3};
+
+ private static final int[] sSeptetUnitsRemaining =
+ {160, 159, 158, 80, 1, 0, 145, 66, 1, 0, 152, 139};
+
+ private static final int[] sUnicodeUnitsRemaining =
+ { 70, 69, 68, 35, 1, 0, 63, 34, 1, 0, 66, 41};
+
+
+ @SmallTest
+ public void testCalcLengthAscii() throws Exception {
+ StringBuilder sb = new StringBuilder(320);
+ int[] values = {0, 0, 0, SmsMessage.ENCODING_7BIT};
+ int startPos = 0;
+ int asciiCharsLen = sAsciiChars.length();
+
+ for (int i = 0; i < sTestLengthCount; i++) {
+ int len = sSeptetTestLengths[i];
+ assertTrue(sb.length() <= len);
+
+ while (sb.length() < len) {
+ int addCount = len - sb.length();
+ int endPos = (asciiCharsLen - startPos > addCount) ?
+ (startPos + addCount) : asciiCharsLen;
+ sb.append(sAsciiChars, startPos, endPos);
+ startPos = (endPos == asciiCharsLen) ? 0 : endPos;
+ }
+ assertEquals(len, sb.length());
+
+ String testStr = sb.toString();
+ values[0] = sTestMsgCounts[i];
+ values[1] = len;
+ values[2] = sSeptetUnitsRemaining[i];
+
+ callGsmLengthMethods(testStr, false, values);
+ callGsmLengthMethods(testStr, true, values);
+ callCdmaLengthMethods(testStr, false, values);
+ callCdmaLengthMethods(testStr, true, values);
+ }
+ }
+
+ @SmallTest
+ public void testCalcLength7bitGsm() throws Exception {
+ // TODO
+ }
+
+ @SmallTest
+ public void testCalcLength7bitGsmExtended() throws Exception {
+ // TODO
+ }
+
+ @SmallTest
+ public void testCalcLengthUnicode() throws Exception {
+ StringBuilder sb = new StringBuilder(160);
+ int[] values = {0, 0, 0, SmsMessage.ENCODING_16BIT};
+ int[] values7bit = {1, 0, 0, SmsMessage.ENCODING_7BIT};
+ int startPos = 0;
+ int unicodeCharsLen = sUnicodeChars.length();
+
+ // start with length 1: empty string uses ENCODING_7BIT
+ for (int i = 1; i < sTestLengthCount; i++) {
+ int len = sUnicodeTestLengths[i];
+ assertTrue(sb.length() <= len);
+
+ while (sb.length() < len) {
+ int addCount = len - sb.length();
+ int endPos = (unicodeCharsLen - startPos > addCount) ?
+ (startPos + addCount) : unicodeCharsLen;
+ sb.append(sUnicodeChars, startPos, endPos);
+ startPos = (endPos == unicodeCharsLen) ? 0 : endPos;
+ }
+ assertEquals(len, sb.length());
+
+ String testStr = sb.toString();
+ values[0] = sTestMsgCounts[i];
+ values[1] = len;
+ values[2] = sUnicodeUnitsRemaining[i];
+ values7bit[1] = len;
+ values7bit[2] = MAX_USER_DATA_SEPTETS - len;
+
+ callGsmLengthMethods(testStr, false, values);
+ callCdmaLengthMethods(testStr, false, values);
+ callGsmLengthMethods(testStr, true, values7bit);
+ callCdmaLengthMethods(testStr, true, values7bit);
+ }
+ }
+
+ private void callGsmLengthMethods(CharSequence msgBody, boolean use7bitOnly,
+ int[] expectedValues)
+ {
+ // deprecated GSM-specific method
+ int[] values = android.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], values[0]);
+ assertEquals("codeUnitCount", expectedValues[1], values[1]);
+ assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+ assertEquals("codeUnitSize", expectedValues[3], values[3]);
+
+ int activePhone = TelephonyManager.getDefault().getPhoneType();
+ if (TelephonyManager.PHONE_TYPE_GSM == activePhone) {
+ values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], values[0]);
+ assertEquals("codeUnitCount", expectedValues[1], values[1]);
+ assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+ assertEquals("codeUnitSize", expectedValues[3], values[3]);
+ }
+
+ SmsMessageBase.TextEncodingDetails ted =
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], ted.msgCount);
+ assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
+ assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+ assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
+ }
+
+ private void callCdmaLengthMethods(CharSequence msgBody, boolean use7bitOnly,
+ int[] expectedValues)
+ {
+ int activePhone = TelephonyManager.getDefault().getPhoneType();
+ if (TelephonyManager.PHONE_TYPE_CDMA == activePhone) {
+ int[] values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], values[0]);
+ assertEquals("codeUnitCount", expectedValues[1], values[1]);
+ assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+ assertEquals("codeUnitSize", expectedValues[3], values[3]);
+ }
+
+ SmsMessageBase.TextEncodingDetails ted =
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], ted.msgCount);
+ assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
+ assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+ assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
+
+ ted = com.android.internal.telephony.cdma.sms.BearerData.calcTextEncodingDetails(msgBody, use7bitOnly);
+ assertEquals("msgCount", expectedValues[0], ted.msgCount);
+ assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
+ assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+ assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
+ }
+}
diff --git a/tests/BatteryWaster/res/layout/battery_waster.xml b/tests/BatteryWaster/res/layout/battery_waster.xml
index e1cb6bf..57a5b55 100644
--- a/tests/BatteryWaster/res/layout/battery_waster.xml
+++ b/tests/BatteryWaster/res/layout/battery_waster.xml
@@ -25,11 +25,23 @@
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginTop="25dp"
+ android:saveEnabled="false"
android:textSize="18sp"
android:textColor="#ffffffff"
android:text="@string/waste_away"
/>
+ <CheckBox android:id="@+id/checkbox_wake"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="25dp"
+ android:layout_marginTop="25dp"
+ android:saveEnabled="false"
+ android:textSize="18sp"
+ android:textColor="#ffffffff"
+ android:text="@string/wake_away"
+ />
+
<ScrollView android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="0px"
diff --git a/tests/BatteryWaster/res/values/strings.xml b/tests/BatteryWaster/res/values/strings.xml
index 46c5fa1..a3b849a 100644
--- a/tests/BatteryWaster/res/values/strings.xml
+++ b/tests/BatteryWaster/res/values/strings.xml
@@ -18,5 +18,7 @@
<string name="waste_away">Discharge my battery!</string>
+ <string name="wake_away">Keep my device awake!</string>
+
</resources>
diff --git a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
index 8ea7e00..48c4520 100644
--- a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
+++ b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
@@ -39,8 +39,11 @@
DateFormat mDateFormat;
IntentFilter mFilter;
PowerManager.WakeLock mWakeLock;
+ PowerManager.WakeLock mPartialWakeLock;
SpinThread mThread;
+ boolean mWasting, mWaking;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -50,6 +53,7 @@
setContentView(R.layout.battery_waster);
findViewById(R.id.checkbox).setOnClickListener(mClickListener);
+ findViewById(R.id.checkbox_wake).setOnClickListener(mWakeClickListener);
mLog = (TextView)findViewById(R.id.log);
mDateFormat = DateFormat.getInstance();
@@ -63,13 +67,27 @@
PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BatteryWaster");
mWakeLock.setReferenceCounted(false);
+ mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BatteryWaster");
+ mPartialWakeLock.setReferenceCounted(false);
}
@Override
public void onPause() {
+ super.onPause();
stopRunning();
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ if (mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.release();
+ }
+ }
+
View.OnClickListener mClickListener = new View.OnClickListener() {
public void onClick(View v) {
CheckBox checkbox = (CheckBox)v;
@@ -81,23 +99,63 @@
}
};
+ View.OnClickListener mWakeClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ CheckBox checkbox = (CheckBox)v;
+ if (checkbox.isChecked()) {
+ mWaking = true;
+ updateWakeLock();
+ } else {
+ mWaking = false;
+ updateWakeLock();
+ }
+ }
+ };
+
void startRunning() {
- log("Start");
- registerReceiver(mReceiver, mFilter);
- mWakeLock.acquire();
- if (mThread == null) {
- mThread = new SpinThread();
- mThread.start();
+ if (!mWasting) {
+ log("Start");
+ registerReceiver(mReceiver, mFilter);
+ mWasting = true;
+ updateWakeLock();
+ if (mThread == null) {
+ mThread = new SpinThread();
+ mThread.start();
+ }
}
}
void stopRunning() {
- log("Stop");
- unregisterReceiver(mReceiver);
- mWakeLock.release();
- if (mThread != null) {
- mThread.quit();
- mThread = null;
+ if (mWasting) {
+ log("Stop");
+ unregisterReceiver(mReceiver);
+ mWasting = false;
+ updateWakeLock();
+ if (mThread != null) {
+ mThread.quit();
+ mThread = null;
+ }
+ }
+ }
+
+ void updateWakeLock() {
+ if (mWasting) {
+ if (!mWakeLock.isHeld()) {
+ mWakeLock.acquire();
+ }
+ } else {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+ if (mWaking) {
+ if (!mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.acquire();
+ }
+ } else {
+ if (mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.release();
+ }
}
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 5855b56..31c1722 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1880,7 +1880,7 @@
className.append(inClassName);
}
}
-
+
String8 rule("-keep class ");
rule += className;
rule += " { <init>(...); }";
@@ -1955,7 +1955,7 @@
if (tag == "application") {
inApplication = true;
keepTag = true;
-
+
String8 agent = getAttribute(tree, "http://schemas.android.com/apk/res/android",
"backupAgent", &error);
if (agent.length() > 0) {
@@ -1988,9 +1988,17 @@
return NO_ERROR;
}
+struct NamespaceAttributePair {
+ const char* ns;
+ const char* attr;
+
+ NamespaceAttributePair(const char* n, const char* a) : ns(n), attr(a) {}
+ NamespaceAttributePair() : ns(NULL), attr(NULL) {}
+};
+
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
- const char* startTag, const char* altTag)
+ const char* startTag, const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs)
{
status_t err;
ResXMLTree tree;
@@ -2020,7 +2028,7 @@
return NO_ERROR;
}
}
-
+
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code != ResXMLTree::START_TAG) {
continue;
@@ -2031,16 +2039,21 @@
if (strchr(tag.string(), '.')) {
addProguardKeepRule(keep, tag, NULL,
layoutFile->getPrintableSource(), tree.getLineNumber());
- } else if (altTag != NULL && tag == altTag) {
- ssize_t classIndex = tree.indexOfAttribute(NULL, "class");
- if (classIndex < 0) {
- fprintf(stderr, "%s:%d: <view> does not have class attribute.\n",
- layoutFile->getPrintableSource().string(), tree.getLineNumber());
- } else {
- size_t len;
- addProguardKeepRule(keep,
- String8(tree.getAttributeStringValue(classIndex, &len)), NULL,
- layoutFile->getPrintableSource(), tree.getLineNumber());
+ } else if (tagAttrPairs != NULL) {
+ ssize_t tagIndex = tagAttrPairs->indexOfKey(tag);
+ if (tagIndex >= 0) {
+ const NamespaceAttributePair& nsAttr = tagAttrPairs->valueAt(tagIndex);
+ ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
+ if (attrIndex < 0) {
+ // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
+ // layoutFile->getPrintableSource().string(), tree.getLineNumber(),
+ // tag.string(), nsAttr.ns, nsAttr.attr);
+ } else {
+ size_t len;
+ addProguardKeepRule(keep,
+ String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
+ layoutFile->getPrintableSource(), tree.getLineNumber());
+ }
}
}
}
@@ -2048,25 +2061,42 @@
return NO_ERROR;
}
+static void addTagAttrPair(KeyedVector<String8, NamespaceAttributePair>* dest,
+ const char* tag, const char* ns, const char* attr) {
+ dest->add(String8(tag), NamespaceAttributePair(ns, attr));
+}
+
status_t
writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
{
status_t err;
+
+ // tag:attribute pairs that should be checked in layout files.
+ KeyedVector<String8, NamespaceAttributePair> kLayoutTagAttrPairs;
+ addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
+ addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
+
+ // tag:attribute pairs that should be checked in xml files.
+ KeyedVector<String8, NamespaceAttributePair> kXmlTagAttrPairs;
+ addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
+ addTagAttrPair(&kXmlTagAttrPairs, "Header", RESOURCES_ANDROID_NAMESPACE, "fragment");
+
const Vector<sp<AaptDir> >& dirs = assets->resDirs();
const size_t K = dirs.size();
for (size_t k=0; k<K; k++) {
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
const char* startTag = NULL;
- const char* altTag = NULL;
+ const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
- altTag = "view";
+ tagAttrPairs = &kLayoutTagAttrPairs;
} else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
startTag = "PreferenceScreen";
+ tagAttrPairs = &kXmlTagAttrPairs;
} else {
continue;
}
-
+
const KeyedVector<String8,sp<AaptGroup> > groups = d->getFiles();
const size_t N = groups.size();
for (size_t i=0; i<N; i++) {
@@ -2074,7 +2104,7 @@
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
const size_t M = files.size();
for (size_t j=0; j<M; j++) {
- err = writeProguardForXml(keep, files.valueAt(j), startTag, altTag);
+ err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
if (err < 0) {
return err;
}
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index abdc9d7..f4be839 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -191,11 +191,8 @@
*/
void continueCall() throws SipException;
- /** Puts the device to in-call mode. */
- void setInCallMode();
-
/** Puts the device to speaker mode. */
- void setSpeakerMode();
+ void setSpeakerMode(boolean speakerMode);
/** Toggles mute. */
void toggleMute();
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 474bc4b..7161309 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -485,16 +485,9 @@
return mMuted;
}
- public synchronized void setInCallMode() {
+ public synchronized void setSpeakerMode(boolean speakerMode) {
((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setSpeakerphoneOn(false);
- ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setMode(AudioManager.MODE_NORMAL);
- }
-
- public synchronized void setSpeakerMode() {
- ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setSpeakerphoneOn(true);
+ .setSpeakerphoneOn(speakerMode);
}
public void sendDtmf(int code) {
@@ -587,8 +580,15 @@
Log.d(TAG, " not sending");
audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
}
+ } else {
+ /* The recorder volume will be very low if the device is in
+ * IN_CALL mode. Therefore, we have to set the mode to NORMAL
+ * in order to have the normal microphone level.
+ */
+ ((AudioManager) mContext.getSystemService
+ (Context.AUDIO_SERVICE))
+ .setMode(AudioManager.MODE_NORMAL);
}
- setInCallMode();
AudioGroup audioGroup = new AudioGroup();
audioStream.join(audioGroup);
@@ -614,7 +614,6 @@
mRtpSession = null;
}
}
- setInCallMode();
}
private int getLocalMediaPort() {