summaryrefslogtreecommitdiffstats
path: root/core/java/android/os
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/os')
-rw-r--r--core/java/android/os/BatteryStats.java425
-rw-r--r--core/java/android/os/Binder.java44
-rw-r--r--core/java/android/os/Build.java3
-rw-r--r--core/java/android/os/Debug.java26
-rw-r--r--core/java/android/os/Environment.java12
-rw-r--r--core/java/android/os/HandlerInterface.java27
-rw-r--r--core/java/android/os/IBinder.java11
-rw-r--r--core/java/android/os/ICheckinService.aidl9
-rw-r--r--core/java/android/os/IMountService.aidl27
-rw-r--r--core/java/android/os/INetStatService.aidl15
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/os/NetStat.java224
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java18
-rw-r--r--core/java/android/os/ResultReceiver.aidl20
-rw-r--r--core/java/android/os/ResultReceiver.java130
15 files changed, 869 insertions, 123 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ed7c366..7590bfe 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1,33 +1,44 @@
package android.os;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Formatter;
import java.util.Map;
+import android.util.Log;
+import android.util.Printer;
import android.util.SparseArray;
/**
* A class providing access to battery usage statistics, including information on
* wakelocks, processes, packages, and services. All times are represented in microseconds
* except where indicated otherwise.
+ * @hide
*/
-public abstract class BatteryStats {
+public abstract class BatteryStats implements Parcelable {
+ private static final boolean LOCAL_LOGV = false;
+
/**
- * A constant indicating a partial wake lock.
+ * A constant indicating a partial wake lock timer.
*/
public static final int WAKE_TYPE_PARTIAL = 0;
/**
- * A constant indicating a full wake lock.
+ * A constant indicating a full wake lock timer.
*/
public static final int WAKE_TYPE_FULL = 1;
/**
- * A constant indicating a window wake lock.
+ * A constant indicating a window wake lock timer.
*/
public static final int WAKE_TYPE_WINDOW = 2;
+
+ /**
+ * A constant indicating a sensor timer.
+ *
+ * {@hide}
+ */
+ public static final int SENSOR = 3;
/**
* Include all of the data in the stats, including previously saved data.
@@ -48,6 +59,22 @@ public abstract class BatteryStats {
* Include only the run since the last time the device was unplugged in the stats.
*/
public static final int STATS_UNPLUGGED = 3;
+
+ /**
+ * Bump the version on this if the checkin format changes.
+ */
+ private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
+
+ // TODO: Update this list if you add/change any stats above.
+ private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
+
+ private static final String APK_DATA = "apk";
+ private static final String PROCESS_DATA = "process";
+ private static final String SENSOR_DATA = "sensor";
+ private static final String WAKELOCK_DATA = "wakelock";
+ private static final String NETWORK_DATA = "network";
+ private static final String BATTERY_DATA = "battery";
+ private static final String MISC_DATA = "misc";
private final StringBuilder mFormatBuilder = new StringBuilder(8);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
@@ -69,11 +96,16 @@ public abstract class BatteryStats {
* Returns the total time in microseconds associated with this Timer for the
* selected type of statistics.
*
- * @param now system uptime time in microseconds
+ * @param batteryRealtime system realtime on battery in microseconds
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
* @return a time in microseconds
*/
- public abstract long getTotalTime(long now, int which);
+ public abstract long getTotalTime(long batteryRealtime, int which);
+
+ /**
+ * Temporary for debugging.
+ */
+ public abstract void logState();
}
/**
@@ -115,8 +147,28 @@ public abstract class BatteryStats {
* @return a Map from Strings to Uid.Pkg objects.
*/
public abstract Map<String, ? extends Pkg> getPackageStats();
+
+ /**
+ * {@hide}
+ */
+ public abstract int getUid();
+
+ /**
+ * {@hide}
+ */
+ public abstract long getTcpBytesReceived(int which);
+
+ /**
+ * {@hide}
+ */
+ public abstract long getTcpBytesSent(int which);
public static abstract class Sensor {
+ // Magic sensor number for the GPS.
+ public static final int GPS = -10000;
+
+ public abstract int getHandle();
+
public abstract Timer getSensorTime();
}
@@ -173,11 +225,11 @@ public abstract class BatteryStats {
/**
* Returns the amount of time spent started.
*
- * @param now elapsed realtime in microseconds.
+ * @param batteryUptime elapsed uptime on battery in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @return
*/
- public abstract long getStartTime(long now, int which);
+ public abstract long getStartTime(long batteryUptime, int which);
/**
* Returns the total number of times startService() has been called.
@@ -200,7 +252,28 @@ public abstract class BatteryStats {
* Returns the number of times the device has been started.
*/
public abstract int getStartCount();
-
+
+ /**
+ * Returns the time in milliseconds that the screen has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getScreenOnTime(long batteryRealtime, int which);
+
+ /**
+ * Returns the time in milliseconds that the phone has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getPhoneOnTime(long batteryRealtime, int which);
+
+ /**
+ * Return whether we are currently running on battery.
+ */
+ public abstract boolean getIsOnBattery();
+
/**
* Returns a SparseArray containing the statistics for each uid.
*/
@@ -312,17 +385,20 @@ public abstract class BatteryStats {
*
* @param sb a StringBuilder object.
* @param timer a Timer object contining the wakelock times.
- * @param now the current time in microseconds.
+ * @param batteryRealtime the current on-battery time in microseconds.
* @param name the name of the wakelock.
* @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
- private final String printWakeLock(StringBuilder sb, Timer timer, long now,
- String name, int which, String linePrefix) {
+ private static final String printWakeLock(StringBuilder sb, Timer timer,
+ long batteryRealtime, String name, int which, String linePrefix) {
+
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
+ long totalTimeMicros = timer.getTotalTime(batteryRealtime, which);
+ long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+
int count = timer.getCount(which);
if (totalTimeMillis != 0) {
sb.append(linePrefix);
@@ -337,40 +413,225 @@ public abstract class BatteryStats {
}
return linePrefix;
}
+
+ /**
+ * Checkin version of wakelock printer. Prints simple comma-separated list.
+ *
+ * @param sb a StringBuilder object.
+ * @param timer a Timer object contining the wakelock times.
+ * @param now the current time in microseconds.
+ * @param name the name of the wakelock.
+ * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param linePrefix a String to be prepended to each line of output.
+ * @return the line prefix
+ */
+ private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
+ String name, int which, String linePrefix) {
+ long totalTimeMicros = 0;
+ int count = 0;
+ if (timer != null) {
+ totalTimeMicros = timer.getTotalTime(now, which);
+ count = timer.getCount(which);
+ }
+ sb.append(linePrefix);
+ sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
+ sb.append(',');
+ sb.append(name);
+ sb.append(',');
+ sb.append(count);
+ return ",";
+ }
+
+ /**
+ * Dump a comma-separated line of values for terse checkin mode.
+ *
+ * @param pw the PageWriter to dump log to
+ * @param category category of data (e.g. "total", "last", "unplugged", "current" )
+ * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network")
+ * @param args type-dependent data arguments
+ */
+ private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
+ Object... args ) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(uid); pw.print(',');
+ pw.print(category); pw.print(',');
+ pw.print(type);
+
+ for (Object arg : args) {
+ pw.print(',');
+ pw.print(arg);
+ }
+ pw.print('\n');
+ }
+
+ /**
+ * Checkin server version of dump to produce more compact, computer-readable log.
+ *
+ * NOTE: all times are expressed in 'ms'.
+ * @param fd
+ * @param pw
+ * @param which
+ */
+ private final void dumpCheckinLocked(PrintWriter pw, int which) {
+ final long rawUptime = SystemClock.uptimeMillis() * 1000;
+ final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryUptime = getBatteryUptime(rawUptime);
+ final long batteryRealtime = getBatteryRealtime(rawRealtime);
+ final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+ final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+ final long totalRealtime = computeRealtime(rawRealtime, which);
+ final long totalUptime = computeUptime(rawUptime, which);
+ final long screenOnTime = getScreenOnTime(batteryRealtime, which);
+ final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+
+ StringBuilder sb = new StringBuilder(128);
+
+ String category = STAT_NAMES[which];
+
+ // Dump "battery" stat
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
+ which == STATS_TOTAL ? getStartCount() : "N/A",
+ whichBatteryUptime / 1000, whichBatteryRealtime / 1000,
+ totalUptime / 1000, totalRealtime / 1000);
+
+ // Dump misc stats
+ dumpLine(pw, 0 /* uid */, category, MISC_DATA,
+ screenOnTime / 1000, phoneOnTime / 1000);
+
+ SparseArray<? extends Uid> uidStats = getUidStats();
+ final int NU = uidStats.size();
+ for (int iu = 0; iu < NU; iu++) {
+ final int uid = uidStats.keyAt(iu);
+ Uid u = uidStats.valueAt(iu);
+ // Dump Network stats per uid, if any
+ long rx = u.getTcpBytesReceived(which);
+ long tx = u.getTcpBytesSent(which);
+ if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
- @SuppressWarnings("unused")
- private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
- long uSecTime = SystemClock.elapsedRealtime() * 1000;
- final long uSecNow = getBatteryUptime(uSecTime);
+ Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
+ if (wakelocks.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
+ : wakelocks.entrySet()) {
+ Uid.Wakelock wl = ent.getValue();
+ String linePrefix = "";
+ sb.setLength(0);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
+ "full", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
+ "partial", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
+ "window", which, linePrefix);
+
+ // Only log if we had at lease one wakelock...
+ if (sb.length() > 0) {
+ dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
+ }
+ }
+ }
+
+ Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ if (sensors.size() > 0) {
+ for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+ : sensors.entrySet()) {
+ Uid.Sensor se = ent.getValue();
+ int sensorNumber = ent.getKey();
+ Timer timer = se.getSensorTime();
+ if (timer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
+ int count = timer.getCount(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
+ }
+ }
+ }
+ }
- StringBuilder sb = new StringBuilder(128);
- if (which == STATS_TOTAL) {
- pw.println(prefix + "Current and Historic Battery Usage Statistics:");
- pw.println(prefix + " System starts: " + getStartCount());
- } else if (which == STATS_LAST) {
- pw.println(prefix + "Last Battery Usage Statistics:");
- } else {
- pw.println(prefix + "Current Battery Usage Statistics:");
+ Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+ if (processStats.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+ : processStats.entrySet()) {
+ Uid.Proc ps = ent.getValue();
+
+ long userTime = ps.getUserTime(which);
+ long systemTime = ps.getSystemTime(which);
+ int starts = ps.getStarts(which);
+
+ if (userTime != 0 || systemTime != 0 || starts != 0) {
+ dumpLine(pw, uid, category, PROCESS_DATA,
+ ent.getKey(), // proc
+ userTime * 10, // cpu time in ms
+ systemTime * 10, // user time in ms
+ starts); // process starts
+ }
+ }
+ }
+
+ Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
+ if (packageStats.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
+ : packageStats.entrySet()) {
+
+ Uid.Pkg ps = ent.getValue();
+ int wakeups = ps.getWakeups(which);
+ Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
+ : serviceStats.entrySet()) {
+ BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
+ long startTime = ss.getStartTime(batteryUptime, which);
+ int starts = ss.getStarts(which);
+ int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ dumpLine(pw, uid, category, APK_DATA,
+ wakeups, // wakeup alarms
+ ent.getKey(), // Apk
+ sent.getKey(), // service
+ startTime / 1000, // time spent started, in ms
+ starts,
+ launches);
+ }
+ }
+ }
+ }
}
- long batteryUptime = computeBatteryUptime(uSecNow, which);
- long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
- long elapsedRealtime = computeRealtime(uSecTime, which);
- long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
+ }
+
+ @SuppressWarnings("unused")
+ private final void dumpLocked(Printer pw, String prefix, int which) {
+ final long rawUptime = SystemClock.uptimeMillis() * 1000;
+ final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryUptime = getBatteryUptime(rawUptime);
+ final long batteryRealtime = getBatteryUptime(rawRealtime);
+
+ final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+ final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+ final long totalRealtime = computeRealtime(rawRealtime, which);
+ final long totalUptime = computeUptime(rawUptime, which);
+
+ StringBuilder sb = new StringBuilder(128);
pw.println(prefix
- + " On battery: " + formatTimeMs(batteryUptime / 1000) + "("
- + formatRatioLocked(batteryUptime, batteryRealtime)
+ + " Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
+ + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+ ") uptime, "
- + formatTimeMs(batteryRealtime / 1000) + "("
- + formatRatioLocked(batteryRealtime, elapsedRealtime)
+ + formatTimeMs(whichBatteryRealtime / 1000) + "("
+ + formatRatioLocked(whichBatteryRealtime, totalRealtime)
+ ") realtime");
pw.println(prefix
+ " Total: "
- + formatTimeMs(uptime / 1000)
+ + formatTimeMs(totalUptime / 1000)
+ "uptime, "
- + formatTimeMs(elapsedRealtime / 1000)
+ + formatTimeMs(totalRealtime / 1000)
+ "realtime");
-
+
+ long screenOnTime = getScreenOnTime(batteryRealtime, which);
+ long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+ pw.println(prefix
+ + " Time with screen on: " + formatTimeMs(screenOnTime / 1000)
+ + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
+ + "), time with phone on: " + formatTimeMs(phoneOnTime / 1000)
+ + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")");
+
pw.println(" ");
SparseArray<? extends Uid> uidStats = getUidStats();
@@ -380,6 +641,13 @@ public abstract class BatteryStats {
Uid u = uidStats.valueAt(iu);
pw.println(prefix + " #" + uid + ":");
boolean uidActivity = false;
+
+ long tcpReceived = u.getTcpBytesReceived(which);
+ long tcpSent = u.getTcpBytesSent(which);
+ if (tcpReceived != 0 || tcpSent != 0) {
+ pw.println(prefix + " Network: " + tcpReceived + " bytes received, "
+ + tcpSent + " bytes sent");
+ }
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
@@ -391,13 +659,15 @@ public abstract class BatteryStats {
sb.append(prefix);
sb.append(" Wake lock ");
sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
"full", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
"partial", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
"window", which, linePrefix);
- if (linePrefix.equals(": ")) {
+ if (!linePrefix.equals(": ")) {
+ sb.append(" realtime");
+ } else {
sb.append(": (nothing executed)");
}
pw.println(sb.toString());
@@ -414,23 +684,30 @@ public abstract class BatteryStats {
sb.setLength(0);
sb.append(prefix);
sb.append(" Sensor ");
- sb.append(sensorNumber);
+ int handle = se.getHandle();
+ if (handle == Uid.Sensor.GPS) {
+ sb.append("GPS");
+ } else {
+ sb.append(handle);
+ }
+ sb.append(": ");
Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
+ long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
int count = timer.getCount(which);
+ //timer.logState();
if (totalTime != 0) {
- sb.append(": ");
sb.append(formatTimeMs(totalTime));
- sb.append(' ');
- sb.append('(');
+ sb.append("realtime (");
sb.append(count);
sb.append(" times)");
+ } else {
+ sb.append("(not used)");
}
} else {
- sb.append(": (none used)");
+ sb.append("(not used)");
}
pw.println(sb.toString());
@@ -478,13 +755,14 @@ public abstract class BatteryStats {
for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
: serviceStats.entrySet()) {
BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(uSecNow, which);
+ long startTime = ss.getStartTime(batteryUptime, which);
int starts = ss.getStarts(which);
int launches = ss.getLaunches(which);
if (startTime != 0 || starts != 0 || launches != 0) {
pw.println(prefix + " Service " + sent.getKey() + ":");
- pw.println(prefix + " Time spent started: "
- + formatTimeMs(startTime / 1000));
+ pw.println(prefix + " Created for: "
+ + formatTimeMs(startTime / 1000)
+ + " uptime");
pw.println(prefix + " Starts: " + starts
+ ", launches: " + launches);
apkActivity = true;
@@ -506,18 +784,45 @@ public abstract class BatteryStats {
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
- * @param fd a FileDescriptor, currently unused.
- * @param pw a PrintWriter to receive the dump output.
- * @param args an array of Strings, currently unused.
+ * @param pw a Printer to receive the dump output.
*/
@SuppressWarnings("unused")
- public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (this) {
- dumpLocked(fd, pw, "", STATS_TOTAL);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_LAST);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_CURRENT);
+ public void dumpLocked(Printer pw) {
+ pw.println("Total Statistics (Current and Historic):");
+ pw.println(" System starts: " + getStartCount()
+ + ", currently on battery: " + getIsOnBattery());
+ dumpLocked(pw, "", STATS_TOTAL);
+ pw.println("");
+ pw.println("Last Run Statistics (Previous run of system):");
+ dumpLocked(pw, "", STATS_LAST);
+ pw.println("");
+ pw.println("Current Battery Statistics (Currently running system):");
+ dumpLocked(pw, "", STATS_CURRENT);
+ pw.println("");
+ pw.println("Unplugged Statistics (Since last unplugged from power):");
+ dumpLocked(pw, "", STATS_UNPLUGGED);
+ }
+
+ @SuppressWarnings("unused")
+ public void dumpCheckinLocked(PrintWriter pw, String[] args) {
+ boolean isUnpluggedOnly = false;
+
+ for (String arg : args) {
+ if ("-u".equals(arg)) {
+ if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data");
+ isUnpluggedOnly = true;
+ }
+ }
+
+ if (isUnpluggedOnly) {
+ dumpCheckinLocked(pw, STATS_UNPLUGGED);
+ }
+ else {
+ dumpCheckinLocked(pw, STATS_TOTAL);
+ dumpCheckinLocked(pw, STATS_LAST);
+ dumpCheckinLocked(pw, STATS_UNPLUGGED);
+ dumpCheckinLocked(pw, STATS_CURRENT);
}
}
+
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 528e6bd..df10c6a 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -33,7 +33,7 @@ import java.lang.reflect.Modifier;
* the standard support creating a local implementation of such an object.
*
* <p>Most developers will not implement this class directly, instead using the
- * <a href="{@docRoot}reference/aidl.html">aidl</a> tool to describe the desired
+ * <a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a> tool to describe the desired
* interface, having it generate the appropriate Binder subclass. You can,
* however, derive directly from Binder to implement your own custom RPC
* protocol or simply instantiate a raw Binder object directly to use as a
@@ -194,18 +194,15 @@ public class Binder implements IBinder {
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
- FileOutputStream fout = fd != null
- ? new FileOutputStream(fd.getFileDescriptor()) : null;
- PrintWriter pw = fout != null ? new PrintWriter(fout) : null;
- if (pw != null) {
- String[] args = data.readStringArray();
- dump(fd.getFileDescriptor(), pw, args);
- pw.flush();
- }
+ String[] args = data.readStringArray();
if (fd != null) {
try {
- fd.close();
- } catch (IOException e) {
+ dump(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
}
}
return true;
@@ -214,6 +211,20 @@ public class Binder implements IBinder {
}
/**
+ * Implemented to call the more convenient version
+ * {@link #dump(FileDescriptor, PrintWriter, String[])}.
+ */
+ public void dump(FileDescriptor fd, String[] args) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new PrintWriter(fout);
+ try {
+ dump(fd, pw, args);
+ } finally {
+ pw.flush();
+ }
+ }
+
+ /**
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
@@ -302,6 +313,17 @@ final class BinderProxy implements IBinder {
throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
+ public void dump(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ try {
+ transact(DUMP_TRANSACTION, data, null, 0);
+ } finally {
+ data.recycle();
+ }
+ }
+
BinderProxy() {
mSelf = new WeakReference(this);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index cdf907b..467c17f 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -26,6 +26,9 @@ public class Build {
/** Either a changelist number, or a label like "M4-rc20". */
public static final String ID = getString("ro.build.id");
+ /** A build ID string meant for displaying to the user */
+ public static final String DISPLAY = getString("ro.build.display.id");
+
/** The name of the overall product. */
public static final String PRODUCT = getString("ro.product.name");
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 5f7f91f..950bb09 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -17,6 +17,7 @@
package android.os;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
@@ -28,12 +29,13 @@ import dalvik.bytecode.Opcodes;
import dalvik.system.VMDebug;
-/** Provides various debugging functions for Android applications, including
+/**
+ * Provides various debugging functions for Android applications, including
* tracing and allocation counts.
* <p><strong>Logging Trace Files</strong></p>
* <p>Debug can create log files that give details about an application, such as
* a call stack and start/stop times for any running methods. See <a
-href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files. To start logging trace files, call one
* of the startMethodTracing() methods. To stop tracing, call
* {@link #stopMethodTracing()}.
@@ -285,7 +287,7 @@ public final class Debug
/**
* Start method tracing with default log name and buffer size. See <a
-href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading these files. Call stopMethodTracing() to stop
* tracing.
*/
@@ -297,7 +299,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name. The trace
* file will be put under "/sdcard" unless an absolute path is given.
* See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
*
* @param traceName Name for the trace log file to create.
@@ -313,7 +315,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name and the
* buffer size. The trace files will be put under "/sdcard" unless an
* absolute path is given. See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
* @param traceName Name for the trace log file to create.
* If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
@@ -330,7 +332,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name and the
* buffer size. The trace files will be put under "/sdcard" unless an
* absolute path is given. See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
*
* <p>
@@ -581,6 +583,18 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
}
/**
+ * Dump "hprof" data to the specified file. This will cause a GC.
+ *
+ * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
+ * @throws UnsupportedOperationException if the VM was built without
+ * HPROF support.
+ * @throws IOException if an error occurs while opening or writing files.
+ */
+ public static void dumpHprofData(String fileName) throws IOException {
+ VMDebug.dumpHprofData(fileName);
+ }
+
+ /**
* Returns the number of sent transactions from this process.
* @return The number of sent transactions or -1 if it could not read t.
*/
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e37b551..f761e8e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -75,6 +75,18 @@ public class Environment {
public static final String MEDIA_UNMOUNTED = "unmounted";
/**
+ * getExternalStorageState() returns MEDIA_CHECKING if the media is present
+ * and being disk-checked
+ */
+ public static final String MEDIA_CHECKING = "checking";
+
+ /**
+ * getExternalStorageState() returns MEDIA_NOFS if the media is present
+ * but is blank or is using an unsupported filesystem
+ */
+ public static final String MEDIA_NOFS = "nofs";
+
+ /**
* getExternalStorageState() returns MEDIA_MOUNTED if the media is present
* and mounted at its mount point with read/write access.
*/
diff --git a/core/java/android/os/HandlerInterface.java b/core/java/android/os/HandlerInterface.java
deleted file mode 100644
index 62dc273..0000000
--- a/core/java/android/os/HandlerInterface.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
- * @hide
- * @deprecated
- */
-public interface HandlerInterface
-{
- void handleMessage(Message msg);
-}
-
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 3ec0e9b..5c40c9a0 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,6 +16,9 @@
package android.os;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Base interface for a remotable object, the core part of a lightweight
* remote procedure call mechanism designed for high performance when
@@ -145,6 +148,14 @@ public interface IBinder {
public IInterface queryLocalInterface(String descriptor);
/**
+ * Print the object's state into the given stream.
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param args additional arguments to the dump request.
+ */
+ public void dump(FileDescriptor fd, String[] args) throws RemoteException;
+
+ /**
* Perform a generic operation with the object.
*
* @param code The action to perform. This should
diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl
index 70ad28e..e56b55d 100644
--- a/core/java/android/os/ICheckinService.aidl
+++ b/core/java/android/os/ICheckinService.aidl
@@ -26,6 +26,15 @@ import android.os.IParentalControlCallback;
* {@hide}
*/
interface ICheckinService {
+ /** Synchronously attempt a checkin with the server, return true
+ * on success.
+ * @throws IllegalStateException whenever an error occurs. The
+ * cause of the exception will be the real exception:
+ * IOException for network errors, JSONException for invalid
+ * server responses, etc.
+ */
+ boolean checkin();
+
/** Direct submission of crash data; returns after writing the crash. */
void reportCrashSync(in byte[] crashData);
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 0397446..96d44b6 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -48,4 +48,31 @@ interface IMountService
* Safely unmount external storage at given mount point.
*/
void unmountMedia(String mountPoint);
+
+ /**
+ * Format external storage given a mount point.
+ */
+ void formatMedia(String mountPoint);
+
+ /**
+ * Returns true if media notification sounds are enabled.
+ */
+ boolean getPlayNotificationSounds();
+
+ /**
+ * Sets whether or not media notification sounds are played.
+ */
+ void setPlayNotificationSounds(boolean value);
+
+ /**
+ * Returns true if USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ boolean getAutoStartUms();
+
+ /**
+ * Sets whether or not USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ void setAutoStartUms(boolean value);
}
diff --git a/core/java/android/os/INetStatService.aidl b/core/java/android/os/INetStatService.aidl
index fb840d8..a8f3de0 100644
--- a/core/java/android/os/INetStatService.aidl
+++ b/core/java/android/os/INetStatService.aidl
@@ -17,14 +17,19 @@
package android.os;
/**
- * Retrieves packet and byte counts for the phone data interface.
+ * Retrieves packet and byte counts for the phone data interface,
+ * and for all interfaces.
* Used for the data activity icon and the phone status in Settings.
*
* {@hide}
*/
interface INetStatService {
- int getTxPackets();
- int getRxPackets();
- int getTxBytes();
- int getRxBytes();
+ long getMobileTxPackets();
+ long getMobileRxPackets();
+ long getMobileTxBytes();
+ long getMobileRxBytes();
+ long getTotalTxPackets();
+ long getTotalRxPackets();
+ long getTotalTxBytes();
+ long getTotalRxBytes();
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index e48f152..5486920 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -29,4 +29,5 @@ interface IPowerManager
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
+ void setScreenBrightnessOverride(int brightness);
}
diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java
index 7312236..e294cdf 100644
--- a/core/java/android/os/NetStat.java
+++ b/core/java/android/os/NetStat.java
@@ -16,36 +16,232 @@
package android.os;
+import android.util.Log;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+
/** @hide */
-public class NetStat{
+public class NetStat {
+
+ // Logging tag.
+ private final static String TAG = "netstat";
+
+ // We pre-create all the File objects so we don't spend a lot of
+ // CPU at runtime converting from Java Strings to byte[] for the
+ // kernel calls.
+ private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets");
+ private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets");
+ private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes");
+ private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes");
+ private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net");
/**
- * Get total number of tx packets sent through ppp0
+ * Get total number of tx packets sent through rmnet0 or ppp0
*
- * @return number of Tx packets through ppp0
+ * @return number of Tx packets through rmnet0 or ppp0
*/
+ public static long getMobileTxPkts() {
+ return getMobileStat(MOBILE_TX_PACKETS);
+ }
- public native static int netStatGetTxPkts();
+ /**
+ * Get total number of rx packets received through rmnet0 or ppp0
+ *
+ * @return number of Rx packets through rmnet0 or ppp0
+ */
+ public static long getMobileRxPkts() {
+ return getMobileStat(MOBILE_RX_PACKETS);
+ }
/**
- * Get total number of rx packets received through ppp0
+ * Get total number of tx bytes received through rmnet0 or ppp0
*
- * @return number of Rx packets through ppp0
+ * @return number of Tx bytes through rmnet0 or ppp0
*/
- public native static int netStatGetRxPkts();
+ public static long getMobileTxBytes() {
+ return getMobileStat(MOBILE_TX_BYTES);
+ }
- /**
- * Get total number of tx bytes received through ppp0
+ /**
+ * Get total number of rx bytes received through rmnet0 or ppp0
*
- * @return number of Tx bytes through ppp0
+ * @return number of Rx bytes through rmnet0 or ppp0
*/
- public native static int netStatGetTxBytes();
+ public static long getMobileRxBytes() {
+ return getMobileStat(MOBILE_RX_BYTES);
+ }
/**
- * Get total number of rx bytes received through ppp0
+ * Get the total number of packets sent through all network interfaces.
*
- * @return number of Rx bytes through ppp0
+ * @return the number of packets sent through all network interfaces
*/
- public native static int netStatGetRxBytes();
+ public static long getTotalTxPkts() {
+ return getTotalStat("tx_packets");
+ }
+
+ /**
+ * Get the total number of packets received through all network interfaces.
+ *
+ * @return the number of packets received through all network interfaces
+ */
+ public static long getTotalRxPkts() {
+ return getTotalStat("rx_packets");
+ }
+
+ /**
+ * Get the total number of bytes sent through all network interfaces.
+ *
+ * @return the number of bytes sent through all network interfaces
+ */
+ public static long getTotalTxBytes() {
+ return getTotalStat("tx_bytes");
+ }
+
+ /**
+ * Get the total number of bytes received through all network interfaces.
+ *
+ * @return the number of bytes received through all network interfaces
+ */
+ public static long getTotalRxBytes() {
+ return getTotalStat("rx_bytes");
+ }
+
+ /**
+ * Gets network bytes sent for this UID.
+ * The statistics are across all interfaces.
+ * The statistics come from /proc/uid_stat.
+ *
+ * {@see android.os.Process#myUid()}.
+ *
+ * @param uid
+ * @return byte count
+ */
+ public static long getUidTxBytes(int uid) {
+ return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd");
+ }
+
+ /**
+ * Gets network bytes received for this UID.
+ * The statistics are across all interfaces.
+ * The statistics come from /proc/uid_stat.
+ *
+ * {@see android.os.Process#myUid()}.
+ *
+ * @param uid
+ * @return byte count
+ */
+ public static long getUidRxBytes(int uid) {
+ return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv");
+ }
+
+ /**
+ * Returns the array of two possible File locations for a given
+ * statistic.
+ */
+ private static File[] mobileFiles(String whatStat) {
+ // Note that we stat them at runtime to see which is
+ // available, rather than here, to guard against the files
+ // coming & going later as modules shut down (e.g. airplane
+ // mode) and whatnot. The runtime stat() isn't expensive compared
+ // to the previous charset conversion that happened before we
+ // were reusing File instances.
+ File[] files = new File[2];
+ files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat);
+ files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat);
+ return files;
+ }
+
+ private static long getTotalStat(String whatStat) {
+ File netdir = new File("/sys/class/net");
+
+ File[] nets = SYS_CLASS_NET_DIR.listFiles();
+ if (nets == null) {
+ return 0;
+ }
+ long total = 0;
+ StringBuffer strbuf = new StringBuffer();
+ for (File net : nets) {
+ strbuf.append(net.getPath()).append(File.separator).append("statistics")
+ .append(File.separator).append(whatStat);
+ total += getNumberFromFilePath(strbuf.toString());
+ strbuf.setLength(0);
+ }
+ return total;
+ }
+
+ private static long getMobileStat(File[] files) {
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ if (!file.exists()) {
+ continue;
+ }
+ try {
+ RandomAccessFile raf = new RandomAccessFile(file, "r");
+ return getNumberFromFile(raf, file.getAbsolutePath());
+ } catch (IOException e) {
+ Log.w(TAG,
+ "Exception opening TCP statistics file " + file.getAbsolutePath(),
+ e);
+ }
+ }
+ return 0L;
+ }
+
+ // File will have format <number><newline>
+ private static long getNumberFromFilePath(String filename) {
+ RandomAccessFile raf = getFile(filename);
+ if (raf == null) {
+ return 0L;
+ }
+ return getNumberFromFile(raf, filename);
+ }
+
+ // Private buffer for getNumberFromFile. Safe for re-use because
+ // getNumberFromFile is synchronized.
+ private final static byte[] buf = new byte[16];
+
+ private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) {
+ try {
+ raf.read(buf);
+ raf.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Exception getting TCP bytes from " + filename, e);
+ return 0L;
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Exception closing " + filename, e);
+ }
+ }
+ }
+
+ long num = 0L;
+ for (int i = 0; i < buf.length; i++) {
+ if (buf[i] < '0' || buf[i] > '9') {
+ break;
+ }
+ num *= 10;
+ num += buf[i] - '0';
+ }
+ return num;
+ }
+
+ private static RandomAccessFile getFile(String filename) {
+ File f = new File(filename);
+ if (!f.canRead()) {
+ return null;
+ }
+ try {
+ return new RandomAccessFile(f, "r");
+ } catch (IOException e) {
+ Log.w(TAG, "Exception opening TCP statistics file " + filename, e);
+ return null;
+ }
+ }
}
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index ed138cb..3fcb18e 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -76,6 +76,11 @@ public class ParcelFileDescriptor implements Parcelable {
public static final int MODE_TRUNCATE = 0x04000000;
/**
+ * For use with {@link #open}: append to end of file while writing.
+ */
+ public static final int MODE_APPEND = 0x02000000;
+
+ /**
* Create a new ParcelFileDescriptor accessing a given file.
*
* @param file The file to be opened.
@@ -138,6 +143,19 @@ public class ParcelFileDescriptor implements Parcelable {
}
/**
+ * Return the total size of the file representing this fd, as determined
+ * by stat(). Returns -1 if the fd is not a file.
+ */
+ public native long getStatSize();
+
+ /**
+ * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
+ * and I really don't think we want it to be public.
+ * @hide
+ */
+ public native long seekTo(long pos);
+
+ /**
* Close the ParcelFileDescriptor. This implementation closes the underlying
* OS resources allocated to represent this stream.
*
diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl
new file mode 100644
index 0000000..28ce6d5
--- /dev/null
+++ b/core/java/android/os/ResultReceiver.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/os/ParcelFileDescriptor.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable ResultReceiver;
diff --git a/core/java/android/os/ResultReceiver.java b/core/java/android/os/ResultReceiver.java
new file mode 100644
index 0000000..711d4d9
--- /dev/null
+++ b/core/java/android/os/ResultReceiver.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import com.android.internal.os.IResultReceiver;
+
+/**
+ * Generic interface for receiving a callback result from someone. Use this
+ * by creating a subclass and implement {@link #onReceiveResult}, which you can
+ * then pass to others and send through IPC, and receive results they
+ * supply with {@link #send}.
+ */
+public class ResultReceiver implements Parcelable {
+ final boolean mLocal;
+ final Handler mHandler;
+
+ IResultReceiver mReceiver;
+
+ class MyRunnable implements Runnable {
+ final int mResultCode;
+ final Bundle mResultData;
+
+ MyRunnable(int resultCode, Bundle resultData) {
+ mResultCode = resultCode;
+ mResultData = resultData;
+ }
+
+ public void run() {
+ onReceiveResult(mResultCode, mResultData);
+ }
+ }
+
+ class MyResultReceiver extends IResultReceiver.Stub {
+ public void send(int resultCode, Bundle resultData) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ }
+ }
+
+ /**
+ * Create a new ResultReceive to receive results. Your
+ * {@link #onReceiveResult} method will be called from the thread running
+ * <var>handler</var> if given, or from an arbitrary thread if null.
+ */
+ public ResultReceiver(Handler handler) {
+ mLocal = true;
+ mHandler = handler;
+ }
+
+ /**
+ * Deliver a result to this receiver. Will call {@link #onReceiveResult},
+ * always asynchronously if the receiver has supplied a Handler in which
+ * to dispatch the result.
+ * @param resultCode Arbitrary result code to deliver, as defined by you.
+ * @param resultData Any additional data provided by you.
+ */
+ public void send(int resultCode, Bundle resultData) {
+ if (mLocal) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ return;
+ }
+
+ if (mReceiver != null) {
+ try {
+ mReceiver.send(resultCode, resultData);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
+ * Override to receive results delivered to this object.
+ *
+ * @param resultCode Arbitrary result code delivered by the sender, as
+ * defined by the sender.
+ * @param resultData Any additional data provided by the sender.
+ */
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ synchronized (this) {
+ if (mReceiver == null) {
+ mReceiver = new MyResultReceiver();
+ }
+ out.writeStrongBinder(mReceiver.asBinder());
+ }
+ }
+
+ ResultReceiver(Parcel in) {
+ mLocal = false;
+ mHandler = null;
+ mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
+ }
+
+ public static final Parcelable.Creator<ResultReceiver> CREATOR
+ = new Parcelable.Creator<ResultReceiver>() {
+ public ResultReceiver createFromParcel(Parcel in) {
+ return new ResultReceiver(in);
+ }
+ public ResultReceiver[] newArray(int size) {
+ return new ResultReceiver[size];
+ }
+ };
+}