Merge commit 'goog/readonly-p4-master'

This commit is contained in:
The Android Open Source Project
2009-03-31 21:34:25 -07:00
50 changed files with 1569 additions and 413 deletions

View File

@@ -485,7 +485,8 @@ public class BluetoothDevice {
* Get the major, minor and servics classes of a remote device.
* These classes are encoded as a 32-bit integer. See BluetoothClass.
* @param address remote device
* @return 32-bit class suitable for use with BluetoothClass.
* @return 32-bit class suitable for use with BluetoothClass, or
* BluetoothClass.ERROR on error
*/
public int getRemoteClass(String address) {
try {

View File

@@ -40,19 +40,26 @@ public abstract class BatteryStats implements Parcelable {
*/
public static final int SENSOR = 3;
/**
* A constant indicating a a wifi turn on timer
*
* {@hide}
*/
public static final int WIFI_TURNED_ON = 4;
/**
* A constant indicating a full wifi lock timer
*
* {@hide}
*/
public static final int FULL_WIFI_LOCK = 4;
public static final int FULL_WIFI_LOCK = 5;
/**
* A constant indicating a scan wifi lock timer
*
* {@hide}
*/
public static final int SCAN_WIFI_LOCK = 5;
public static final int SCAN_WIFI_LOCK = 6;
/**
* Include all of the data in the stats, including previously saved data.
@@ -77,7 +84,11 @@ public abstract class BatteryStats implements Parcelable {
/**
* Bump the version on this if the checkin format changes.
*/
private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
private static final int BATTERY_STATS_CHECKIN_VERSION = 3;
private static final long BYTES_PER_KB = 1024;
private static final long BYTES_PER_MB = 1048576; // 1024^2
private static final long BYTES_PER_GB = 1073741824; //1024^3
// TODO: Update this list if you add/change any stats above.
private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
@@ -87,15 +98,38 @@ public abstract class BatteryStats implements Parcelable {
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 USER_ACTIVITY_DATA = "useract";
private static final String BATTERY_DATA = "battery";
private static final String WIFI_LOCK_DATA = "wifilock";
private static final String MISC_DATA = "misc";
private static final String SIGNAL_STRENGTH_DATA = "signal";
private static final String DATA_CONNECTION_DATA = "dataconn";
private static final String SCREEN_BRIGHTNESS_DATA = "brightness";
private static final String SIGNAL_STRENGTH_TIME_DATA = "sigtime";
private static final String SIGNAL_STRENGTH_COUNT_DATA = "sigcnt";
private static final String DATA_CONNECTION_TIME_DATA = "dconntime";
private static final String DATA_CONNECTION_COUNT_DATA = "dconncnt";
private final StringBuilder mFormatBuilder = new StringBuilder(8);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
/**
* State for keeping track of counting information.
*/
public static abstract class Counter {
/**
* Returns the count associated with this Counter for the
* selected type of statistics.
*
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
*/
public abstract int getCount(int which);
/**
* Temporary for debugging.
*/
public abstract void logState(Printer pw, String prefix);
}
/**
* State for keeping track of timing information.
*/
@@ -180,13 +214,29 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getTcpBytesSent(int which);
public abstract void noteWifiTurnedOnLocked();
public abstract void noteWifiTurnedOffLocked();
public abstract void noteFullWifiLockAcquiredLocked();
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteScanWifiLockAcquiredLocked();
public abstract void noteScanWifiLockReleasedLocked();
public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getScanWifiLockTime(long batteryRealtime, int which);
/**
* Note that these must match the constants in android.os.LocalPowerManager.
*/
static final String[] USER_ACTIVITY_TYPES = {
"other", "cheek", "touch", "long_touch", "touch_up", "button", "unknown"
};
public static final int NUM_USER_ACTIVITY_TYPES = 7;
public abstract void noteUserActivityLocked(int type);
public abstract boolean hasUserActivity();
public abstract int getUserActivityCount(int type, int which);
public static abstract class Sensor {
// Magic sensor number for the GPS.
public static final int GPS = -10000;
@@ -285,6 +335,29 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getScreenOnTime(long batteryRealtime, int which);
public static final int SCREEN_BRIGHTNESS_DARK = 0;
public static final int SCREEN_BRIGHTNESS_DIM = 1;
public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
public static final int SCREEN_BRIGHTNESS_LIGHT = 3;
public static final int SCREEN_BRIGHTNESS_BRIGHT = 4;
static final String[] SCREEN_BRIGHTNESS_NAMES = {
"dark", "dim", "medium", "light", "bright"
};
public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5;
/**
* Returns the time in milliseconds that the screen has been on with
* the given brightness
*
* {@hide}
*/
public abstract long getScreenBrightnessTime(int brightnessBin,
long batteryRealtime, int which);
public abstract int getInputEventCount(int which);
/**
* Returns the time in milliseconds that the phone has been on while the device was
* running on battery.
@@ -314,6 +387,13 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getPhoneSignalStrengthTime(int strengthBin,
long batteryRealtime, int which);
/**
* Returns the number of times the phone has entered the given signal strength.
*
* {@hide}
*/
public abstract int getPhoneSignalStrengthCount(int strengthBin, int which);
public static final int DATA_CONNECTION_NONE = 0;
public static final int DATA_CONNECTION_GPRS = 1;
public static final int DATA_CONNECTION_EDGE = 2;
@@ -335,6 +415,14 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getPhoneDataConnectionTime(int dataType,
long batteryRealtime, int which);
/**
* Returns the number of times the phone has entered the given data
* connection type.
*
* {@hide}
*/
public abstract int getPhoneDataConnectionCount(int dataType, int which);
/**
* Returns the time in milliseconds that wifi has been on while the device was
* running on battery.
@@ -482,6 +570,23 @@ public abstract class BatteryStats implements Parcelable {
return mFormatBuilder.toString();
}
private final String formatBytesLocked(long bytes) {
mFormatBuilder.setLength(0);
if (bytes < BYTES_PER_KB) {
return bytes + "B";
} else if (bytes < BYTES_PER_MB) {
mFormatter.format("%.2fKB", bytes / (double) BYTES_PER_KB);
return mFormatBuilder.toString();
} else if (bytes < BYTES_PER_GB){
mFormatter.format("%.2fMB", bytes / (double) BYTES_PER_MB);
return mFormatBuilder.toString();
} else {
mFormatter.format("%.2fGB", bytes / (double) BYTES_PER_GB);
return mFormatBuilder.toString();
}
}
/**
*
* @param sb a StringBuilder object.
@@ -590,40 +695,89 @@ public abstract class BatteryStats implements Parcelable {
StringBuilder sb = new StringBuilder(128);
SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
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);
whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
totalRealtime / 1000, totalUptime / 1000);
// Calculate total network and wakelock times across all uids.
long rxTotal = 0;
long txTotal = 0;
long fullWakeLockTimeTotal = 0;
long partialWakeLockTimeTotal = 0;
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
rxTotal += u.getTcpBytesReceived(which);
txTotal += u.getTcpBytesSent(which);
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();
Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
if (fullWakeTimer != null) {
fullWakeLockTimeTotal += fullWakeTimer.getTotalTime(batteryRealtime, which);
}
Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
if (partialWakeTimer != null) {
partialWakeLockTimeTotal += partialWakeTimer.getTotalTime(
batteryRealtime, which);
}
}
}
}
// Dump misc stats
dumpLine(pw, 0 /* uid */, category, MISC_DATA,
screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000,
wifiRunningTime / 1000, bluetoothOnTime / 1000);
wifiRunningTime / 1000, bluetoothOnTime / 1000, rxTotal, txTotal,
fullWakeLockTimeTotal, partialWakeLockTimeTotal,
getInputEventCount(which));
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
args[i] = getScreenBrightnessTime(i, batteryRealtime, which) / 1000;
}
dumpLine(pw, 0 /* uid */, category, SCREEN_BRIGHTNESS_DATA, args);
// Dump signal strength stats
Object[] args = new Object[NUM_SIGNAL_STRENGTH_BINS];
args = new Object[NUM_SIGNAL_STRENGTH_BINS];
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
args[i] = getPhoneSignalStrengthTime(i, batteryRealtime, which) / 1000;
}
dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_DATA, args);
dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_TIME_DATA, args);
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
args[i] = getPhoneSignalStrengthCount(i, which);
}
dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_COUNT_DATA, args);
// Dump network type stats
args = new Object[NUM_DATA_CONNECTION_TYPES];
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
args[i] = getPhoneDataConnectionTime(i, batteryRealtime, which) / 1000;
}
dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_DATA, args);
dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_TIME_DATA, args);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
args[i] = getPhoneDataConnectionCount(i, which);
}
dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args);
if (which == STATS_UNPLUGGED) {
dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(),
getPluggedStartLevel());
}
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);
@@ -632,14 +786,29 @@ public abstract class BatteryStats implements Parcelable {
long tx = u.getTcpBytesSent(which);
long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
|| wifiTurnedOnTime != 0) {
dumpLine(pw, uid, category, WIFI_LOCK_DATA,
fullWifiLockOnTime, scanWifiLockOnTime);
fullWifiLockOnTime, scanWifiLockOnTime, wifiTurnedOnTime);
}
if (u.hasUserActivity()) {
args = new Object[Uid.NUM_USER_ACTIVITY_TYPES];
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
int val = u.getUserActivityCount(i, which);
args[i] = val;
if (val != 0) hasData = true;
}
if (hasData) {
dumpLine(pw, 0 /* uid */, category, USER_ACTIVITY_DATA, args);
}
}
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
@@ -741,20 +910,24 @@ public abstract class BatteryStats implements Parcelable {
final long totalUptime = computeUptime(rawUptime, which);
StringBuilder sb = new StringBuilder(128);
SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
pw.println(prefix
+ " Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
+ "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+ ") uptime, "
+ " Time on battery: "
+ formatTimeMs(whichBatteryRealtime / 1000) + "("
+ formatRatioLocked(whichBatteryRealtime, totalRealtime)
+ ") realtime");
+ ") realtime, "
+ formatTimeMs(whichBatteryUptime / 1000)
+ "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+ ") uptime");
pw.println(prefix
+ " Total: "
+ formatTimeMs(totalUptime / 1000)
+ "uptime, "
+ " Total run time: "
+ formatTimeMs(totalRealtime / 1000)
+ "realtime");
+ "realtime, "
+ formatTimeMs(totalUptime / 1000)
+ "uptime, ");
final long screenOnTime = getScreenOnTime(batteryRealtime, which);
final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
@@ -764,19 +937,73 @@ public abstract class BatteryStats implements Parcelable {
pw.println(prefix
+ " Screen on: " + formatTimeMs(screenOnTime / 1000)
+ "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
+ "), Phone on: " + formatTimeMs(phoneOnTime / 1000)
+ "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+ "), Input events: " + getInputEventCount(which)
+ ", Active phone call: " + formatTimeMs(phoneOnTime / 1000)
+ "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")");
sb.setLength(0);
sb.append(" Screen brightnesses: ");
boolean didOne = false;
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
final long time = getScreenBrightnessTime(i, batteryRealtime, which);
if (time == 0) {
continue;
}
if (didOne) sb.append(", ");
didOne = true;
sb.append(SCREEN_BRIGHTNESS_NAMES[i]);
sb.append(" ");
sb.append(formatTimeMs(time/1000));
sb.append("(");
sb.append(formatRatioLocked(time, screenOnTime));
sb.append(")");
}
if (!didOne) sb.append("No activity");
pw.println(sb.toString());
// Calculate total network and wakelock times across all uids.
long rxTotal = 0;
long txTotal = 0;
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
rxTotal += u.getTcpBytesReceived(which);
txTotal += u.getTcpBytesSent(which);
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();
Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
if (fullWakeTimer != null) {
fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTime(
batteryRealtime, which);
}
Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
if (partialWakeTimer != null) {
partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTime(
batteryRealtime, which);
}
}
}
}
pw.println(prefix
+ " Wifi on: " + formatTimeMs(wifiOnTime / 1000)
+ "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
+ "), Wifi running: " + formatTimeMs(wifiRunningTime / 1000)
+ "(" + formatRatioLocked(wifiRunningTime, whichBatteryRealtime)
+ "), Bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
+ "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
+ " Total received: " + formatBytesLocked(rxTotal)
+ ", Total sent: " + formatBytesLocked(txTotal));
pw.println(prefix
+ " Total full wakelock time: " + formatTimeMs(
(fullWakeLockTimeTotalMicros + 500) / 1000)
+ ", Total partial waklock time: " + formatTimeMs(
(partialWakeLockTimeTotalMicros + 500) / 1000));
sb.setLength(0);
sb.append(" Signal strengths: ");
boolean didOne = false;
sb.append(" Signal levels: ");
didOne = false;
for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
if (time == 0) {
@@ -789,13 +1016,15 @@ public abstract class BatteryStats implements Parcelable {
sb.append(formatTimeMs(time/1000));
sb.append("(");
sb.append(formatRatioLocked(time, whichBatteryRealtime));
sb.append(")");
sb.append(") ");
sb.append(getPhoneSignalStrengthCount(i, which));
sb.append("x");
}
if (!didOne) sb.append("No activity");
pw.println(sb.toString());
sb.setLength(0);
sb.append(" Data types: ");
sb.append(" Radio types: ");
didOne = false;
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
@@ -809,11 +1038,21 @@ public abstract class BatteryStats implements Parcelable {
sb.append(formatTimeMs(time/1000));
sb.append("(");
sb.append(formatRatioLocked(time, whichBatteryRealtime));
sb.append(")");
sb.append(") ");
sb.append(getPhoneDataConnectionCount(i, which));
sb.append("x");
}
if (!didOne) sb.append("No activity");
pw.println(sb.toString());
pw.println(prefix
+ " Wifi on: " + formatTimeMs(wifiOnTime / 1000)
+ "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
+ "), Wifi running: " + formatTimeMs(wifiRunningTime / 1000)
+ "(" + formatRatioLocked(wifiRunningTime, whichBatteryRealtime)
+ "), Bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
+ "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
pw.println(" ");
if (which == STATS_UNPLUGGED) {
@@ -828,12 +1067,10 @@ public abstract class BatteryStats implements Parcelable {
pw.println(prefix + " Last discharge cycle end level: " +
getPluggedStartLevel());
}
pw.println(" ");
}
pw.println(" ");
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);
@@ -844,12 +1081,41 @@ public abstract class BatteryStats implements Parcelable {
long tcpSent = u.getTcpBytesSent(which);
long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
if (tcpReceived != 0 || tcpSent != 0) {
pw.println(prefix + " Network: " + tcpReceived + " bytes received, "
+ tcpSent + " bytes sent");
pw.println(prefix + " Network: " + formatBytesLocked(tcpReceived) + " received, "
+ formatBytesLocked(tcpSent) + " sent");
}
if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
int val = u.getUserActivityCount(i, which);
if (val != 0) {
if (!hasData) {
sb.setLength(0);
sb.append(" User activity: ");
hasData = true;
} else {
sb.append(", ");
}
sb.append(val);
sb.append(" ");
sb.append(Uid.USER_ACTIVITY_TYPES[i]);
}
}
if (hasData) {
pw.println(sb.toString());
}
}
if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
|| wifiTurnedOnTime != 0) {
pw.println(prefix + " Turned Wifi On Time: "
+ formatTimeMs(wifiTurnedOnTime / 1000)
+ "(" + formatRatioLocked(wifiTurnedOnTime,
whichBatteryRealtime)+ ")");
pw.println(prefix + " Full Wifi Lock Time: "
+ formatTimeMs(fullWifiLockOnTime / 1000)
+ "(" + formatRatioLocked(fullWifiLockOnTime,

View File

@@ -18,6 +18,8 @@ package android.os;
/** @hide */
public interface LocalPowerManager {
// Note: be sure to update BatteryStats if adding or modifying event constants.
public static final int OTHER_EVENT = 0;
public static final int CHEEK_EVENT = 1;
public static final int TOUCH_EVENT = 2; // touch events are TOUCH for 300ms, and then either

View File

@@ -24,6 +24,7 @@
package android.server;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
@@ -970,8 +971,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
*/
public synchronized int getRemoteClass(String address) {
if (!BluetoothDevice.checkBluetoothAddress(address)) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
return -1;
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
return BluetoothClass.ERROR;
}
return getRemoteClassNative(address);
}
@@ -1254,4 +1255,3 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
Log.d(TAG, msg);
}
}

View File

@@ -618,7 +618,9 @@ extends Layout
* - is class HY: a breakpoint
* except when followed by a digit.
*
* Ideographs are class ID: breakpoints when adjacent.
* Ideographs are class ID: breakpoints when adjacent,
* except for NS (non-starters), which can be broken
* after but not before.
*/
if (c == ' ' || c == '\t' ||
@@ -627,8 +629,8 @@ extends Layout
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
((c == '/' || c == '-') &&
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
(c >= FIRST_CJK && isIdeographic(c) &&
j + 1 < next && isIdeographic(chs[j + 1 - start]))) {
(c >= FIRST_CJK && isIdeographic(c, true) &&
j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {
okwidth = w;
ok = j + 1;
@@ -807,8 +809,12 @@ extends Layout
* as being Ideographic (class ID) by the Unicode Line Breaking Algorithm
* (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK
* to break between a pair of.
*
* @param includeNonStarters also return true for category NS
* (non-starters), which can be broken
* after but not before.
*/
private static final boolean isIdeographic(char c) {
private static final boolean isIdeographic(char c, boolean includeNonStarters) {
if (c >= '\u2E80' && c <= '\u2FFF') {
return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS
}
@@ -816,9 +822,52 @@ extends Layout
return true; // IDEOGRAPHIC SPACE
}
if (c >= '\u3040' && c <= '\u309F') {
if (!includeNonStarters) {
switch (c) {
case '\u3041': // # HIRAGANA LETTER SMALL A
case '\u3043': // # HIRAGANA LETTER SMALL I
case '\u3045': // # HIRAGANA LETTER SMALL U
case '\u3047': // # HIRAGANA LETTER SMALL E
case '\u3049': // # HIRAGANA LETTER SMALL O
case '\u3063': // # HIRAGANA LETTER SMALL TU
case '\u3083': // # HIRAGANA LETTER SMALL YA
case '\u3085': // # HIRAGANA LETTER SMALL YU
case '\u3087': // # HIRAGANA LETTER SMALL YO
case '\u308E': // # HIRAGANA LETTER SMALL WA
case '\u3095': // # HIRAGANA LETTER SMALL KA
case '\u3096': // # HIRAGANA LETTER SMALL KE
case '\u309B': // # KATAKANA-HIRAGANA VOICED SOUND MARK
case '\u309C': // # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
case '\u309D': // # HIRAGANA ITERATION MARK
case '\u309E': // # HIRAGANA VOICED ITERATION MARK
return false;
}
}
return true; // Hiragana (except small characters)
}
if (c >= '\u30A0' && c <= '\u30FF') {
if (!includeNonStarters) {
switch (c) {
case '\u30A0': // # KATAKANA-HIRAGANA DOUBLE HYPHEN
case '\u30A1': // # KATAKANA LETTER SMALL A
case '\u30A3': // # KATAKANA LETTER SMALL I
case '\u30A5': // # KATAKANA LETTER SMALL U
case '\u30A7': // # KATAKANA LETTER SMALL E
case '\u30A9': // # KATAKANA LETTER SMALL O
case '\u30C3': // # KATAKANA LETTER SMALL TU
case '\u30E3': // # KATAKANA LETTER SMALL YA
case '\u30E5': // # KATAKANA LETTER SMALL YU
case '\u30E7': // # KATAKANA LETTER SMALL YO
case '\u30EE': // # KATAKANA LETTER SMALL WA
case '\u30F5': // # KATAKANA LETTER SMALL KA
case '\u30F6': // # KATAKANA LETTER SMALL KE
case '\u30FB': // # KATAKANA MIDDLE DOT
case '\u30FC': // # KATAKANA-HIRAGANA PROLONGED SOUND MARK
case '\u30FD': // # KATAKANA ITERATION MARK
case '\u30FE': // # KATAKANA VOICED ITERATION MARK
return false;
}
}
return true; // Katakana (except small characters)
}
if (c >= '\u3400' && c <= '\u4DB5') {

View File

@@ -405,23 +405,34 @@ public class QwertyKeyListener extends BaseKeyListener {
PICKER_SETS.put('<', "\u00AB");
PICKER_SETS.put('>', "\u00BB");
PICKER_SETS.put('?', "\u00BF");
PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5");
PICKER_SETS.put('C', "\u00C7");
PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB");
PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF");
PICKER_SETS.put('N', "\u00D1");
PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6");
PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC");
PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5\u0104\u0100");
PICKER_SETS.put('C', "\u00C7\u0106\u010C");
PICKER_SETS.put('D', "\u010E");
PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112");
PICKER_SETS.put('L', "\u0141");
PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A");
PICKER_SETS.put('N', "\u00D1\u0143\u0147");
PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C");
PICKER_SETS.put('R', "\u0158");
PICKER_SETS.put('S', "\u015A\u0160");
PICKER_SETS.put('T', "\u0164");
PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC\u016E\u016A");
PICKER_SETS.put('Y', "\u00DD\u0178");
PICKER_SETS.put('a', "\u00E0\u00E1\u00E2\u00E4\u00E6\u00E3\u00E5");
PICKER_SETS.put('c', "\u00E7");
PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB");
PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF");
PICKER_SETS.put('n', "\u00F1");
PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6");
PICKER_SETS.put('s', "\u00A7\u00DF");
PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC");
PICKER_SETS.put('Z', "\u0179\u017B\u017D");
PICKER_SETS.put('a', "\u00E0\u00E1\u00E2\u00E4\u00E6\u00E3\u00E5\u0105\u0101");
PICKER_SETS.put('c', "\u00E7\u0107\u010D");
PICKER_SETS.put('d', "\u010F");
PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113");
PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B");
PICKER_SETS.put('l', "\u0142");
PICKER_SETS.put('n', "\u00F1\u0144\u0148");
PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D");
PICKER_SETS.put('r', "\u0159");
PICKER_SETS.put('s', "\u00A7\u00DF\u015B\u0161");
PICKER_SETS.put('t', "\u0165");
PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC\u016F\u016B");
PICKER_SETS.put('y', "\u00FD\u00FF");
PICKER_SETS.put('z', "\u017A\u017C\u017E");
PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
"\u2026\u00A5\u2022\u00AE\u00A9\u00B1");
};

View File

@@ -0,0 +1,86 @@
/*
* 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.util;
/**
* @hide
*/
class FinitePool<T extends Poolable<T>> implements Pool<T> {
/**
* Factory used to create new pool objects
*/
private final PoolableManager<T> mManager;
/**
* Maximum number of objects in the pool
*/
private final int mLimit;
/**
* If true, mLimit is ignored
*/
private final boolean mInfinite;
/**
* Next object to acquire
*/
private T mRoot;
/**
* Number of objects in the pool
*/
private int mPoolCount;
FinitePool(PoolableManager<T> manager) {
mManager = manager;
mLimit = 0;
mInfinite = true;
}
FinitePool(PoolableManager<T> manager, int limit) {
if (limit <= 0) throw new IllegalArgumentException("The pool limit must be > 0");
mManager = manager;
mLimit = limit;
mInfinite = false;
}
public T acquire() {
T element;
if (mRoot != null) {
element = mRoot;
mRoot = element.getNextPoolable();
mPoolCount--;
} else {
element = mManager.newInstance();
}
if (element != null) {
element.setNextPoolable(null);
mManager.onAcquired(element);
}
return element;
}
public void release(T element) {
if (mInfinite || mPoolCount < mLimit) {
mPoolCount++;
element.setNextPoolable(mRoot);
mRoot = element;
}
mManager.onReleased(element);
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.util;
/**
* @hide
*/
public interface Pool<T extends Poolable<T>> {
public abstract T acquire();
public abstract void release(T element);
}

View File

@@ -0,0 +1,41 @@
/*
* 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.util;
/**
* @hide
*/
public class PoolFactory {
private PoolFactory() {
}
public static <T extends Poolable<T>> Pool<T> simplePool(PoolableManager<T> manager) {
return new FinitePool<T>(manager);
}
public static <T extends Poolable<T>> Pool<T> finitePool(PoolableManager<T> manager, int limit) {
return new FinitePool<T>(manager, limit);
}
public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool) {
return new SynchronizedPool<T>(pool);
}
public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool, Object lock) {
return new SynchronizedPool<T>(pool, lock);
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.util;
/**
* @hide
*/
public interface Poolable<T> {
void setNextPoolable(T element);
T getNextPoolable();
}

View File

@@ -0,0 +1,27 @@
/*
* 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.util;
/**
* @hide
*/
public interface PoolableManager<T extends Poolable<T>> {
T newInstance();
void onAcquired(T element);
void onReleased(T element);
}

View File

@@ -0,0 +1,48 @@
/*
* 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.util;
/**
*
* @hide
*/
class SynchronizedPool<T extends Poolable<T>> implements Pool<T> {
private final Pool<T> mPool;
private final Object mLock;
public SynchronizedPool(Pool<T> pool) {
mPool = pool;
mLock = this;
}
public SynchronizedPool(Pool<T> pool, Object lock) {
mPool = pool;
mLock = lock;
}
public T acquire() {
synchronized (mLock) {
return mPool.acquire();
}
}
public void release(T element) {
synchronized (mLock) {
mPool.release(element);
}
}
}

View File

@@ -18,6 +18,10 @@ package android.view;
import android.util.Config;
import android.util.Log;
import android.util.Poolable;
import android.util.Pool;
import android.util.PoolFactory;
import android.util.PoolableManager;
/**
* Helper for tracking the velocity of touch events, for implementing
@@ -28,52 +32,72 @@ import android.util.Log;
* {@link #computeCurrentVelocity(int)} and then {@link #getXVelocity()}
* and {@link #getXVelocity()}.
*/
public final class VelocityTracker {
public final class VelocityTracker implements Poolable<VelocityTracker> {
static final String TAG = "VelocityTracker";
static final boolean DEBUG = false;
static final boolean localLOGV = DEBUG || Config.LOGV;
static final int NUM_PAST = 10;
static final int LONGEST_PAST_TIME = 200;
static final VelocityTracker[] mPool = new VelocityTracker[1];
private static final Pool<VelocityTracker> sPool = PoolFactory.synchronizedPool(
PoolFactory.finitePool(new PoolableManager<VelocityTracker>() {
public VelocityTracker newInstance() {
return new VelocityTracker();
}
public void onAcquired(VelocityTracker element) {
element.clear();
}
public void onReleased(VelocityTracker element) {
}
}, 2));
final float mPastX[] = new float[NUM_PAST];
final float mPastY[] = new float[NUM_PAST];
final long mPastTime[] = new long[NUM_PAST];
float mYVelocity;
float mXVelocity;
private VelocityTracker mNext;
/**
* Retrieve a new VelocityTracker object to watch the velocity of a
* motion. Be sure to call {@link #recycle} when done. You should
* generally only maintain an active object while tracking a movement,
* so that the VelocityTracker can be re-used elsewhere.
*
*
* @return Returns a new VelocityTracker.
*/
static public VelocityTracker obtain() {
synchronized (mPool) {
VelocityTracker vt = mPool[0];
if (vt != null) {
vt.clear();
return vt;
}
return new VelocityTracker();
}
return sPool.acquire();
}
/**
* Return a VelocityTracker object back to be re-used by others. You must
* not touch the object after calling this function.
*/
public void recycle() {
synchronized (mPool) {
mPool[0] = this;
}
sPool.release(this);
}
/**
* @hide
*/
public void setNextPoolable(VelocityTracker element) {
mNext = element;
}
/**
* @hide
*/
public VelocityTracker getNextPoolable() {
return mNext;
}
private VelocityTracker() {
}

View File

@@ -45,6 +45,10 @@ import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.Poolable;
import android.util.Pool;
import android.util.PoolFactory;
import android.util.PoolableManager;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Animation;
import android.view.inputmethod.InputConnection;
@@ -5531,7 +5535,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
(mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE);
if (width <= 0 || height <= 0 ||
(width * height * (opaque ? 2 : 4) >= // Projected bitmap size in bytes
(width * height * (opaque ? 2 : 4) > // Projected bitmap size in bytes
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
return;
@@ -5627,6 +5631,62 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
}
/**
* Create a snapshot of the view into a bitmap. We should probably make
* some form of this public, but should think about the API.
*/
/*package*/ Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) {
final int width = mRight - mLeft;
final int height = mBottom - mTop;
Bitmap bitmap = Bitmap.createBitmap(width, height, quality);
if (bitmap == null) {
throw new OutOfMemoryError();
}
Canvas canvas;
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
canvas = attachInfo.mCanvas;
if (canvas == null) {
canvas = new Canvas();
}
canvas.setBitmap(bitmap);
// Temporarily clobber the cached Canvas in case one of our children
// is also using a drawing cache. Without this, the children would
// steal the canvas by attaching their own bitmap to it and bad, bad
// things would happen (invisible views, corrupted drawings, etc.)
attachInfo.mCanvas = null;
} else {
// This case should hopefully never or seldom happen
canvas = new Canvas(bitmap);
}
if ((backgroundColor&0xff000000) != 0) {
bitmap.eraseColor(backgroundColor);
}
computeScroll();
final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY);
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
dispatchDraw(canvas);
} else {
draw(canvas);
}
canvas.restoreToCount(restoreCount);
if (attachInfo != null) {
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
}
return bitmap;
}
/**
* Indicates whether this View is currently in edit mode. A View is usually
* in edit mode when displayed within a developer tool. For instance, if
@@ -7827,26 +7887,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* For performance purposes, this class also implements a pool of up to
* POOL_LIMIT objects that get reused. This reduces memory allocations
* whenever possible.
*
* The pool is implemented as a linked list of InvalidateInfo object with
* the root pointing to the next available InvalidateInfo. If the root
* is null (i.e. when all instances from the pool have been acquired),
* then a new InvalidateInfo is created and returned to the caller.
*
* An InvalidateInfo is sent back to the pool by calling its release()
* method. If the pool is full the object is simply discarded.
*
* This implementation follows the object pool pattern used in the
* MotionEvent class.
*/
static class InvalidateInfo {
static class InvalidateInfo implements Poolable<InvalidateInfo> {
private static final int POOL_LIMIT = 10;
private static final Object sLock = new Object();
private static final Pool<InvalidateInfo> sPool = PoolFactory.synchronizedPool(
PoolFactory.finitePool(new PoolableManager<InvalidateInfo>() {
public InvalidateInfo newInstance() {
return new InvalidateInfo();
}
private static int sAcquiredCount = 0;
private static InvalidateInfo sRoot;
public void onAcquired(InvalidateInfo element) {
}
private InvalidateInfo next;
public void onReleased(InvalidateInfo element) {
}
}, POOL_LIMIT)
);
private InvalidateInfo mNext;
View target;
@@ -7855,28 +7913,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
int right;
int bottom;
public void setNextPoolable(InvalidateInfo element) {
mNext = element;
}
public InvalidateInfo getNextPoolable() {
return mNext;
}
static InvalidateInfo acquire() {
synchronized (sLock) {
if (sRoot == null) {
return new InvalidateInfo();
}
InvalidateInfo info = sRoot;
sRoot = info.next;
sAcquiredCount--;
return info;
}
return sPool.acquire();
}
void release() {
synchronized (sLock) {
if (sAcquiredCount < POOL_LIMIT) {
sAcquiredCount++;
next = sRoot;
sRoot = this;
}
}
sPool.release(this);
}
}

View File

@@ -741,22 +741,18 @@ public class ViewDebug {
final CountDownLatch latch = new CountDownLatch(1);
final Bitmap[] cache = new Bitmap[1];
final boolean hasCache = captureView.isDrawingCacheEnabled();
final boolean willNotCache = captureView.willNotCacheDrawing();
if (willNotCache) {
// TODO: Should happen on the UI thread
captureView.setWillNotCacheDrawing(false);
}
root.post(new Runnable() {
public void run() {
try {
if (!hasCache) {
captureView.buildDrawingCache();
cache[0] = captureView.createSnapshot(
Bitmap.Config.ARGB_8888, 0);
} catch (OutOfMemoryError e) {
try {
cache[0] = captureView.createSnapshot(
Bitmap.Config.ARGB_4444, 0);
} catch (OutOfMemoryError e2) {
Log.w("View", "Out of memory for bitmap");
}
cache[0] = captureView.getDrawingCache();
} finally {
latch.countDown();
}
@@ -776,20 +772,15 @@ public class ViewDebug {
if (out != null) {
out.close();
}
cache[0].recycle();
}
} else {
Log.w("View", "Failed to create capture bitmap!");
clientStream.close();
}
} catch (InterruptedException e) {
Log.w("View", "Could not complete the capture of the view " + captureView);
Thread.currentThread().interrupt();
} finally {
if (willNotCache) {
// TODO: Should happen on the UI thread
captureView.setWillNotCacheDrawing(true);
}
if (!hasCache) {
// TODO: Should happen on the UI thread
captureView.destroyDrawingCache();
}
}
}
}

View File

@@ -580,8 +580,11 @@ public interface WindowManagerPolicy {
* Called when layout of the windows is finished. After this function has
* returned, all windows given to layoutWindow() <em>must</em> have had a
* frame assigned.
*
* @return Return true if layout state may have changed (so that another
* layout will be performed).
*/
public void finishLayoutLw();
public boolean finishLayoutLw();
/**
* Called when animation of the windows is about to start.

View File

@@ -4503,14 +4503,19 @@ public class WebView extends AbsoluteLayout
int scrollYDelta = 0;
if (rect.bottom > screenBottom && rect.top > screenTop) {
if (rect.height() > height) {
scrollYDelta += (rect.top - screenTop);
if (rect.bottom > screenBottom) {
int oneThirdOfScreenHeight = height / 3;
if (rect.height() > 2 * oneThirdOfScreenHeight) {
// If the rectangle is too tall to fit in the bottom two thirds
// of the screen, place it at the top.
scrollYDelta = rect.top - screenTop;
} else {
scrollYDelta += (rect.bottom - screenBottom);
// If the rectangle will still fit on screen, we want its
// top to be in the top third of the screen.
scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
}
} else if (rect.top < screenTop) {
scrollYDelta -= (screenTop - rect.top);
scrollYDelta = rect.top - screenTop;
}
int width = getWidth() - getVerticalScrollbarWidth();

View File

@@ -885,6 +885,22 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
return result;
}
/**
* Set the horizontal offset with respect to {@link #setDropDownAnchor(int)}
* @hide pending API council review
*/
public void setDropDownHorizontalOffset(int horizontalOffset) {
mDropDownHorizontalOffset = horizontalOffset;
}
/**
* Set the vertical offset with respect to {@link #setDropDownAnchor(int)}
* @hide pending API council review
*/
public void setDropDownVerticalOffset(int verticalOffset) {
mDropDownVerticalOffset = verticalOffset;
}
/**
* <p>Used for lazy instantiation of the anchor view from the id we have. If the value of
* the id is NO_ID or we can't find a view for the given id, we return this TextView as

View File

@@ -24,6 +24,7 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.Gravity;
import android.widget.RemoteViews.RemoteView;
@@ -45,21 +46,31 @@ import android.widget.RemoteViews.RemoteView;
*/
@RemoteView
public class FrameLayout extends ViewGroup {
@ViewDebug.ExportedProperty
boolean mMeasureAllChildren = false;
@ViewDebug.ExportedProperty
private Drawable mForeground;
@ViewDebug.ExportedProperty
private int mForegroundPaddingLeft = 0;
@ViewDebug.ExportedProperty
private int mForegroundPaddingTop = 0;
@ViewDebug.ExportedProperty
private int mForegroundPaddingRight = 0;
@ViewDebug.ExportedProperty
private int mForegroundPaddingBottom = 0;
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
@ViewDebug.ExportedProperty
private int mForegroundGravity = Gravity.FILL;
/** {@hide} */
@ViewDebug.ExportedProperty
protected boolean mForegroundInPadding = true;
boolean mForegroundBoundsChanged = false;
public FrameLayout(Context context) {
super(context);
}
@@ -269,6 +280,8 @@ public class FrameLayout extends ViewGroup {
final int parentTop = mPaddingTop + mForegroundPaddingTop;
final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom;
mForegroundBoundsChanged = true;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
@@ -328,22 +341,7 @@ public class FrameLayout extends ViewGroup {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
final Drawable foreground = mForeground;
if (foreground != null) {
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
}
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
foreground.setBounds(overlayBounds);
}
mForegroundBoundsChanged = true;
}
/**
@@ -354,7 +352,29 @@ public class FrameLayout extends ViewGroup {
super.draw(canvas);
if (mForeground != null) {
mForeground.draw(canvas);
final Drawable foreground = mForeground;
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
if (foreground != null) {
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
final int w = mRight-mLeft;
final int h = mBottom-mTop;
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
}
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
foreground.setBounds(overlayBounds);
}
}
foreground.draw(canvas);
}
}