summaryrefslogtreecommitdiffstats
path: root/core/java/android/util
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /core/java/android/util
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'core/java/android/util')
-rw-r--r--core/java/android/util/AndroidException.java34
-rw-r--r--core/java/android/util/AndroidRuntimeException.java34
-rw-r--r--core/java/android/util/AttributeSet.java269
-rw-r--r--core/java/android/util/Config.java51
-rw-r--r--core/java/android/util/DayOfMonthCursor.java173
-rw-r--r--core/java/android/util/DebugUtils.java104
-rw-r--r--core/java/android/util/DisplayMetrics.java85
-rw-r--r--core/java/android/util/EventLog.java288
-rw-r--r--core/java/android/util/EventLogTags.java90
-rw-r--r--core/java/android/util/FloatMath.java74
-rw-r--r--core/java/android/util/Log.java247
-rw-r--r--core/java/android/util/LogPrinter.java47
-rw-r--r--core/java/android/util/MonthDisplayHelper.java213
-rw-r--r--core/java/android/util/PrintWriterPrinter.java40
-rw-r--r--core/java/android/util/Printer.java31
-rw-r--r--core/java/android/util/SparseArray.java340
-rw-r--r--core/java/android/util/SparseBooleanArray.java245
-rw-r--r--core/java/android/util/SparseIntArray.java244
-rw-r--r--core/java/android/util/StateSet.java178
-rw-r--r--core/java/android/util/StringBuilderPrinter.java42
-rw-r--r--core/java/android/util/TimeFormatException.java26
-rw-r--r--core/java/android/util/TimeUtils.java109
-rw-r--r--core/java/android/util/TimingLogger.java144
-rw-r--r--core/java/android/util/TypedValue.java477
-rw-r--r--core/java/android/util/Xml.java185
-rw-r--r--core/java/android/util/XmlPullAttributes.java146
-rw-r--r--core/java/android/util/package.html6
27 files changed, 3922 insertions, 0 deletions
diff --git a/core/java/android/util/AndroidException.java b/core/java/android/util/AndroidException.java
new file mode 100644
index 0000000..a767ea1
--- /dev/null
+++ b/core/java/android/util/AndroidException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util;
+
+/**
+ * Base class for all checked exceptions thrown by the Android frameworks.
+ */
+public class AndroidException extends Exception {
+ public AndroidException() {
+ }
+
+ public AndroidException(String name) {
+ super(name);
+ }
+
+ public AndroidException(Exception cause) {
+ super(cause);
+ }
+};
+
diff --git a/core/java/android/util/AndroidRuntimeException.java b/core/java/android/util/AndroidRuntimeException.java
new file mode 100644
index 0000000..4ed17bc
--- /dev/null
+++ b/core/java/android/util/AndroidRuntimeException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util;
+
+/**
+ * Base class for all unchecked exceptions thrown by the Android frameworks.
+ */
+public class AndroidRuntimeException extends RuntimeException {
+ public AndroidRuntimeException() {
+ }
+
+ public AndroidRuntimeException(String name) {
+ super(name);
+ }
+
+ public AndroidRuntimeException(Exception cause) {
+ super(cause);
+ }
+};
+
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
new file mode 100644
index 0000000..01a7ad4
--- /dev/null
+++ b/core/java/android/util/AttributeSet.java
@@ -0,0 +1,269 @@
+/*
+ * 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.util;
+
+
+/**
+ * A collection of attributes, as found associated with a tag in an XML
+ * document. Often you will not want to use this interface directly, instead
+ * passing it to {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+ * Resources.Theme.obtainStyledAttributes()}
+ * which will take care of parsing the attributes for you. In particular,
+ * the Resources API will convert resource references (attribute values such as
+ * "@string/my_label" in the original XML) to the desired type
+ * for you; if you use AttributeSet directly then you will need to manually
+ * check for resource references
+ * (with {@link #getAttributeResourceValue(int, int)}) and do the resource
+ * lookup yourself if needed. Direct use of AttributeSet also prevents the
+ * application of themes and styles when retrieving attribute values.
+ *
+ * <p>This interface provides an efficient mechanism for retrieving
+ * data from compiled XML files, which can be retrieved for a particular
+ * XmlPullParser through {@link Xml#asAttributeSet
+ * Xml.getAttributeSet()}. Normally this will return an implementation
+ * of the interface that works on top of a generic XmlPullParser, however it
+ * is more useful in conjunction with compiled XML resources:
+ *
+ * <pre>
+ * XmlPullParser parser = resources.getXml(myResouce);
+ * AttributeSet attributes = Xml.getAttributeSet(parser);</pre>
+ *
+ * <p>The implementation returned here, unlike using
+ * the implementation on top of a generic XmlPullParser,
+ * is highly optimized by retrieving pre-computed information that was
+ * generated by aapt when compiling your resources. For example,
+ * the {@link #getAttributeFloatValue(int, float)} method returns a floating
+ * point number previous stored in the compiled resource instead of parsing
+ * at runtime the string originally in the XML file.
+ *
+ * <p>This interface also provides additional information contained in the
+ * compiled XML resource that is not available in a normal XML file, such
+ * as {@link #getAttributeNameResource(int)} which returns the resource
+ * identifier associated with a particular XML attribute name.
+ */
+public interface AttributeSet {
+ public int getAttributeCount();
+ public String getAttributeName(int index);
+ public String getAttributeValue(int index);
+ public String getAttributeValue(String namespace, String name);
+ public String getPositionDescription();
+
+ /**
+ * Return the resource ID associated with the given attribute name. This
+ * will be the identifier for an attribute resource, which can be used by
+ * styles. Returns 0 if there is no resource associated with this
+ * attribute.
+ *
+ * <p>Note that this is different than {@link #getAttributeResourceValue}
+ * in that it returns a resource identifier for the attribute name; the
+ * other method returns this attribute's value as a resource identifier.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ *
+ * @return The resource identifier, 0 if none.
+ */
+ public int getAttributeNameResource(int index);
+
+ /**
+ * Return the index of the value of 'attribute' in the list 'options'.
+ *
+ * @param attribute Name of attribute to retrieve.
+ * @param options List of strings whose values we are checking against.
+ * @param defaultValue Value returned if attribute doesn't exist or no
+ * match is found.
+ *
+ * @return Index in to 'options' or defaultValue.
+ */
+ public int getAttributeListValue(String namespace, String attribute,
+ String[] options, int defaultValue);
+
+ /**
+ * Return the boolean value of 'attribute'.
+ *
+ * @param attribute The attribute to retrieve.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public boolean getAttributeBooleanValue(String namespace, String attribute,
+ boolean defaultValue);
+
+ /**
+ * Return the value of 'attribute' as a resource identifier.
+ *
+ * <p>Note that this is different than {@link #getAttributeNameResource}
+ * in that it returns a the value contained in this attribute as a
+ * resource identifier (i.e., a value originally of the form
+ * "@package:type/resource"); the other method returns a resource
+ * identifier that identifies the name of the attribute.
+ *
+ * @param attribute The attribute to retrieve.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeResourceValue(String namespace, String attribute,
+ int defaultValue);
+
+ /**
+ * Return the integer value of 'attribute'.
+ *
+ * @param attribute The attribute to retrieve.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeIntValue(String namespace, String attribute,
+ int defaultValue);
+
+ /**
+ * Return the boolean value of 'attribute' that is formatted as an
+ * unsigned value. In particular, the formats 0xn...n and #n...n are
+ * handled.
+ *
+ * @param attribute The attribute to retrieve.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeUnsignedIntValue(String namespace, String attribute,
+ int defaultValue);
+
+ /**
+ * Return the float value of 'attribute'.
+ *
+ * @param attribute The attribute to retrieve.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public float getAttributeFloatValue(String namespace, String attribute,
+ float defaultValue);
+
+ /**
+ * Return the index of the value of attribute at 'index' in the list
+ * 'options'.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param options List of strings whose values we are checking against.
+ * @param defaultValue Value returned if attribute doesn't exist or no
+ * match is found.
+ *
+ * @return Index in to 'options' or defaultValue.
+ */
+ public int getAttributeListValue(int index,
+ String[] options, int defaultValue);
+
+ /**
+ * Return the boolean value of attribute at 'index'.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public boolean getAttributeBooleanValue(int index,
+ boolean defaultValue);
+
+ /**
+ * Return the value of attribute at 'index' as a resource identifier.
+ *
+ * <p>Note that this is different than {@link #getAttributeNameResource}
+ * in that it returns a the value contained in this attribute as a
+ * resource identifier (i.e., a value originally of the form
+ * "@package:type/resource"); the other method returns a resource
+ * identifier that identifies the name of the attribute.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeResourceValue(int index,
+ int defaultValue);
+
+ /**
+ * Return the integer value of attribute at 'index'.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeIntValue(int index,
+ int defaultValue);
+
+ /**
+ * Return the integer value of attribute at 'index' that is formatted as an
+ * unsigned value. In particular, the formats 0xn...n and #n...n are
+ * handled.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public int getAttributeUnsignedIntValue(int index,
+ int defaultValue);
+
+ /**
+ * Return the float value of attribute at 'index'.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ * @param defaultValue What to return if the attribute isn't found.
+ *
+ * @return Resulting value.
+ */
+ public float getAttributeFloatValue(int index,
+ float defaultValue);
+
+ /**
+ * Return the value of the "id" attribute or null if there is not one.
+ * Equivalent to getAttributeValue(null, "id").
+ *
+ * @return The id attribute's value or null.
+ */
+ public String getIdAttribute();
+
+ /**
+ * Return the value of the "class" attribute or null if there is not one.
+ * Equivalent to getAttributeValue(null, "class").
+ *
+ * @return The class attribute's value or null.
+ */
+ public String getClassAttribute();
+
+ /**
+ * Return the integer value of the "id" attribute or defaultValue if there
+ * is none.
+ * Equivalent to getAttributeResourceValue(null, "id", defaultValue);
+ *
+ * @param defaultValue What to return if the "id" attribute isn't found.
+ * @return int Resulting value.
+ */
+ public int getIdAttributeResourceValue(int defaultValue);
+
+ /**
+
+ * Return the value of the "style" attribute or 0 if there is not one.
+ * Equivalent to getAttributeResourceValue(null, "style").
+ *
+ * @return The style attribute's resource identifier or 0.
+ */
+ public int getStyleAttribute();
+}
+
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
new file mode 100644
index 0000000..c0b27f8
--- /dev/null
+++ b/core/java/android/util/Config.java
@@ -0,0 +1,51 @@
+/* device/vmlibs-config/release/android/util/Config.java
+**
+** Copyright 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.util;
+
+/**
+ * Build configuration. The constants in this class vary depending
+ * on release vs. debug build. This is the configuration for release builds.
+ * {@more}
+ */
+public final class Config
+{
+ /**
+ * Is this a release build?
+ */
+ public static final boolean RELEASE = true;
+
+ /**
+ * Is this a debug build?
+ */
+ public static final boolean DEBUG = false;
+
+ /**
+ * Is profiling enabled?
+ */
+ public static final boolean PROFILE = false;
+
+ /**
+ * Are VERBOSE log messages enabled?
+ */
+ public static final boolean LOGV = false;
+
+ /**
+ * Are DEBUG log messages enabled?
+ */
+ public static final boolean LOGD = true;
+}
diff --git a/core/java/android/util/DayOfMonthCursor.java b/core/java/android/util/DayOfMonthCursor.java
new file mode 100644
index 0000000..52ee00e
--- /dev/null
+++ b/core/java/android/util/DayOfMonthCursor.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 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.util;
+
+/**
+ * Helps control and display a month view of a calendar that has a current
+ * selected day.
+ * <ul>
+ * <li>Keeps track of current month, day, year</li>
+ * <li>Keeps track of current cursor position (row, column)</li>
+ * <li>Provides methods to help display the calendar</li>
+ * <li>Provides methods to move the cursor up / down / left / right.</li>
+ * </ul>
+ *
+ * This should be used by anyone who presents a month view to users and wishes
+ * to behave consistently with other widgets and apps; if we ever change our
+ * mind about when to flip the month, we can change it here only.
+ *
+ * @hide
+ */
+public class DayOfMonthCursor extends MonthDisplayHelper {
+
+ private int mRow;
+ private int mColumn;
+
+ /**
+ * @param year The initial year.
+ * @param month The initial month.
+ * @param dayOfMonth The initial dayOfMonth.
+ * @param weekStartDay What dayOfMonth of the week the week should start,
+ * in terms of {@link java.util.Calendar} constants such as
+ * {@link java.util.Calendar#SUNDAY}.
+ */
+ public DayOfMonthCursor(int year, int month, int dayOfMonth, int weekStartDay) {
+ super(year, month, weekStartDay);
+ mRow = getRowOf(dayOfMonth);
+ mColumn = getColumnOf(dayOfMonth);
+ }
+
+
+ public int getSelectedRow() {
+ return mRow;
+ }
+
+ public int getSelectedColumn() {
+ return mColumn;
+ }
+
+ public void setSelectedRowColumn(int row, int col) {
+ mRow = row;
+ mColumn = col;
+ }
+
+ public int getSelectedDayOfMonth() {
+ return getDayAt(mRow, mColumn);
+ }
+
+ public void setSelectedDayOfMonth(int dayOfMonth) {
+ mRow = getRowOf(dayOfMonth);
+ mColumn = getColumnOf(dayOfMonth);
+ }
+
+ public boolean isSelected(int row, int column) {
+ return (mRow == row) && (mColumn == column);
+ }
+
+ /**
+ * Move up one box, potentially flipping to the previous month.
+ * @return Whether the month was flipped to the previous month
+ * due to the move.
+ */
+ public boolean up() {
+ if (isWithinCurrentMonth(mRow - 1, mColumn)) {
+ // within current month, just move up
+ mRow--;
+ return false;
+ }
+ // flip back to previous month, same column, first position within month
+ previousMonth();
+ mRow = 5;
+ while(!isWithinCurrentMonth(mRow, mColumn)) {
+ mRow--;
+ }
+ return true;
+ }
+
+ /**
+ * Move down one box, potentially flipping to the next month.
+ * @return Whether the month was flipped to the next month
+ * due to the move.
+ */
+ public boolean down() {
+ if (isWithinCurrentMonth(mRow + 1, mColumn)) {
+ // within current month, just move down
+ mRow++;
+ return false;
+ }
+ // flip to next month, same column, first position within month
+ nextMonth();
+ mRow = 0;
+ while (!isWithinCurrentMonth(mRow, mColumn)) {
+ mRow++;
+ }
+ return true;
+ }
+
+ /**
+ * Move left one box, potentially flipping to the previous month.
+ * @return Whether the month was flipped to the previous month
+ * due to the move.
+ */
+ public boolean left() {
+ if (mColumn == 0) {
+ mRow--;
+ mColumn = 6;
+ } else {
+ mColumn--;
+ }
+
+ if (isWithinCurrentMonth(mRow, mColumn)) {
+ return false;
+ }
+
+ // need to flip to last day of previous month
+ previousMonth();
+ int lastDay = getNumberOfDaysInMonth();
+ mRow = getRowOf(lastDay);
+ mColumn = getColumnOf(lastDay);
+ return true;
+ }
+
+ /**
+ * Move right one box, potentially flipping to the next month.
+ * @return Whether the month was flipped to the next month
+ * due to the move.
+ */
+ public boolean right() {
+ if (mColumn == 6) {
+ mRow++;
+ mColumn = 0;
+ } else {
+ mColumn++;
+ }
+
+ if (isWithinCurrentMonth(mRow, mColumn)) {
+ return false;
+ }
+
+ // need to flip to first day of next month
+ nextMonth();
+ mRow = 0;
+ mColumn = 0;
+ while (!isWithinCurrentMonth(mRow, mColumn)) {
+ mColumn++;
+ }
+ return true;
+ }
+
+}
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
new file mode 100644
index 0000000..1c5d669
--- /dev/null
+++ b/core/java/android/util/DebugUtils.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 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.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * <p>Various utilities for debugging and logging.</p>
+ */
+public class DebugUtils {
+ /**
+ * <p>Filters objects against the <code>ANDROID_OBJECT_FILTER</code>
+ * environment variable. This environment variable can filter objects
+ * based on their class name and attribute values.</p>
+ *
+ * <p>Here is the syntax for <code>ANDROID_OBJECT_FILTER</code>:</p>
+ *
+ * <p><code>ClassName@attribute1=value1@attribute2=value2...</code></p>
+ *
+ * <p>Examples:</p>
+ * <ul>
+ * <li>Select TextView instances: <code>TextView</code></li>
+ * <li>Select TextView instances of text "Loading" and bottom offset of 22:
+ * <code>TextView@text=Loading.*@bottom=22</code></li>
+ * </ul>
+ *
+ * <p>The class name and the values are regular expressions.</p>
+ *
+ * <p>This class is useful for debugging and logging purpose:</p>
+ * <pre>
+ * if (Config.DEBUG) {
+ * if (DebugUtils.isObjectSelected(childView) && Config.LOGV) {
+ * Log.v(TAG, "Object " + childView + " logged!");
+ * }
+ * }
+ * </pre>
+ *
+ * <p><strong>NOTE</strong>: This method is very expensive as it relies
+ * heavily on regular expressions and reflection. Calls to this method
+ * should always be stripped out of the release binaries and avoided
+ * as much as possible in debug mode.</p>
+ *
+ * @param object any object to match against the ANDROID_OBJECT_FILTER
+ * environement variable
+ * @return true if object is selected by the ANDROID_OBJECT_FILTER
+ * environment variable, false otherwise
+ */
+ public static boolean isObjectSelected(Object object) {
+ boolean match = false;
+ String s = System.getenv("ANDROID_OBJECT_FILTER");
+ if (s != null && s.length() > 0) {
+ String[] selectors = s.split("@");
+ // first selector == class name
+ if (object.getClass().getSimpleName().matches(selectors[0])) {
+ // check potential attributes
+ for (int i = 1; i < selectors.length; i++) {
+ String[] pair = selectors[i].split("=");
+ Class<?> klass = object.getClass();
+ try {
+ Method declaredMethod = null;
+ Class<?> parent = klass;
+ do {
+ declaredMethod = parent.getDeclaredMethod("get" +
+ pair[0].substring(0, 1).toUpperCase() +
+ pair[0].substring(1),
+ (Class[]) null);
+ } while ((parent = klass.getSuperclass()) != null &&
+ declaredMethod == null);
+
+ if (declaredMethod != null) {
+ Object value = declaredMethod
+ .invoke(object, (Object[])null);
+ match |= (value != null ?
+ value.toString() : "null").matches(pair[1]);
+ }
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ return match;
+ }
+
+}
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
new file mode 100644
index 0000000..8fc3602
--- /dev/null
+++ b/core/java/android/util/DisplayMetrics.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util;
+
+
+/**
+ * A structure describing general information about a display, such as its
+ * size, density, and font scaling.
+ */
+public class DisplayMetrics {
+ /**
+ * The absolute width of the display in pixels.
+ */
+ public int widthPixels;
+ /**
+ * The absolute height of the display in pixels.
+ */
+ public int heightPixels;
+ /**
+ * The logical density of the display. This is a scaling factor for the
+ * Density Independent Pixel unit, where one DIP is one pixel on an
+ * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
+ * providing the baseline of the system's display. Thus on a 160dpi screen
+ * this density value will be 1; on a 106 dpi screen it would be .75; etc.
+ *
+ * <p>This value does not exactly follow the real screen size (as given by
+ * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
+ * the overall UI in steps based on gross changes in the display dpi. For
+ * example, a 240x320 screen will have a density of 1 even if its width is
+ * 1.8", 1.3", etc. However, if the screen resolution is increased to
+ * 320x480 but the screen size remained 1.5"x2" then the density would be
+ * increased (probably to 1.5).
+ */
+ public float density;
+ /**
+ * A scaling factor for fonts displayed on the display. This is the same
+ * as {@link #density}, except that it may be adjusted in smaller
+ * increments at runtime based on a user preference for the font size.
+ */
+ public float scaledDensity;
+ /**
+ * The exact physical pixels per inch of the screen in the X dimension.
+ */
+ public float xdpi;
+ /**
+ * The exact physical pixels per inch of the screen in the Y dimension.
+ */
+ public float ydpi;
+
+ public DisplayMetrics() {
+ }
+
+ public void setTo(DisplayMetrics o) {
+ widthPixels = o.widthPixels;
+ heightPixels = o.heightPixels;
+ density = o.density;
+ scaledDensity = o.scaledDensity;
+ xdpi = o.xdpi;
+ ydpi = o.ydpi;
+ }
+
+ public void setToDefaults() {
+ widthPixels = 0;
+ heightPixels = 0;
+ density = 1;
+ scaledDensity = 1;
+ xdpi = 160;
+ ydpi = 160;
+ }
+}
+
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
new file mode 100644
index 0000000..24b4f73
--- /dev/null
+++ b/core/java/android/util/EventLog.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 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.util;
+
+import com.google.android.collect.Lists;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * {@hide}
+ * Dynamically defined (in terms of event types), space efficient (i.e. "tight") event logging
+ * to help instrument code for large scale stability and performance monitoring.
+ *
+ * Note that this class contains all static methods. This is done for efficiency reasons.
+ *
+ * Events for the event log are self-describing binary data structures. They start with a 20 byte
+ * header (generated automatically) which contains all of the following in order:
+ *
+ * <ul>
+ * <li> Payload length: 2 bytes - length of the non-header portion </li>
+ * <li> Padding: 2 bytes - no meaning at this time </li>
+ * <li> Timestamp:
+ * <ul>
+ * <li> Seconds: 4 bytes - seconds since Epoch </li>
+ * <li> Nanoseconds: 4 bytes - plus extra nanoseconds </li>
+ * </ul></li>
+ * <li> Process ID: 4 bytes - matching {@link android.os.Process#myPid} </li>
+ * <li> Thread ID: 4 bytes - matching {@link android.os.Process#myTid} </li>
+ * </li>
+ * </ul>
+ *
+ * The above is followed by a payload, comprised of the following:
+ * <ul>
+ * <li> Tag: 4 bytes - unique integer used to identify a particular event. This number is also
+ * used as a key to map to a string that can be displayed by log reading tools.
+ * </li>
+ * <li> Type: 1 byte - can be either {@link #INT}, {@link #LONG}, {@link #STRING},
+ * or {@link #LIST}. </li>
+ * <li> Event log value: the size and format of which is one of:
+ * <ul>
+ * <li> INT: 4 bytes </li>
+ * <li> LONG: 8 bytes </li>
+ * <li> STRING:
+ * <ul>
+ * <li> Size of STRING: 4 bytes </li>
+ * <li> The string: n bytes as specified in the size fields above. </li>
+ * </ul></li>
+ * <li> {@link List LIST}:
+ * <ul>
+ * <li> Num items: 1 byte </li>
+ * <li> N value payloads, where N is the number of items specified above. </li>
+ * </ul></li>
+ * </ul>
+ * </li>
+ * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
+ * corruption and enable stansard unix tools like grep, tail and wc to operate
+ * on event logs. </li>
+ * </ul>
+ *
+ * Note that all output is done in the endian-ness of the device (as determined
+ * by {@link ByteOrder#nativeOrder()}).
+ */
+
+public class EventLog {
+
+ // Value types
+ public static final byte INT = 0;
+ public static final byte LONG = 1;
+ public static final byte STRING = 2;
+ public static final byte LIST = 3;
+
+ /**
+ * An immutable tuple used to log a heterogeneous set of loggable items.
+ * The items can be Integer, Long, String, or {@link List}.
+ * The maximum number of items is 127
+ */
+ public static final class List {
+ private Object[] mItems;
+
+ /**
+ * Get a particular tuple item
+ * @param pos The position of the item in the tuple
+ */
+ public final Object getItem(int pos) {
+ return mItems[pos];
+ }
+
+ /**
+ * Get the number of items in the tuple.
+ */
+ public final byte getNumItems() {
+ return (byte) mItems.length;
+ }
+
+ /**
+ * Create a new tuple.
+ * @param items The items to create the tuple with, as varargs.
+ * @throws IllegalArgumentException if the arguments are too few (0),
+ * too many, or aren't loggable types.
+ */
+ public List(Object... items) throws IllegalArgumentException {
+ if (items.length > Byte.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "A List must have fewer than "
+ + Byte.MAX_VALUE + " items in it.");
+ }
+ if (items.length < 1) {
+ throw new IllegalArgumentException(
+ "A List must have at least one item in it.");
+ }
+ for (int i = 0; i < items.length; i++) {
+ final Object item = items[i];
+ if (item == null) {
+ // Would be nice to be able to write null strings...
+ items[i] = "";
+ } else if (!(item instanceof List ||
+ item instanceof String ||
+ item instanceof Integer ||
+ item instanceof Long)) {
+ throw new IllegalArgumentException(
+ "Attempt to create a List with illegal item type.");
+ }
+ }
+ this.mItems = items;
+ }
+ }
+
+ /**
+ * A previously logged event read from the logs.
+ */
+ public static final class Event {
+ private final ByteBuffer mBuffer;
+
+ // Layout of event log entry received from kernel.
+ private static final int LENGTH_OFFSET = 0;
+ private static final int PROCESS_OFFSET = 4;
+ private static final int THREAD_OFFSET = 8;
+ private static final int SECONDS_OFFSET = 12;
+ private static final int NANOSECONDS_OFFSET = 16;
+
+ private static final int PAYLOAD_START = 20;
+ private static final int TAG_OFFSET = 20;
+ private static final int DATA_START = 24;
+
+ /** @param data containing event, read from the system */
+ public Event(byte[] data) {
+ mBuffer = ByteBuffer.wrap(data);
+ mBuffer.order(ByteOrder.nativeOrder());
+ }
+
+ public int getProcessId() {
+ return mBuffer.getInt(PROCESS_OFFSET);
+ }
+
+ public int getThreadId() {
+ return mBuffer.getInt(THREAD_OFFSET);
+ }
+
+ public long getTimeNanos() {
+ return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
+ + mBuffer.getInt(NANOSECONDS_OFFSET);
+ }
+
+ public int getTag() {
+ return mBuffer.getInt(TAG_OFFSET);
+ }
+
+ /** @return one of Integer, Long, String, or List. */
+ public synchronized Object getData() {
+ mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
+ mBuffer.position(DATA_START); // Just after the tag.
+ return decodeObject();
+ }
+
+ /** @return the loggable item at the current position in mBuffer. */
+ private Object decodeObject() {
+ if (mBuffer.remaining() < 1) return null;
+ switch (mBuffer.get()) {
+ case INT:
+ if (mBuffer.remaining() < 4) return null;
+ return mBuffer.getInt();
+
+ case LONG:
+ if (mBuffer.remaining() < 8) return null;
+ return mBuffer.getLong();
+
+ case STRING:
+ try {
+ if (mBuffer.remaining() < 4) return null;
+ int length = mBuffer.getInt();
+ if (length < 0 || mBuffer.remaining() < length) return null;
+ int start = mBuffer.position();
+ mBuffer.position(start + length);
+ return new String(mBuffer.array(), start, length, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // UTF-8 is guaranteed.
+ }
+
+ case LIST:
+ if (mBuffer.remaining() < 1) return null;
+ int length = mBuffer.get();
+ if (length <= 0) return null;
+ Object[] array = new Object[length];
+ for (int i = 0; i < length; ++i) {
+ array[i] = decodeObject();
+ if (array[i] == null) return null;
+ }
+ return new List(array);
+
+ default:
+ return null;
+ }
+ }
+ }
+
+ // We assume that the native methods deal with any concurrency issues.
+
+ /**
+ * Send an event log message.
+ * @param tag An event identifer
+ * @param value A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeEvent(int tag, int value);
+
+ /**
+ * Send an event log message.
+ * @param tag An event identifer
+ * @param value A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeEvent(int tag, long value);
+
+ /**
+ * Send an event log message.
+ * @param tag An event identifer
+ * @param str A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeEvent(int tag, String str);
+
+ /**
+ * Send an event log message.
+ * @param tag An event identifer
+ * @param list A {@link List} to log
+ * @return The number of bytes written
+ */
+ public static native int writeEvent(int tag, List list);
+
+ /**
+ * Send an event log message.
+ * @param tag An event identifer
+ * @param list A list of values to log
+ * @return The number of bytes written
+ */
+ public static int writeEvent(int tag, Object... list) {
+ return writeEvent(tag, new List(list));
+ }
+
+ /**
+ * Read events from the log, filtered by type.
+ * @param tags to search for
+ * @param output container to add events into
+ * @throws IOException if something goes wrong reading events
+ */
+ public static native void readEvents(int[] tags, Collection<Event> output)
+ throws IOException;
+}
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
new file mode 100644
index 0000000..be905e3
--- /dev/null
+++ b/core/java/android/util/EventLogTags.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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;
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Parsed representation of /etc/event-log-tags. */
+public class EventLogTags {
+ private final static String TAG = "EventLogTags";
+
+ private final static String TAGS_FILE = "/etc/event-log-tags";
+
+ public static class Description {
+ public final int mTag;
+ public final String mName;
+ // TODO: Parse parameter descriptions when anyone has a use for them.
+
+ Description(int tag, String name) {
+ mTag = tag;
+ mName = name;
+ }
+ }
+
+ private final static Pattern COMMENT_PATTERN = Pattern.compile(
+ "^\\s*(#.*)?$");
+
+ private final static Pattern TAG_PATTERN = Pattern.compile(
+ "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$");
+
+ private final HashMap<String, Description> mNameMap =
+ new HashMap<String, Description>();
+
+ private final HashMap<Integer, Description> mTagMap =
+ new HashMap<Integer, Description>();
+
+ public EventLogTags() throws IOException {
+ this(new BufferedReader(new FileReader(TAGS_FILE), 256));
+ }
+
+ public EventLogTags(BufferedReader input) throws IOException {
+ String line;
+ while ((line = input.readLine()) != null) {
+ Matcher m = COMMENT_PATTERN.matcher(line);
+ if (m.matches()) continue;
+
+ m = TAG_PATTERN.matcher(line);
+ if (m.matches()) {
+ try {
+ int tag = Integer.parseInt(m.group(1));
+ Description d = new Description(tag, m.group(2));
+ mNameMap.put(d.mName, d);
+ mTagMap.put(d.mTag, d);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error in event log tags entry: " + line, e);
+ }
+ } else {
+ Log.e(TAG, "Can't parse event log tags entry: " + line);
+ }
+ }
+ }
+
+ public Description get(String name) {
+ return mNameMap.get(name);
+ }
+
+ public Description get(int tag) {
+ return mTagMap.get(tag);
+ }
+}
diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java
new file mode 100644
index 0000000..6216638
--- /dev/null
+++ b/core/java/android/util/FloatMath.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 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.util;
+
+/**
+ * Math routines similar to those found in {@link java.lang.Math}. Performs
+ * computations on {@code float} values directly without incurring the overhead
+ * of conversions to and from {@code double}.
+ *
+ * <p>On one platform, {@code FloatMath.sqrt(100)} executes in one third of the
+ * time required by {@code java.lang.Math.sqrt(100)}.</p>
+ */
+public class FloatMath {
+
+ /** Prevents instantiation. */
+ private FloatMath() {}
+
+ /**
+ * Returns the float conversion of the most positive (i.e. closest to
+ * positive infinity) integer value which is less than the argument.
+ *
+ * @param value to be converted
+ * @return the floor of value
+ */
+ public static native float floor(float value);
+
+ /**
+ * Returns the float conversion of the most negative (i.e. closest to
+ * negative infinity) integer value which is greater than the argument.
+ *
+ * @param value to be converted
+ * @return the ceiling of value
+ */
+ public static native float ceil(float value);
+
+ /**
+ * Returns the closest float approximation of the sine of the argument.
+ *
+ * @param angle to compute the cosine of, in radians
+ * @return the sine of angle
+ */
+ public static native float sin(float angle);
+
+ /**
+ * Returns the closest float approximation of the cosine of the argument.
+ *
+ * @param angle to compute the cosine of, in radians
+ * @return the cosine of angle
+ */
+ public static native float cos(float angle);
+
+ /**
+ * Returns the closest float approximation of the square root of the
+ * argument.
+ *
+ * @param value to compute sqrt of
+ * @return the square root of value
+ */
+ public static native float sqrt(float value);
+}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
new file mode 100644
index 0000000..24f67cd
--- /dev/null
+++ b/core/java/android/util/Log.java
@@ -0,0 +1,247 @@
+/*
+ * 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.util;
+
+import com.android.internal.os.RuntimeInit;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * API for sending log output.
+ *
+ * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e()
+ * methods.
+ *
+ * <p>The order in terms of verbosity, from least to most is
+ * ERROR, WARN, INFO, DEBUG, VERBOSE. Verbose should never be compiled
+ * into an application except during development. Debug logs are compiled
+ * in but stripped at runtime. Error, warning and info logs are always kept.
+ *
+ * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
+ * in your class:
+ *
+ * <pre>private static final String TAG = "MyActivity";</pre>
+ *
+ * and use that in subsequent calls to the log methods.
+ * </p>
+ *
+ * <p><b>Tip:</b> Don't forget that when you make a call like
+ * <pre>Log.v(TAG, "index=" + i);</pre>
+ * that when you're building the string to pass into Log.d, the compiler uses a
+ * StringBuilder and at least three allocations occur: the StringBuilder
+ * itself, the buffer, and the String object. Realistically, there is also
+ * another buffer allocation and copy, and even more pressure on the gc.
+ * That means that if your log message is filtered out, you might be doing
+ * significant work and incurring significant overhead.
+ */
+public final class Log {
+
+ /**
+ * Priority constant for the println method; use Log.v.
+ */
+ public static final int VERBOSE = 2;
+
+ /**
+ * Priority constant for the println method; use Log.d.
+ */
+ public static final int DEBUG = 3;
+
+ /**
+ * Priority constant for the println method; use Log.i.
+ */
+ public static final int INFO = 4;
+
+ /**
+ * Priority constant for the println method; use Log.w.
+ */
+ public static final int WARN = 5;
+
+ /**
+ * Priority constant for the println method; use Log.e.
+ */
+ public static final int ERROR = 6;
+
+ /**
+ * Priority constant for the println method.
+ */
+ public static final int ASSERT = 7;
+
+ private Log() {
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int v(String tag, String msg) {
+ return println(VERBOSE, tag, msg);
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int v(String tag, String msg, Throwable tr) {
+ return println(VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int d(String tag, String msg) {
+ return println(DEBUG, tag, msg);
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int d(String tag, String msg, Throwable tr) {
+ return println(DEBUG, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send an {@link #INFO} log message.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int i(String tag, String msg) {
+ return println(INFO, tag, msg);
+ }
+
+ /**
+ * Send a {@link #INFO} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int i(String tag, String msg, Throwable tr) {
+ return println(INFO, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send a {@link #WARN} log message.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int w(String tag, String msg) {
+ return println(WARN, tag, msg);
+ }
+
+ /**
+ * Send a {@link #WARN} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int w(String tag, String msg, Throwable tr) {
+ return println(WARN, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Checks to see whether or not a log for the specified tag is loggable at the specified level.
+ *
+ * The default level of any tag is set to INFO. This means that any level above and including
+ * INFO will be logged. Before you make any calls to a logging method you should check to see
+ * if your tag should be logged. You can change the default level by setting a system property:
+ * 'setprop log.tag.&lt;YOUR_LOG_TAG> &lt;LEVEL>'
+ * Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPRESS will
+ * turn off all logging for your tag. You can also create a local.prop file that with the
+ * following in it:
+ * 'log.tag.&lt;YOUR_LOG_TAG>=&lt;LEVEL>'
+ * and place that in /data/local.prop.
+ *
+ * @param tag The tag to check.
+ * @param level The level to check.
+ * @return Whether or not that this is allowed to be logged.
+ * @throws IllegalArgumentException is thrown if the tag.length() > 23.
+ */
+ public static native boolean isLoggable(String tag, int level);
+
+ /*
+ * Send a {@link #WARN} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ */
+ public static int w(String tag, Throwable tr) {
+ return println(WARN, tag, getStackTraceString(tr));
+ }
+
+ /**
+ * Send an {@link #ERROR} log message.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int e(String tag, String msg) {
+ return println(ERROR, tag, msg);
+ }
+
+ /**
+ * Send a {@link #ERROR} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int e(String tag, String msg, Throwable tr) {
+ int r = println(ERROR, tag, msg + '\n' + getStackTraceString(tr));
+ RuntimeInit.reportException(tag, tr, false); // asynchronous
+ return r;
+ }
+
+ /**
+ * Handy function to get a loggable stack trace from a Throwable
+ * @param tr An exception to log
+ */
+ public static String getStackTraceString(Throwable tr) {
+ if (tr == null) {
+ return "";
+ }
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ tr.printStackTrace(pw);
+ return sw.toString();
+ }
+
+ /**
+ * Low-level logging call.
+ * @param priority The priority/type of this log message
+ * @param tag Used to identify the source of a log message. It usually identfies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @return The number of bytes written.
+ */
+ public static native int println(int priority, String tag, String msg);
+}
diff --git a/core/java/android/util/LogPrinter.java b/core/java/android/util/LogPrinter.java
new file mode 100644
index 0000000..643b8d3
--- /dev/null
+++ b/core/java/android/util/LogPrinter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of a {@link android.util.Printer} that sends its output
+ * to the system log.
+ */
+public class LogPrinter implements Printer {
+ private final int mPriority;
+ private final String mTag;
+
+ /**
+ * Create a new Printer that sends to the log with the given priority
+ * and tag.
+ *
+ * @param priority The desired log priority:
+ * {@link android.util.Log#VERBOSE Log.VERBOSE},
+ * {@link android.util.Log#DEBUG Log.DEBUG},
+ * {@link android.util.Log#INFO Log.INFO},
+ * {@link android.util.Log#WARN Log.WARN}, or
+ * {@link android.util.Log#ERROR Log.ERROR}.
+ * @param tag A string tag to associate with each printed log statement.
+ */
+ public LogPrinter(int priority, String tag) {
+ mPriority = priority;
+ mTag = tag;
+ }
+
+ public void println(String x) {
+ Log.println(mPriority, mTag, x);
+ }
+}
diff --git a/core/java/android/util/MonthDisplayHelper.java b/core/java/android/util/MonthDisplayHelper.java
new file mode 100644
index 0000000..c3f13fc
--- /dev/null
+++ b/core/java/android/util/MonthDisplayHelper.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 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.util;
+
+import java.util.Calendar;
+
+/**
+ * Helps answer common questions that come up when displaying a month in a
+ * 6 row calendar grid format.
+ *
+ * Not thread safe.
+ */
+public class MonthDisplayHelper {
+
+ // display pref
+ private final int mWeekStartDay;
+
+ // holds current month, year, helps compute display
+ private Calendar mCalendar;
+
+ // cached computed stuff that helps with display
+ private int mNumDaysInMonth;
+ private int mNumDaysInPrevMonth;
+ private int mOffset;
+
+
+ /**
+ * @param year The year.
+ * @param month The month.
+ * @param weekStartDay What day of the week the week should start.
+ */
+ public MonthDisplayHelper(int year, int month, int weekStartDay) {
+
+ if (weekStartDay < Calendar.SUNDAY || weekStartDay > Calendar.SATURDAY) {
+ throw new IllegalArgumentException();
+ }
+ mWeekStartDay = weekStartDay;
+
+ mCalendar = Calendar.getInstance();
+ mCalendar.set(Calendar.YEAR, year);
+ mCalendar.set(Calendar.MONTH, month);
+ mCalendar.set(Calendar.DAY_OF_MONTH, 1);
+ mCalendar.set(Calendar.HOUR_OF_DAY, 0);
+ mCalendar.set(Calendar.MINUTE, 0);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.getTimeInMillis();
+
+ recalculate();
+ }
+
+
+ public MonthDisplayHelper(int year, int month) {
+ this(year, month, Calendar.SUNDAY);
+ }
+
+
+ public int getYear() {
+ return mCalendar.get(Calendar.YEAR);
+ }
+
+ public int getMonth() {
+ return mCalendar.get(Calendar.MONTH);
+ }
+
+
+ public int getWeekStartDay() {
+ return mWeekStartDay;
+ }
+
+ /**
+ * @return The first day of the month using a constants such as
+ * {@link java.util.Calendar#SUNDAY}.
+ */
+ public int getFirstDayOfMonth() {
+ return mCalendar.get(Calendar.DAY_OF_WEEK);
+ }
+
+ /**
+ * @return The number of days in the month.
+ */
+ public int getNumberOfDaysInMonth() {
+ return mNumDaysInMonth;
+ }
+
+
+ /**
+ * @return The offset from displaying everything starting on the very first
+ * box. For example, if the calendar is set to display the first day of
+ * the week as Sunday, and the month starts on a Wednesday, the offset is 3.
+ */
+ public int getOffset() {
+ return mOffset;
+ }
+
+
+ /**
+ * @param row Which row (0-5).
+ * @return the digits of the month to display in one
+ * of the 6 rows of a calendar month display.
+ */
+ public int[] getDigitsForRow(int row) {
+ if (row < 0 || row > 5) {
+ throw new IllegalArgumentException("row " + row
+ + " out of range (0-5)");
+ }
+
+ int [] result = new int[7];
+ for (int column = 0; column < 7; column++) {
+ result[column] = getDayAt(row, column);
+ }
+
+ return result;
+ }
+
+ /**
+ * @param row The row, 0-5, starting from the top.
+ * @param column The column, 0-6, starting from the left.
+ * @return The day at a particular row, column
+ */
+ public int getDayAt(int row, int column) {
+
+ if (row == 0 && column < mOffset) {
+ return mNumDaysInPrevMonth + column - mOffset + 1;
+ }
+
+ int day = 7 * row + column - mOffset + 1;
+
+ return (day > mNumDaysInMonth) ?
+ day - mNumDaysInMonth : day;
+ }
+
+ /**
+ * @return Which row day is in.
+ */
+ public int getRowOf(int day) {
+ return (day + mOffset - 1) / 7;
+ }
+
+ /**
+ * @return Which column day is in.
+ */
+ public int getColumnOf(int day) {
+ return (day + mOffset - 1) % 7;
+ }
+
+ /**
+ * Decrement the month.
+ */
+ public void previousMonth() {
+ mCalendar.add(Calendar.MONTH, -1);
+ recalculate();
+ }
+
+ /**
+ * Increment the month.
+ */
+ public void nextMonth() {
+ mCalendar.add(Calendar.MONTH, 1);
+ recalculate();
+ }
+
+ /**
+ * @return Whether the row and column fall within the month.
+ */
+ public boolean isWithinCurrentMonth(int row, int column) {
+
+ if (row < 0 || column < 0 || row > 5 || column > 6) {
+ return false;
+ }
+
+ if (row == 0 && column < mOffset) {
+ return false;
+ }
+
+ int day = 7 * row + column - mOffset + 1;
+ if (day > mNumDaysInMonth) {
+ return false;
+ }
+ return true;
+ }
+
+
+ // helper method that recalculates cached values based on current month / year
+ private void recalculate() {
+
+ mNumDaysInMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+
+ mCalendar.add(Calendar.MONTH, -1);
+ mNumDaysInPrevMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ mCalendar.add(Calendar.MONTH, 1);
+
+ int firstDayOfMonth = getFirstDayOfMonth();
+ int offset = firstDayOfMonth - mWeekStartDay;
+ if (offset < 0) {
+ offset += 7;
+ }
+ mOffset = offset;
+ }
+}
diff --git a/core/java/android/util/PrintWriterPrinter.java b/core/java/android/util/PrintWriterPrinter.java
new file mode 100644
index 0000000..82c4d03
--- /dev/null
+++ b/core/java/android/util/PrintWriterPrinter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util;
+
+import java.io.PrintWriter;
+
+/**
+ * Implementation of a {@link android.util.Printer} that sends its output
+ * to a {@link java.io.PrintWriter}.
+ */
+public class PrintWriterPrinter implements Printer {
+ private final PrintWriter mPW;
+
+ /**
+ * Create a new Printer that sends to a PrintWriter object.
+ *
+ * @param pw The PrintWriter where you would like output to go.
+ */
+ public PrintWriterPrinter(PrintWriter pw) {
+ mPW = pw;
+ }
+
+ public void println(String x) {
+ mPW.println(x);
+ }
+}
diff --git a/core/java/android/util/Printer.java b/core/java/android/util/Printer.java
new file mode 100644
index 0000000..595cf70
--- /dev/null
+++ b/core/java/android/util/Printer.java
@@ -0,0 +1,31 @@
+/*
+ * 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.util;
+
+/**
+ * Simple interface for printing text, allowing redirection to various
+ * targets. Standard implementations are {@link android.util.LogPrinter},
+ * {@link android.util.StringBuilderPrinter}, and
+ * {@link android.util.PrintWriterPrinter}.
+ */
+public interface Printer {
+ /**
+ * Write a line of text to the output. There is no need to terminate
+ * the given string with a newline.
+ */
+ void println(String x);
+}
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
new file mode 100644
index 0000000..1c8b330
--- /dev/null
+++ b/core/java/android/util/SparseArray.java
@@ -0,0 +1,340 @@
+/*
+ * 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.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * SparseArrays map integers to Objects. Unlike a normal array of Objects,
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Integers to Objects.
+ */
+public class SparseArray<E> {
+ private static final Object DELETED = new Object();
+ private boolean mGarbage = false;
+
+ /**
+ * Creates a new SparseArray containing no mappings.
+ */
+ public SparseArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public SparseArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new int[initialCapacity];
+ mValues = new Object[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key) {
+ return get(key, null);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(int key, E valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0 || mValues[i] == DELETED) {
+ return valueIfKeyNotFound;
+ } else {
+ return (E) mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ if (mValues[i] != DELETED) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key) {
+ delete(key);
+ }
+
+ private void gc() {
+ // Log.e("SparseArray", "gc start with " + mSize);
+
+ int n = mSize;
+ int o = 0;
+ int[] keys = mKeys;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ Object val = values[i];
+
+ if (val != DELETED) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+
+ // Log.e("SparseArray", "gc end with " + mSize);
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = value;
+ } else {
+ i = ~i;
+
+ if (i < mSize && mValues[i] == DELETED) {
+ mKeys[i] = key;
+ mValues[i] = value;
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~binarySearch(mKeys, 0, mSize, key);
+ }
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public int keyAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public E valueAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return (E) mValues[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public void setValueAt(int index, E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i] == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ int n = mSize;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ values[i] = null;
+ }
+
+ mSize = 0;
+ mGarbage = false;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length) {
+ gc();
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ private static int binarySearch(int[] a, int start, int len, int key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private void checkIntegrity() {
+ for (int i = 1; i < mSize; i++) {
+ if (mKeys[i] <= mKeys[i - 1]) {
+ for (int j = 0; j < mSize; j++) {
+ Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
+ }
+
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ private int[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+}
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
new file mode 100644
index 0000000..f7799de
--- /dev/null
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -0,0 +1,245 @@
+/*
+ * 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.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * SparseBooleanArrays map integers to booleans.
+ * Unlike a normal array of booleans
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Integers to Booleans.
+ */
+public class SparseBooleanArray {
+ /**
+ * Creates a new SparseBooleanArray containing no mappings.
+ */
+ public SparseBooleanArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseBooleanArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public SparseBooleanArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new int[initialCapacity];
+ mValues = new boolean[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or <code>false</code>
+ * if no such mapping has been made.
+ */
+ public boolean get(int key) {
+ return get(key, false);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public boolean get(int key, boolean valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0) {
+ return valueIfKeyNotFound;
+ } else {
+ return mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1));
+ System.arraycopy(mValues, i + 1, mValues, i, mSize - (i + 1));
+ mSize--;
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, boolean value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = value;
+ } else {
+ i = ~i;
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ boolean[] nvalues = new boolean[n];
+
+ // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseBooleanArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseBooleanArray
+ * currently stores.
+ */
+ public int size() {
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ */
+ public int keyAt(int index) {
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ */
+ public boolean valueAt(int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(boolean value) {
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i] == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseBooleanArray.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, boolean value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ boolean[] nvalues = new boolean[n];
+
+ // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ private static int binarySearch(int[] a, int start, int len, int key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private void checkIntegrity() {
+ for (int i = 1; i < mSize; i++) {
+ if (mKeys[i] <= mKeys[i - 1]) {
+ for (int j = 0; j < mSize; j++) {
+ Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
+ }
+
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ private int[] mKeys;
+ private boolean[] mValues;
+ private int mSize;
+}
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
new file mode 100644
index 0000000..610cfd4
--- /dev/null
+++ b/core/java/android/util/SparseIntArray.java
@@ -0,0 +1,244 @@
+/*
+ * 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.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * SparseIntArrays map integers to integers. Unlike a normal array of integers,
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Integers to Integers.
+ */
+public class SparseIntArray {
+ /**
+ * Creates a new SparseIntArray containing no mappings.
+ */
+ public SparseIntArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseIntArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public SparseIntArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new int[initialCapacity];
+ mValues = new int[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the int mapped from the specified key, or <code>0</code>
+ * if no such mapping has been made.
+ */
+ public int get(int key) {
+ return get(key, 0);
+ }
+
+ /**
+ * Gets the int mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public int get(int key, int valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0) {
+ return valueIfKeyNotFound;
+ } else {
+ return mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1));
+ System.arraycopy(mValues, i + 1, mValues, i, mSize - (i + 1));
+ mSize--;
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, int value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = value;
+ } else {
+ i = ~i;
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ int[] nvalues = new int[n];
+
+ // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseIntArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseIntArray
+ * currently stores.
+ */
+ public int size() {
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseIntArray stores.
+ */
+ public int keyAt(int index) {
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseIntArray stores.
+ */
+ public int valueAt(int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(int value) {
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i] == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseIntArray.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, int value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ int[] nvalues = new int[n];
+
+ // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ private static int binarySearch(int[] a, int start, int len, int key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private void checkIntegrity() {
+ for (int i = 1; i < mSize; i++) {
+ if (mKeys[i] <= mKeys[i - 1]) {
+ for (int j = 0; j < mSize; j++) {
+ Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
+ }
+
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ private int[] mKeys;
+ private int[] mValues;
+ private int mSize;
+}
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
new file mode 100644
index 0000000..f3d8159
--- /dev/null
+++ b/core/java/android/util/StateSet.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 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.util;
+
+import com.android.internal.R;
+
+/**
+ * State sets are arrays of positive ints where each element
+ * represents the state of a {@link android.view.View} (e.g. focused,
+ * selected, visible, etc.). A {@link android.view.View} may be in
+ * one or more of those states.
+ *
+ * A state spec is an array of signed ints where each element
+ * represents a required (if positive) or an undesired (if negative)
+ * {@link android.view.View} state.
+ *
+ * Utils dealing with state sets.
+ *
+ * In theory we could encapsulate the state set and state spec arrays
+ * and not have static methods here but there is some concern about
+ * performance since these methods are called during view drawing.
+ */
+
+public class StateSet {
+
+ public static final int[] WILD_CARD = new int[0];
+
+ /**
+ * Return whether the stateSetOrSpec is matched by all StateSets.
+ *
+ * @param stateSetOrSpec a state set or state spec.
+ */
+ public static boolean isWildCard(int[] stateSetOrSpec) {
+ return stateSetOrSpec.length == 0 || stateSetOrSpec[0] == 0;
+ }
+
+ /**
+ * Return whether the stateSet matches the desired stateSpec.
+ *
+ * @param stateSpec an array of required (if positive) or
+ * prohibited (if negative) {@link android.view.View} states.
+ * @param stateSet an array of {@link android.view.View} states
+ */
+ public static boolean stateSetMatches(int[] stateSpec, int[] stateSet) {
+ if (stateSet == null) {
+ return (stateSpec == null || isWildCard(stateSpec));
+ }
+ int stateSpecSize = stateSpec.length;
+ int stateSetSize = stateSet.length;
+ for (int i = 0; i < stateSpecSize; i++) {
+ int stateSpecState = stateSpec[i];
+ if (stateSpecState == 0) {
+ // We've reached the end of the cases to match against.
+ return true;
+ }
+ final boolean mustMatch;
+ if (stateSpecState > 0) {
+ mustMatch = true;
+ } else {
+ // We use negative values to indicate must-NOT-match states.
+ mustMatch = false;
+ stateSpecState = -stateSpecState;
+ }
+ boolean found = false;
+ for (int j = 0; j < stateSetSize; j++) {
+ final int state = stateSet[j];
+ if (state == 0) {
+ // We've reached the end of states to match.
+ if (mustMatch) {
+ // We didn't find this must-match state.
+ return false;
+ } else {
+ // Continue checking other must-not-match states.
+ break;
+ }
+ }
+ if (state == stateSpecState) {
+ if (mustMatch) {
+ found = true;
+ // Continue checking other other must-match states.
+ break;
+ } else {
+ // Any match of a must-not-match state returns false.
+ return false;
+ }
+ }
+ }
+ if (mustMatch && !found) {
+ // We've reached the end of states to match and we didn't
+ // find a must-match state.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return whether the state matches the desired stateSpec.
+ *
+ * @param stateSpec an array of required (if positive) or
+ * prohibited (if negative) {@link android.view.View} states.
+ * @param state a {@link android.view.View} state
+ */
+ public static boolean stateSetMatches(int[] stateSpec, int state) {
+ int stateSpecSize = stateSpec.length;
+ for (int i = 0; i < stateSpecSize; i++) {
+ int stateSpecState = stateSpec[i];
+ if (stateSpecState == 0) {
+ // We've reached the end of the cases to match against.
+ return true;
+ }
+ if (stateSpecState > 0) {
+ if (state != stateSpecState) {
+ return false;
+ }
+ } else {
+ // We use negative values to indicate must-NOT-match states.
+ if (state == -stateSpecState) {
+ // We matched a must-not-match case.
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static int[] trimStateSet(int[] states, int newSize) {
+ if (states.length == newSize) {
+ return states;
+ }
+
+ int[] trimmedStates = new int[newSize];
+ System.arraycopy(states, 0, trimmedStates, 0, newSize);
+ return trimmedStates;
+ }
+
+ public static String dump(int[] states) {
+ StringBuilder sb = new StringBuilder();
+
+ int count = states.length;
+ for (int i = 0; i < count; i++) {
+
+ switch (states[i]) {
+ case R.attr.state_window_focused:
+ sb.append("W ");
+ break;
+ case R.attr.state_pressed:
+ sb.append("P ");
+ break;
+ case R.attr.state_selected:
+ sb.append("S ");
+ break;
+ case R.attr.state_focused:
+ sb.append("F ");
+ break;
+ case R.attr.state_enabled:
+ sb.append("E ");
+ break;
+ }
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/core/java/android/util/StringBuilderPrinter.java b/core/java/android/util/StringBuilderPrinter.java
new file mode 100644
index 0000000..d0fc1e7
--- /dev/null
+++ b/core/java/android/util/StringBuilderPrinter.java
@@ -0,0 +1,42 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of a {@link android.util.Printer} that sends its output
+ * to a {@link StringBuilder}.
+ */
+public class StringBuilderPrinter implements Printer {
+ private final StringBuilder mBuilder;
+
+ /**
+ * Create a new Printer that sends to a StringBuilder object.
+ *
+ * @param builder The StringBuilder where you would like output to go.
+ */
+ public StringBuilderPrinter(StringBuilder builder) {
+ mBuilder = builder;
+ }
+
+ public void println(String x) {
+ mBuilder.append(x);
+ int len = x.length();
+ if (len <= 0 || x.charAt(len-1) != '\n') {
+ mBuilder.append('\n');
+ }
+ }
+}
diff --git a/core/java/android/util/TimeFormatException.java b/core/java/android/util/TimeFormatException.java
new file mode 100644
index 0000000..d7a898b
--- /dev/null
+++ b/core/java/android/util/TimeFormatException.java
@@ -0,0 +1,26 @@
+/*
+ * 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.util;
+
+public class TimeFormatException extends RuntimeException
+{
+ TimeFormatException(String s)
+ {
+ super(s);
+ }
+}
+
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
new file mode 100644
index 0000000..3c4e337
--- /dev/null
+++ b/core/java/android/util/TimeUtils.java
@@ -0,0 +1,109 @@
+/*
+ * 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.util;
+
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.TimeZone;
+import java.util.Date;
+
+import com.android.internal.util.XmlUtils;
+
+public class TimeUtils {
+ /**
+ * Tries to return a time zone that would have had the specified offset
+ * and DST value at the specified moment in the specified country.
+ * Returns null if no suitable zone could be found.
+ */
+ public static TimeZone getTimeZone(int offset, boolean dst, long when,
+ String country) {
+ if (country == null) {
+ return null;
+ }
+
+ TimeZone best = null;
+
+ Resources r = Resources.getSystem();
+ XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
+ Date d = new Date(when);
+
+ TimeZone current = TimeZone.getDefault();
+ String currentName = current.getID();
+ int currentOffset = current.getOffset(when);
+ boolean currentDst = current.inDaylightTime(d);
+
+ try {
+ XmlUtils.beginDocument(parser, "timezones");
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+
+ String element = parser.getName();
+ if (element == null || !(element.equals("timezone"))) {
+ break;
+ }
+
+ String code = parser.getAttributeValue(null, "code");
+
+ if (country.equals(code)) {
+ if (parser.next() == XmlPullParser.TEXT) {
+ String maybe = parser.getText();
+
+ // If the current time zone is from the right country
+ // and meets the other known properties, keep it
+ // instead of changing to another one.
+
+ if (maybe.equals(currentName)) {
+ if (currentOffset == offset && currentDst == dst) {
+ return current;
+ }
+ }
+
+ // Otherwise, take the first zone from the right
+ // country that has the correct current offset and DST.
+ // (Keep iterating instead of returning in case we
+ // haven't encountered the current time zone yet.)
+
+ if (best == null) {
+ TimeZone tz = TimeZone.getTimeZone(maybe);
+
+ if (tz.getOffset(when) == offset &&
+ tz.inDaylightTime(d) == dst) {
+ best = tz;
+ }
+ }
+ }
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Log.e("TimeUtils",
+ "Got exception while getting preferred time zone.", e);
+ } catch (IOException e) {
+ Log.e("TimeUtils",
+ "Got exception while getting preferred time zone.", e);
+ } finally {
+ parser.close();
+ }
+
+ return best;
+ }
+}
diff --git a/core/java/android/util/TimingLogger.java b/core/java/android/util/TimingLogger.java
new file mode 100644
index 0000000..0f39c97
--- /dev/null
+++ b/core/java/android/util/TimingLogger.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 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.util;
+
+import java.util.ArrayList;
+
+import android.os.SystemClock;
+
+/**
+ * A utility class to help log timings splits throughout a method call.
+ * Typical usage is:
+ *
+ * TimingLogger timings = new TimingLogger(TAG, "methodA");
+ * ... do some work A ...
+ * timings.addSplit("work A");
+ * ... do some work B ...
+ * timings.addSplit("work B");
+ * ... do some work C ...
+ * timings.addSplit("work C");
+ * timings.dumpToLog();
+ *
+ * The dumpToLog call would add the following to the log:
+ *
+ * D/TAG ( 3459): methodA: begin
+ * D/TAG ( 3459): methodA: 9 ms, work A
+ * D/TAG ( 3459): methodA: 1 ms, work B
+ * D/TAG ( 3459): methodA: 6 ms, work C
+ * D/TAG ( 3459): methodA: end, 16 ms
+ */
+public class TimingLogger {
+
+ /**
+ * The Log tag to use for checking Log.isLoggable and for
+ * logging the timings.
+ */
+ private String mTag;
+
+ /** A label to be included in every log. */
+ private String mLabel;
+
+ /** Used to track whether Log.isLoggable was enabled at reset time. */
+ private boolean mDisabled;
+
+ /** Stores the time of each split. */
+ ArrayList<Long> mSplits;
+
+ /** Stores the labels for each split. */
+ ArrayList<String> mSplitLabels;
+
+ /**
+ * Create and initialize a TimingLogger object that will log using
+ * the specific tag. If the Log.isLoggable is not enabled to at
+ * least the Log.VERBOSE level for that tag at creation time then
+ * the addSplit and dumpToLog call will do nothing.
+ * @param tag the log tag to use while logging the timings
+ * @param label a string to be displayed with each log
+ */
+ public TimingLogger(String tag, String label) {
+ reset(tag, label);
+ }
+
+ /**
+ * Clear and initialize a TimingLogger object that will log using
+ * the specific tag. If the Log.isLoggable is not enabled to at
+ * least the Log.VERBOSE level for that tag at creation time then
+ * the addSplit and dumpToLog call will do nothing.
+ * @param tag the log tag to use while logging the timings
+ * @param label a string to be displayed with each log
+ */
+ public void reset(String tag, String label) {
+ mTag = tag;
+ mLabel = label;
+ reset();
+ }
+
+ /**
+ * Clear and initialize a TimingLogger object that will log using
+ * the tag and label that was specified previously, either via
+ * the constructor or a call to reset(tag, label). If the
+ * Log.isLoggable is not enabled to at least the Log.VERBOSE
+ * level for that tag at creation time then the addSplit and
+ * dumpToLog call will do nothing.
+ */
+ public void reset() {
+ mDisabled = !Log.isLoggable(mTag, Log.VERBOSE);
+ if (mDisabled) return;
+ if (mSplits == null) {
+ mSplits = new ArrayList<Long>();
+ mSplitLabels = new ArrayList<String>();
+ } else {
+ mSplits.clear();
+ mSplitLabels.clear();
+ }
+ addSplit(null);
+ }
+
+ /**
+ * Add a split for the current time, labeled with splitLabel. If
+ * Log.isLoggable was not enabled to at least the Log.VERBOSE for
+ * the specified tag at construction or reset() time then this
+ * call does nothing.
+ * @param splitLabel a label to associate with this split.
+ */
+ public void addSplit(String splitLabel) {
+ if (mDisabled) return;
+ long now = SystemClock.elapsedRealtime();
+ mSplits.add(now);
+ mSplitLabels.add(splitLabel);
+ }
+
+ /**
+ * Dumps the timings to the log using Log.d(). If Log.isLoggable was
+ * not enabled to at least the Log.VERBOSE for the specified tag at
+ * construction or reset() time then this call does nothing.
+ */
+ public void dumpToLog() {
+ if (mDisabled) return;
+ Log.d(mTag, mLabel + ": begin");
+ final long first = mSplits.get(0);
+ long now = first;
+ for (int i = 1; i < mSplits.size(); i++) {
+ now = mSplits.get(i);
+ final String splitLabel = mSplitLabels.get(i);
+ final long prev = mSplits.get(i - 1);
+
+ Log.d(mTag, mLabel + ": " + (now - prev) + " ms, " + splitLabel);
+ }
+ Log.d(mTag, mLabel + ": end, " + (now - first) + " ms");
+ }
+}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
new file mode 100644
index 0000000..a4ee35a
--- /dev/null
+++ b/core/java/android/util/TypedValue.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 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.util;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * Container for a dynamically typed data value. Primarily used with
+ * {@link android.content.res.Resources} for holding resource values.
+ */
+public class TypedValue {
+ /** The value contains no data. */
+ public static final int TYPE_NULL = 0x00;
+
+ /** The <var>data</var> field holds a resource identifier. */
+ public static final int TYPE_REFERENCE = 0x01;
+ /** The <var>data</var> field holds an attribute resource
+ * identifier (referencing an attribute in the current theme
+ * style, not a resource entry). */
+ public static final int TYPE_ATTRIBUTE = 0x02;
+ /** The <var>string</var> field holds string data. In addition, if
+ * <var>data</var> is non-zero then it is the string block
+ * index of the string and <var>assetCookie</var> is the set of
+ * assets the string came from. */
+ public static final int TYPE_STRING = 0x03;
+ /** The <var>data</var> field holds an IEEE 754 floating point number. */
+ public static final int TYPE_FLOAT = 0x04;
+ /** The <var>data</var> field holds a complex number encoding a
+ * dimension value. */
+ public static final int TYPE_DIMENSION = 0x05;
+ /** The <var>data</var> field holds a complex number encoding a fraction
+ * of a container. */
+ public static final int TYPE_FRACTION = 0x06;
+
+ /** Identifies the start of plain integer values. Any type value
+ * from this to {@link #TYPE_LAST_INT} means the
+ * <var>data</var> field holds a generic integer value. */
+ public static final int TYPE_FIRST_INT = 0x10;
+
+ /** The <var>data</var> field holds a number that was
+ * originally specified in decimal. */
+ public static final int TYPE_INT_DEC = 0x10;
+ /** The <var>data</var> field holds a number that was
+ * originally specified in hexadecimal (0xn). */
+ public static final int TYPE_INT_HEX = 0x11;
+ /** The <var>data</var> field holds 0 or 1 that was originally
+ * specified as "false" or "true". */
+ public static final int TYPE_INT_BOOLEAN = 0x12;
+
+ /** Identifies the start of integer values that were specified as
+ * color constants (starting with '#'). */
+ public static final int TYPE_FIRST_COLOR_INT = 0x1c;
+
+ /** The <var>data</var> field holds a color that was originally
+ * specified as #aarrggbb. */
+ public static final int TYPE_INT_COLOR_ARGB8 = 0x1c;
+ /** The <var>data</var> field holds a color that was originally
+ * specified as #rrggbb. */
+ public static final int TYPE_INT_COLOR_RGB8 = 0x1d;
+ /** The <var>data</var> field holds a color that was originally
+ * specified as #argb. */
+ public static final int TYPE_INT_COLOR_ARGB4 = 0x1e;
+ /** The <var>data</var> field holds a color that was originally
+ * specified as #rgb. */
+ public static final int TYPE_INT_COLOR_RGB4 = 0x1f;
+
+ /** Identifies the end of integer values that were specified as color
+ * constants. */
+ public static final int TYPE_LAST_COLOR_INT = 0x1f;
+
+ /** Identifies the end of plain integer values. */
+ public static final int TYPE_LAST_INT = 0x1f;
+
+ /* ------------------------------------------------------------ */
+
+ /** Complex data: bit location of unit information. */
+ public static final int COMPLEX_UNIT_SHIFT = 0;
+ /** Complex data: mask to extract unit information (after shifting by
+ * {@link #COMPLEX_UNIT_SHIFT}). This gives us 16 possible types, as
+ * defined below. */
+ public static final int COMPLEX_UNIT_MASK = 0xf;
+
+ /** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
+ public static final int COMPLEX_UNIT_PX = 0;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent
+ * Pixels. */
+ public static final int COMPLEX_UNIT_DIP = 1;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */
+ public static final int COMPLEX_UNIT_SP = 2;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in points. */
+ public static final int COMPLEX_UNIT_PT = 3;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in inches. */
+ public static final int COMPLEX_UNIT_IN = 4;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */
+ public static final int COMPLEX_UNIT_MM = 5;
+
+ /** {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall
+ * size. */
+ public static final int COMPLEX_UNIT_FRACTION = 0;
+ /** {@link #TYPE_FRACTION} complex unit: A fraction of the parent size. */
+ public static final int COMPLEX_UNIT_FRACTION_PARENT = 1;
+
+ /** Complex data: where the radix information is, telling where the decimal
+ * place appears in the mantissa. */
+ public static final int COMPLEX_RADIX_SHIFT = 4;
+ /** Complex data: mask to extract radix information (after shifting by
+ * {@link #COMPLEX_RADIX_SHIFT}). This give us 4 possible fixed point
+ * representations as defined below. */
+ public static final int COMPLEX_RADIX_MASK = 0x3;
+
+ /** Complex data: the mantissa is an integral number -- i.e., 0xnnnnnn.0 */
+ public static final int COMPLEX_RADIX_23p0 = 0;
+ /** Complex data: the mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn */
+ public static final int COMPLEX_RADIX_16p7 = 1;
+ /** Complex data: the mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn */
+ public static final int COMPLEX_RADIX_8p15 = 2;
+ /** Complex data: the mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn */
+ public static final int COMPLEX_RADIX_0p23 = 3;
+
+ /** Complex data: bit location of mantissa information. */
+ public static final int COMPLEX_MANTISSA_SHIFT = 8;
+ /** Complex data: mask to extract mantissa information (after shifting by
+ * {@link #COMPLEX_MANTISSA_SHIFT}). This gives us 23 bits of precision;
+ * the top bit is the sign. */
+ public static final int COMPLEX_MANTISSA_MASK = 0xffffff;
+
+ /* ------------------------------------------------------------ */
+
+ /** The type held by this value, as defined by the constants here.
+ * This tells you how to interpret the other fields in the object. */
+ public int type;
+
+ /** If the value holds a string, this is it. */
+ public CharSequence string;
+
+ /** Basic data in the value, interpreted according to {@link #type} */
+ public int data;
+
+ /** Additional information about where the value came from; only
+ * set for strings. */
+ public int assetCookie;
+
+ /** If Value came from a resource, this holds the corresponding resource id. */
+ public int resourceId;
+
+ /** If Value came from a resource, these are the configurations for which
+ * its contents can change. */
+ public int changingConfigurations = -1;
+
+ /* ------------------------------------------------------------ */
+
+ /** Return the data for this value as a float. Only use for values
+ * whose type is {@link #TYPE_FLOAT}. */
+ public final float getFloat() {
+ return Float.intBitsToFloat(data);
+ }
+
+ private static final float MANTISSA_MULT =
+ 1.0f / (1<<TypedValue.COMPLEX_MANTISSA_SHIFT);
+ private static final float[] RADIX_MULTS = new float[] {
+ 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
+ 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
+ };
+
+ /**
+ * Retrieve the base value from a complex data integer. This uses the
+ * {@link #COMPLEX_MANTISSA_MASK} and {@link #COMPLEX_RADIX_MASK} fields of
+ * the data to compute a floating point representation of the number they
+ * describe. The units are ignored.
+ *
+ * @param complex A complex data value.
+ *
+ * @return A floating point value corresponding to the complex data.
+ */
+ public static float complexToFloat(int complex)
+ {
+ return (complex&(TypedValue.COMPLEX_MANTISSA_MASK
+ <<TypedValue.COMPLEX_MANTISSA_SHIFT))
+ * RADIX_MULTS[(complex>>TypedValue.COMPLEX_RADIX_SHIFT)
+ & TypedValue.COMPLEX_RADIX_MASK];
+ }
+
+ /**
+ * Converts a complex data value holding a dimension to its final floating
+ * point value. The given <var>data</var> must be structured as a
+ * {@link #TYPE_DIMENSION}.
+ *
+ * @param data A complex data value holding a unit, magnitude, and
+ * mantissa.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return The complex floating point value multiplied by the appropriate
+ * metrics depending on its unit.
+ */
+ public static float complexToDimension(int data, DisplayMetrics metrics)
+ {
+ return applyDimension(
+ (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
+ complexToFloat(data),
+ metrics);
+ }
+
+ /**
+ * Converts a complex data value holding a dimension to its final value
+ * as an integer pixel offset. This is the same as
+ * {@link #complexToDimension}, except the raw floating point value is
+ * truncated to an integer (pixel) value.
+ * The given <var>data</var> must be structured as a
+ * {@link #TYPE_DIMENSION}.
+ *
+ * @param data A complex data value holding a unit, magnitude, and
+ * mantissa.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return The number of pixels specified by the data and its desired
+ * multiplier and units.
+ */
+ public static int complexToDimensionPixelOffset(int data,
+ DisplayMetrics metrics)
+ {
+ return (int)applyDimension(
+ (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
+ complexToFloat(data),
+ metrics);
+ }
+
+ /**
+ * Converts a complex data value holding a dimension to its final value
+ * as an integer pixel size. This is the same as
+ * {@link #complexToDimension}, except the raw floating point value is
+ * converted to an integer (pixel) value for use as a size. A size
+ * conversion involves rounding the base value, and ensuring that a
+ * non-zero base value is at least one pixel in size.
+ * The given <var>data</var> must be structured as a
+ * {@link #TYPE_DIMENSION}.
+ *
+ * @param data A complex data value holding a unit, magnitude, and
+ * mantissa.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return The number of pixels specified by the data and its desired
+ * multiplier and units.
+ */
+ public static int complexToDimensionPixelSize(int data,
+ DisplayMetrics metrics)
+ {
+ final float value = complexToFloat(data);
+ final float f = applyDimension(
+ (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
+ value,
+ metrics);
+ final int res = (int)(f+0.5f);
+ if (res != 0) return res;
+ if (value == 0) return 0;
+ if (value > 0) return 1;
+ return -1;
+ }
+
+ public static float complexToDimensionNoisy(int data, DisplayMetrics metrics)
+ {
+ float res = complexToDimension(data, metrics);
+ System.out.println(
+ "Dimension (0x" + ((data>>TypedValue.COMPLEX_MANTISSA_SHIFT)
+ & TypedValue.COMPLEX_MANTISSA_MASK)
+ + "*" + (RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT)
+ & TypedValue.COMPLEX_RADIX_MASK] / MANTISSA_MULT)
+ + ")" + DIMENSION_UNIT_STRS[(data>>COMPLEX_UNIT_SHIFT)
+ & COMPLEX_UNIT_MASK]
+ + " = " + res);
+ return res;
+ }
+
+ /**
+ * Converts an unpacked complex data value holding a dimension to its final floating
+ * point value. The two parameters <var>unit</var> and <var>value</var>
+ * are as in {@link #TYPE_DIMENSION}.
+ *
+ * @param unit The unit to convert from.
+ * @param value The value to apply the unit to.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return The complex floating point value multiplied by the appropriate
+ * metrics depending on its unit.
+ */
+ public static float applyDimension(int unit, float value,
+ DisplayMetrics metrics)
+ {
+ switch (unit) {
+ case COMPLEX_UNIT_PX:
+ return value;
+ case COMPLEX_UNIT_DIP:
+ return value * metrics.density;
+ case COMPLEX_UNIT_SP:
+ return value * metrics.scaledDensity;
+ case COMPLEX_UNIT_PT:
+ return value * metrics.xdpi * (1.0f/72);
+ case COMPLEX_UNIT_IN:
+ return value * metrics.xdpi;
+ case COMPLEX_UNIT_MM:
+ return value * metrics.xdpi * (1.0f/25.4f);
+ }
+ return 0;
+ }
+
+ /**
+ * Return the data for this value as a dimension. Only use for values
+ * whose type is {@link #TYPE_DIMENSION}.
+ *
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return The complex floating point value multiplied by the appropriate
+ * metrics depending on its unit.
+ */
+ public float getDimension(DisplayMetrics metrics)
+ {
+ return complexToDimension(data, metrics);
+ }
+
+ /**
+ * Converts a complex data value holding a fraction to its final floating
+ * point value. The given <var>data</var> must be structured as a
+ * {@link #TYPE_FRACTION}.
+ *
+ * @param data A complex data value holding a unit, magnitude, and
+ * mantissa.
+ * @param base The base value of this fraction. In other words, a
+ * standard fraction is multiplied by this value.
+ * @param pbase The parent base value of this fraction. In other
+ * words, a parent fraction (nn%p) is multiplied by this
+ * value.
+ *
+ * @return The complex floating point value multiplied by the appropriate
+ * base value depending on its unit.
+ */
+ public static float complexToFraction(int data, float base, float pbase)
+ {
+ switch ((data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK) {
+ case COMPLEX_UNIT_FRACTION:
+ return complexToFloat(data) * base;
+ case COMPLEX_UNIT_FRACTION_PARENT:
+ return complexToFloat(data) * pbase;
+ }
+ return 0;
+ }
+
+ /**
+ * Return the data for this value as a fraction. Only use for values whose
+ * type is {@link #TYPE_FRACTION}.
+ *
+ * @param base The base value of this fraction. In other words, a
+ * standard fraction is multiplied by this value.
+ * @param pbase The parent base value of this fraction. In other
+ * words, a parent fraction (nn%p) is multiplied by this
+ * value.
+ *
+ * @return The complex floating point value multiplied by the appropriate
+ * base value depending on its unit.
+ */
+ public float getFraction(float base, float pbase)
+ {
+ return complexToFraction(data, base, pbase);
+ }
+
+ /**
+ * Regardless of the actual type of the value, try to convert it to a
+ * string value. For example, a color type will be converted to a
+ * string of the form #aarrggbb.
+ *
+ * @return CharSequence The coerced string value. If the value is
+ * null or the type is not known, null is returned.
+ */
+ public final CharSequence coerceToString()
+ {
+ int t = type;
+ if (t == TYPE_STRING) {
+ return string;
+ }
+ return coerceToString(t, data);
+ }
+
+ private static final String[] DIMENSION_UNIT_STRS = new String[] {
+ "px", "dip", "sp", "pt", "in", "mm"
+ };
+ private static final String[] FRACTION_UNIT_STRS = new String[] {
+ "%", "%p"
+ };
+
+ /**
+ * Perform type conversion as per {@link #coerceToString()} on an
+ * explicitly supplied type and data.
+ *
+ * @param type The data type identifier.
+ * @param data The data value.
+ *
+ * @return String The coerced string value. If the value is
+ * null or the type is not known, null is returned.
+ */
+ public static final String coerceToString(int type, int data)
+ {
+ switch (type) {
+ case TYPE_NULL:
+ return null;
+ case TYPE_REFERENCE:
+ return "@" + data;
+ case TYPE_ATTRIBUTE:
+ return "?" + data;
+ case TYPE_FLOAT:
+ return Float.toString(Float.intBitsToFloat(data));
+ case TYPE_DIMENSION:
+ return Float.toString(complexToFloat(data)) + DIMENSION_UNIT_STRS[
+ (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
+ case TYPE_FRACTION:
+ return Float.toString(complexToFloat(data)*100) + FRACTION_UNIT_STRS[
+ (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
+ case TYPE_INT_HEX:
+ return "0x" + Integer.toHexString(data);
+ case TYPE_INT_BOOLEAN:
+ return data != 0 ? "true" : "false";
+ }
+
+ if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) {
+ return "#" + Integer.toHexString(data);
+ } else if (type >= TYPE_FIRST_INT && type <= TYPE_LAST_INT) {
+ return Integer.toString(data);
+ }
+
+ return null;
+ }
+
+ public void setTo(TypedValue other)
+ {
+ type = other.type;
+ string = other.string;
+ data = other.data;
+ assetCookie = other.assetCookie;
+ resourceId = other.resourceId;
+ }
+
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("TypedValue{t=0x").append(Integer.toHexString(type));
+ sb.append("/d=0x").append(Integer.toHexString(data));
+ if (type == TYPE_STRING) {
+ sb.append(" \"").append(string != null ? string : "<null>").append("\"");
+ }
+ if (assetCookie != 0) {
+ sb.append(" a=").append(assetCookie);
+ }
+ if (resourceId != 0) {
+ sb.append(" r=0x").append(Integer.toHexString(resourceId));
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+};
+
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
new file mode 100644
index 0000000..a2b69a5
--- /dev/null
+++ b/core/java/android/util/Xml.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 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.util;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.harmony.xml.ExpatPullParser;
+import org.apache.harmony.xml.ExpatReader;
+
+/**
+ * XML utility methods.
+ */
+public class Xml {
+
+ /**
+ * {@link org.xmlpull.v1.XmlPullParser} "relaxed" feature name.
+ *
+ * @see <a href="http://xmlpull.org/v1/doc/features.html#relaxed">
+ * specification</a>
+ */
+ public static String FEATURE_RELAXED = ExpatPullParser.FEATURE_RELAXED;
+
+ /**
+ * Parses the given xml string and fires events on the given SAX handler.
+ */
+ public static void parse(String xml, ContentHandler contentHandler)
+ throws SAXException {
+ try {
+ XMLReader reader = new ExpatReader();
+ reader.setContentHandler(contentHandler);
+ reader.parse(new InputSource(new StringReader(xml)));
+ }
+ catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Parses xml from the given reader and fires events on the given SAX
+ * handler.
+ */
+ public static void parse(Reader in, ContentHandler contentHandler)
+ throws IOException, SAXException {
+ XMLReader reader = new ExpatReader();
+ reader.setContentHandler(contentHandler);
+ reader.parse(new InputSource(in));
+ }
+
+ /**
+ * Parses xml from the given input stream and fires events on the given SAX
+ * handler.
+ */
+ public static void parse(InputStream in, Encoding encoding,
+ ContentHandler contentHandler) throws IOException, SAXException {
+ try {
+ XMLReader reader = new ExpatReader();
+ reader.setContentHandler(contentHandler);
+ InputSource source = new InputSource(in);
+ source.setEncoding(encoding.expatName);
+ reader.parse(source);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Creates a new pull parser with namespace support.
+ *
+ * <p><b>Note:</b> This is actually slower than the SAX parser, and it's not
+ * fully implemented. If you need a fast, mostly implemented pull parser,
+ * use this. If you need a complete implementation, use KXML.
+ */
+ public static XmlPullParser newPullParser() {
+ ExpatPullParser parser = new ExpatPullParser();
+ parser.setNamespaceProcessingEnabled(true);
+ return parser;
+ }
+
+ /**
+ * Creates a new xml serializer.
+ */
+ public static XmlSerializer newSerializer() {
+ try {
+ return XmlSerializerFactory.instance.newSerializer();
+ } catch (XmlPullParserException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /** Factory for xml serializers. Initialized on demand. */
+ static class XmlSerializerFactory {
+ static final String TYPE
+ = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
+ static final XmlPullParserFactory instance;
+ static {
+ try {
+ instance = XmlPullParserFactory.newInstance(TYPE, null);
+ } catch (XmlPullParserException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ /**
+ * Supported character encodings.
+ */
+ public enum Encoding {
+
+ US_ASCII("US-ASCII"),
+ UTF_8("UTF-8"),
+ UTF_16("UTF-16"),
+ ISO_8859_1("ISO-8859-1");
+
+ final String expatName;
+
+ Encoding(String expatName) {
+ this.expatName = expatName;
+ }
+ }
+
+ /**
+ * Finds an encoding by name. Returns UTF-8 if you pass {@code null}.
+ */
+ public static Encoding findEncodingByName(String encodingName)
+ throws UnsupportedEncodingException {
+ if (encodingName == null) {
+ return Encoding.UTF_8;
+ }
+
+ for (Encoding encoding : Encoding.values()) {
+ if (encoding.expatName.equalsIgnoreCase(encodingName))
+ return encoding;
+ }
+ throw new UnsupportedEncodingException(encodingName);
+ }
+
+ /**
+ * Return an AttributeSet interface for use with the given XmlPullParser.
+ * If the given parser itself implements AttributeSet, that implementation
+ * is simply returned. Otherwise a wrapper class is
+ * instantiated on top of the XmlPullParser, as a proxy for retrieving its
+ * attributes, and returned to you.
+ *
+ * @param parser The existing parser for which you would like an
+ * AttributeSet.
+ *
+ * @return An AttributeSet you can use to retrieve the
+ * attribute values at each of the tags as the parser moves
+ * through its XML document.
+ *
+ * @see AttributeSet
+ */
+ public static AttributeSet asAttributeSet(XmlPullParser parser) {
+ return (parser instanceof AttributeSet)
+ ? (AttributeSet) parser
+ : new XmlPullAttributes(parser);
+ }
+}
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
new file mode 100644
index 0000000..12d6dd9
--- /dev/null
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -0,0 +1,146 @@
+/*
+ * 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.util;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import android.util.AttributeSet;
+import com.android.internal.util.XmlUtils;
+
+/**
+ * Provides an implementation of AttributeSet on top of an XmlPullParser.
+ */
+class XmlPullAttributes implements AttributeSet {
+ public XmlPullAttributes(XmlPullParser parser) {
+ mParser = parser;
+ }
+
+ public int getAttributeCount() {
+ return mParser.getAttributeCount();
+ }
+
+ public String getAttributeName(int index) {
+ return mParser.getAttributeName(index);
+ }
+
+ public String getAttributeValue(int index) {
+ return mParser.getAttributeValue(index);
+ }
+
+ public String getAttributeValue(String namespace, String name) {
+ return mParser.getAttributeValue(namespace, name);
+ }
+
+ public String getPositionDescription() {
+ return mParser.getPositionDescription();
+ }
+
+ public int getAttributeNameResource(int index) {
+ return 0;
+ }
+
+ public int getAttributeListValue(String namespace, String attribute,
+ String[] options, int defaultValue) {
+ return XmlUtils.convertValueToList(
+ getAttributeValue(namespace, attribute), options, defaultValue);
+ }
+
+ public boolean getAttributeBooleanValue(String namespace, String attribute,
+ boolean defaultValue) {
+ return XmlUtils.convertValueToBoolean(
+ getAttributeValue(namespace, attribute), defaultValue);
+ }
+
+ public int getAttributeResourceValue(String namespace, String attribute,
+ int defaultValue) {
+ return XmlUtils.convertValueToInt(
+ getAttributeValue(namespace, attribute), defaultValue);
+ }
+
+ public int getAttributeIntValue(String namespace, String attribute,
+ int defaultValue) {
+ return XmlUtils.convertValueToInt(
+ getAttributeValue(namespace, attribute), defaultValue);
+ }
+
+ public int getAttributeUnsignedIntValue(String namespace, String attribute,
+ int defaultValue) {
+ return XmlUtils.convertValueToUnsignedInt(
+ getAttributeValue(namespace, attribute), defaultValue);
+ }
+
+ public float getAttributeFloatValue(String namespace, String attribute,
+ float defaultValue) {
+ String s = getAttributeValue(namespace, attribute);
+ if (s != null) {
+ return Float.parseFloat(s);
+ }
+ return defaultValue;
+ }
+
+ public int getAttributeListValue(int index,
+ String[] options, int defaultValue) {
+ return XmlUtils.convertValueToList(
+ getAttributeValue(index), options, defaultValue);
+ }
+
+ public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
+ return XmlUtils.convertValueToBoolean(
+ getAttributeValue(index), defaultValue);
+ }
+
+ public int getAttributeResourceValue(int index, int defaultValue) {
+ return XmlUtils.convertValueToInt(
+ getAttributeValue(index), defaultValue);
+ }
+
+ public int getAttributeIntValue(int index, int defaultValue) {
+ return XmlUtils.convertValueToInt(
+ getAttributeValue(index), defaultValue);
+ }
+
+ public int getAttributeUnsignedIntValue(int index, int defaultValue) {
+ return XmlUtils.convertValueToUnsignedInt(
+ getAttributeValue(index), defaultValue);
+ }
+
+ public float getAttributeFloatValue(int index, float defaultValue) {
+ String s = getAttributeValue(index);
+ if (s != null) {
+ return Float.parseFloat(s);
+ }
+ return defaultValue;
+ }
+
+ public String getIdAttribute() {
+ return getAttributeValue(null, "id");
+ }
+
+ public String getClassAttribute() {
+ return getAttributeValue(null, "class");
+ }
+
+ public int getIdAttributeResourceValue(int defaultValue) {
+ return getAttributeResourceValue(null, "id", defaultValue);
+ }
+
+ public int getStyleAttribute() {
+ return getAttributeResourceValue(null, "style", 0);
+ }
+
+ private XmlPullParser mParser;
+}
diff --git a/core/java/android/util/package.html b/core/java/android/util/package.html
new file mode 100644
index 0000000..d918d69
--- /dev/null
+++ b/core/java/android/util/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Provides common utility methods such as date/time manipulation, base64 encoders
+and decoders, string and number conversion methods, and XML utilities.
+</BODY>
+</HTML> \ No newline at end of file