refactor source tree organization, switch to meson

This commit is contained in:
Mis012
2022-10-02 23:06:56 +02:00
parent 2f785e2a59
commit 449090143e
296 changed files with 171615 additions and 69 deletions

View File

@@ -0,0 +1,38 @@
/*
* 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(String name, Throwable cause) {
super(name, cause);
}
public AndroidException(Exception cause) {
super(cause);
}
};

View File

@@ -0,0 +1,38 @@
/*
* 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(String name, Throwable cause) {
super(name, cause);
}
public AndroidRuntimeException(Exception cause) {
super(cause);
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
/*
* 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;
/**
* 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.asAttributeSet()}. 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(myResource);
* AttributeSet attributes = Xml.asAttributeSet(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.
*
* @see XmlPullParser
*/
public interface AttributeSet {
/**
* Returns the number of attributes available in the set.
*
* <p>See also {@link XmlPullParser#getAttributeCount XmlPullParser.getAttributeCount()},
* which this method corresponds to when parsing a compiled XML file.</p>
*
* @return A positive integer, or 0 if the set is empty.
*/
public int getAttributeCount();
/**
* Returns the namespace of the specified attribute.
*
* <p>See also {@link XmlPullParser#getAttributeNamespace XmlPullParser.getAttributeNamespace()},
* which this method corresponds to when parsing a compiled XML file.</p>
*
* @param index Index of the desired attribute, 0...count-1.
*
* @return A String containing the namespace of the attribute, or null if th
* attribute cannot be found.
*/
/* default */ String getAttributeNamespace (int index);/* {
// This is a new method since the first interface definition, so add stub impl.
return null;
}*/
/**
* Returns the name of the specified attribute.
*
* <p>See also {@link XmlPullParser#getAttributeName XmlPullParser.getAttributeName()},
* which this method corresponds to when parsing a compiled XML file.</p>
*
* @param index Index of the desired attribute, 0...count-1.
*
* @return A String containing the name of the attribute, or null if the
* attribute cannot be found.
*/
public String getAttributeName(int index);
/**
* Returns the value of the specified attribute as a string representation.
*
* @param index Index of the desired attribute, 0...count-1.
*
* @return A String containing the value of the attribute, or null if the
* attribute cannot be found.
*/
public String getAttributeValue(int index);
/**
* Returns the value of the specified attribute as a string representation.
* The lookup is performed using the attribute name.
*
* @param namespace The namespace of the attribute to get the value from.
* @param name The name of the attribute to get the value from.
*
* @return A String containing the value of the attribute, or null if the
* attribute cannot be found.
*/
public String getAttributeValue(String namespace, String name);
/**
* Returns a description of the current position of the attribute set.
* For instance, if the attribute set is loaded from an XML document,
* the position description could indicate the current line number.
*
* @return A string representation of the current position in the set,
* may be null.
*/
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 namespace Namespace of attribute to retrieve.
* @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 namespace Namespace of attribute to retrieve.
* @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 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 namespace Namespace of attribute to retrieve.
* @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 namespace Namespace of attribute to retrieve.
* @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 namespace Namespace of attribute to retrieve.
* @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 namespace Namespace of attribute to retrieve.
* @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 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();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2011 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.IOException;
/**
* This exception is thrown by {@link Base64InputStream} or {@link Base64OutputStream}
* when an error is detected in the data being decoded. This allows problems with the base64 data
* to be disambiguated from errors in the underlying streams (e.g. actual connection errors.)
*/
public class Base64DataException extends IOException {
public Base64DataException(String detailMessage) {
super(detailMessage);
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* An InputStream that does Base64 decoding on the data read through
* it.
*/
public class Base64InputStream extends FilterInputStream {
private final Base64.Coder coder;
private static byte[] EMPTY = new byte[0];
private static final int BUFFER_SIZE = 2048;
private boolean eof;
private byte[] inputBuffer;
private int outputStart;
private int outputEnd;
/**
* An InputStream that performs Base64 decoding on the data read
* from the wrapped stream.
*
* @param in the InputStream to read the source data from
* @param flags bit flags for controlling the decoder; see the
* constants in {@link Base64}
*/
public Base64InputStream(InputStream in, int flags) {
this(in, flags, false);
}
/**
* Performs Base64 encoding or decoding on the data read from the
* wrapped InputStream.
*
* @param in the InputStream to read the source data from
* @param flags bit flags for controlling the decoder; see the
* constants in {@link Base64}
* @param encode true to encode, false to decode
*
* @hide
*/
public Base64InputStream(InputStream in, int flags, boolean encode) {
super(in);
eof = false;
inputBuffer = new byte[BUFFER_SIZE];
if (encode) {
coder = new Base64.Encoder(flags, null);
} else {
coder = new Base64.Decoder(flags, null);
}
coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)];
outputStart = 0;
outputEnd = 0;
}
public boolean markSupported() {
return false;
}
public void mark(int readlimit) {
throw new UnsupportedOperationException();
}
public void reset() {
throw new UnsupportedOperationException();
}
public void close() throws IOException {
in.close();
inputBuffer = null;
}
public int available() {
return outputEnd - outputStart;
}
public long skip(long n) throws IOException {
if (outputStart >= outputEnd) {
refill();
}
if (outputStart >= outputEnd) {
return 0;
}
long bytes = Math.min(n, outputEnd-outputStart);
outputStart += bytes;
return bytes;
}
public int read() throws IOException {
if (outputStart >= outputEnd) {
refill();
}
if (outputStart >= outputEnd) {
return -1;
} else {
return coder.output[outputStart++] & 0xff;
}
}
public int read(byte[] b, int off, int len) throws IOException {
if (outputStart >= outputEnd) {
refill();
}
if (outputStart >= outputEnd) {
return -1;
}
int bytes = Math.min(len, outputEnd-outputStart);
System.arraycopy(coder.output, outputStart, b, off, bytes);
outputStart += bytes;
return bytes;
}
/**
* Read data from the input stream into inputBuffer, then
* decode/encode it into the empty coder.output, and reset the
* outputStart and outputEnd pointers.
*/
private void refill() throws IOException {
if (eof) return;
int bytesRead = in.read(inputBuffer);
boolean success;
if (bytesRead == -1) {
eof = true;
success = coder.process(EMPTY, 0, 0, true);
} else {
success = coder.process(inputBuffer, 0, bytesRead, false);
}
if (!success) {
throw new Base64DataException("bad base-64");
}
outputEnd = coder.op;
outputStart = 0;
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* An OutputStream that does Base64 encoding on the data written to
* it, writing the resulting data to another OutputStream.
*/
public class Base64OutputStream extends FilterOutputStream {
private final Base64.Coder coder;
private final int flags;
private byte[] buffer = null;
private int bpos = 0;
private static byte[] EMPTY = new byte[0];
/**
* Performs Base64 encoding on the data written to the stream,
* writing the encoded data to another OutputStream.
*
* @param out the OutputStream to write the encoded data to
* @param flags bit flags for controlling the encoder; see the
* constants in {@link Base64}
*/
public Base64OutputStream(OutputStream out, int flags) {
this(out, flags, true);
}
/**
* Performs Base64 encoding or decoding on the data written to the
* stream, writing the encoded/decoded data to another
* OutputStream.
*
* @param out the OutputStream to write the encoded data to
* @param flags bit flags for controlling the encoder; see the
* constants in {@link Base64}
* @param encode true to encode, false to decode
*
* @hide
*/
public Base64OutputStream(OutputStream out, int flags, boolean encode) {
super(out);
this.flags = flags;
if (encode) {
coder = new Base64.Encoder(flags, null);
} else {
coder = new Base64.Decoder(flags, null);
}
}
public void write(int b) throws IOException {
// To avoid invoking the encoder/decoder routines for single
// bytes, we buffer up calls to write(int) in an internal
// byte array to transform them into writes of decently-sized
// arrays.
if (buffer == null) {
buffer = new byte[1024];
}
if (bpos >= buffer.length) {
// internal buffer full; write it out.
internalWrite(buffer, 0, bpos, false);
bpos = 0;
}
buffer[bpos++] = (byte) b;
}
/**
* Flush any buffered data from calls to write(int). Needed
* before doing a write(byte[], int, int) or a close().
*/
private void flushBuffer() throws IOException {
if (bpos > 0) {
internalWrite(buffer, 0, bpos, false);
bpos = 0;
}
}
public void write(byte[] b, int off, int len) throws IOException {
if (len <= 0) return;
flushBuffer();
internalWrite(b, off, len, false);
}
public void close() throws IOException {
IOException thrown = null;
try {
flushBuffer();
internalWrite(EMPTY, 0, 0, true);
} catch (IOException e) {
thrown = e;
}
try {
if ((flags & Base64.NO_CLOSE) == 0) {
out.close();
} else {
out.flush();
}
} catch (IOException e) {
if (thrown != null) {
thrown = e;
}
}
if (thrown != null) {
throw thrown;
}
}
/**
* Write the given bytes to the encoder/decoder.
*
* @param finish true if this is the last batch of input, to cause
* encoder/decoder state to be finalized.
*/
private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
coder.output = embiggen(coder.output, coder.maxOutputSize(len));
if (!coder.process(b, off, len, finish)) {
throw new Base64DataException("bad base-64");
}
out.write(coder.output, 0, coder.op);
}
/**
* If b.length is at least len, return b. Otherwise return a new
* byte array of length len.
*/
private byte[] embiggen(byte[] b, int len) {
if (b == null || b.length < len) {
return new byte[len];
} else {
return b;
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2013 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;
class ContainerHelpers {
static final boolean[] EMPTY_BOOLEANS = new boolean[0];
static final int[] EMPTY_INTS = new int[0];
static final long[] EMPTY_LONGS = new long[0];
static final Object[] EMPTY_OBJECTS = new Object[0];
// This is Arrays.binarySearch(), but doesn't do any argument validation.
static int binarySearch(int[] array, int size, int value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int midVal = array[mid];
if (midVal < value) {
lo = mid + 1;
} else if (midVal > value) {
hi = mid - 1;
} else {
return mid; // value found
}
}
return ~lo; // value not present
}
static int binarySearch(long[] array, int size, long value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final long midVal = array[mid];
if (midVal < value) {
lo = mid + 1;
} else if (midVal > value) {
hi = mid - 1;
} else {
return mid; // value found
}
}
return ~lo; // value not present
}
}

View File

@@ -0,0 +1,127 @@
package android.util;
import org.xmlpull.v1.XmlPullParser;
import org.kxml2.io.KXmlParser;
import com.android.internal.util.XmlUtils;
import android.util.AttributeSet;
public class DecompiledXmlResourceParser extends KXmlParser implements AttributeSet, AutoCloseable {
public int getAttributeCount() {
return this.getAttributeCount();
}
public String getAttributeNamespace (int index) {
return this.getAttributeNamespace(index);
}
public String getAttributeName(int index) {
return this.getAttributeName(index);
}
public String getAttributeValue(int index) {
return this.getAttributeValue(index);
}
public String getAttributeValue(String namespace, String name) {
return this.getAttributeValue(namespace, name);
}
public String getPositionDescription() {
return this.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);
}
}

View File

@@ -0,0 +1,299 @@
/*
* 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.
* <p>To access the DisplayMetrics members, initialize an object like this:</p>
* <pre> DisplayMetrics metrics = new DisplayMetrics();
* getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
*/
public class DisplayMetrics {
/**
* Standard quantized DPI for low-density screens.
*/
public static final int DENSITY_LOW = 120;
/**
* Standard quantized DPI for medium-density screens.
*/
public static final int DENSITY_MEDIUM = 160;
/**
* This is a secondary density, added for some common screen configurations.
* It is recommended that applications not generally target this as a first
* class density -- that is, don't supply specific graphics for this
* density, instead allow the platform to scale from other densities
* (typically {@link #DENSITY_HIGH}) as
* appropriate. In most cases (such as using bitmaps in
* {@link android.graphics.drawable.Drawable}) the platform
* can perform this scaling at load time, so the only cost is some slight
* startup runtime overhead.
*
* <p>This density was original introduced to correspond with a
* 720p TV screen: the density for 1080p televisions is
* {@link #DENSITY_XHIGH}, and the value here provides the same UI
* size for a TV running at 720p. It has also found use in 7" tablets,
* when these devices have 1280x720 displays.
*/
public static final int DENSITY_TV = 213;
/**
* Standard quantized DPI for high-density screens.
*/
public static final int DENSITY_HIGH = 240;
/**
* Standard quantized DPI for extra-high-density screens.
*/
public static final int DENSITY_XHIGH = 320;
/**
* Intermediate density for screens that sit somewhere between
* {@link #DENSITY_XHIGH} (320dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
* This is not a density that applications should target, instead relying
* on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
*/
public static final int DENSITY_400 = 400;
/**
* Standard quantized DPI for extra-extra-high-density screens. Applications
* should not generally worry about this density; relying on XHIGH graphics
* being scaled up to it should be sufficient for almost all cases.
*/
public static final int DENSITY_XXHIGH = 480;
/**
* Standard quantized DPI for extra-extra-extra-high-density screens. Applications
* should not generally worry about this density; relying on XHIGH graphics
* being scaled up to it should be sufficient for almost all cases. A typical
* use of this density would be 4K television screens -- 3840x2160, which
* is 2x a traditional HD 1920x1080 screen which runs at DENSITY_XHIGH.
*/
public static final int DENSITY_XXXHIGH = 640;
/**
* The reference density used throughout the system.
*/
public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
/**
* Scaling factor to convert a density in DPI units to the density scale.
* @hide
*/
public static final float DENSITY_DEFAULT_SCALE = 1.0f / DENSITY_DEFAULT;
/**
* The device's density.
* @hide because eventually this should be able to change while
* running, so shouldn't be a constant.
* @deprecated There is no longer a static density; you can find the
* density for a display in {@link #densityDpi}.
*/
@Deprecated
public static int DENSITY_DEVICE = getDeviceDensity();
/**
* 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 120 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).
*
* @see #DENSITY_DEFAULT
*/
public float density;
/**
* The screen density expressed as dots-per-inch. May be either
* {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
*/
public int densityDpi;
/**
* 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;
/**
* The reported display width prior to any compatibility mode scaling
* being applied.
* @hide
*/
public int noncompatWidthPixels;
/**
* The reported display height prior to any compatibility mode scaling
* being applied.
* @hide
*/
public int noncompatHeightPixels;
/**
* The reported display density prior to any compatibility mode scaling
* being applied.
* @hide
*/
public float noncompatDensity;
/**
* The reported display density prior to any compatibility mode scaling
* being applied.
* @hide
*/
public int noncompatDensityDpi;
/**
* The reported scaled density prior to any compatibility mode scaling
* being applied.
* @hide
*/
public float noncompatScaledDensity;
/**
* The reported display xdpi prior to any compatibility mode scaling
* being applied.
* @hide
*/
public float noncompatXdpi;
/**
* The reported display ydpi prior to any compatibility mode scaling
* being applied.
* @hide
*/
public float noncompatYdpi;
public DisplayMetrics() {
setToDefaults();
}
public void setTo(DisplayMetrics o) {
widthPixels = o.widthPixels;
heightPixels = o.heightPixels;
density = o.density;
densityDpi = o.densityDpi;
scaledDensity = o.scaledDensity;
xdpi = o.xdpi;
ydpi = o.ydpi;
noncompatWidthPixels = o.noncompatWidthPixels;
noncompatHeightPixels = o.noncompatHeightPixels;
noncompatDensity = o.noncompatDensity;
noncompatDensityDpi = o.noncompatDensityDpi;
noncompatScaledDensity = o.noncompatScaledDensity;
noncompatXdpi = o.noncompatXdpi;
noncompatYdpi = o.noncompatYdpi;
}
public void setToDefaults() {
widthPixels = 0;
heightPixels = 0;
density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
densityDpi = DENSITY_DEVICE;
scaledDensity = density;
xdpi = DENSITY_DEVICE;
ydpi = DENSITY_DEVICE;
noncompatWidthPixels = widthPixels;
noncompatHeightPixels = heightPixels;
noncompatDensity = density;
noncompatDensityDpi = densityDpi;
noncompatScaledDensity = scaledDensity;
noncompatXdpi = xdpi;
noncompatYdpi = ydpi;
}
@Override
public boolean equals(Object o) {
return o instanceof DisplayMetrics && equals((DisplayMetrics)o);
}
/**
* Returns true if these display metrics equal the other display metrics.
*
* @param other The display metrics with which to compare.
* @return True if the display metrics are equal.
*/
public boolean equals(DisplayMetrics other) {
return equalsPhysical(other)
&& scaledDensity == other.scaledDensity
&& noncompatScaledDensity == other.noncompatScaledDensity;
}
/**
* Returns true if the physical aspects of the two display metrics
* are equal. This ignores the scaled density, which is a logical
* attribute based on the current desired font size.
*
* @param other The display metrics with which to compare.
* @return True if the display metrics are equal.
* @hide
*/
public boolean equalsPhysical(DisplayMetrics other) {
return other != null
&& widthPixels == other.widthPixels
&& heightPixels == other.heightPixels
&& density == other.density
&& densityDpi == other.densityDpi
&& xdpi == other.xdpi
&& ydpi == other.ydpi
&& noncompatWidthPixels == other.noncompatWidthPixels
&& noncompatHeightPixels == other.noncompatHeightPixels
&& noncompatDensity == other.noncompatDensity
&& noncompatDensityDpi == other.noncompatDensityDpi
&& noncompatXdpi == other.noncompatXdpi
&& noncompatYdpi == other.noncompatYdpi;
}
@Override
public int hashCode() {
return widthPixels * heightPixels * densityDpi;
}
@Override
public String toString() {
return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
}
private static int getDeviceDensity() {
// qemu.sf.lcd_density can be used to override ro.sf.lcd_density
// when running in the emulator, allowing for dynamic configurations.
// The reason for this is that ro.sf.lcd_density is write-once and is
// set by the init process when it parses build.prop before anything else.
return DENSITY_DEFAULT;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2013 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 class for defining layout directions. A layout direction can be left-to-right (LTR)
* or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default
* language script of a locale.
*/
public final class LayoutDirection {
// No instantiation
private LayoutDirection() {}
/**
* Horizontal layout direction is from Left to Right.
*/
public static final int LTR = 0;
/**
* Horizontal layout direction is from Right to Left.
*/
public static final int RTL = 1;
/**
* Horizontal layout direction is inherited.
*/
public static final int INHERIT = 2;
/**
* Horizontal layout direction is deduced from the default language script for the locale.
*/
public static final int LOCALE = 3;
}

View File

@@ -0,0 +1,359 @@
/*
* 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;
import java.io.StringWriter;
import java.net.UnknownHostException;
/**
* 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;
/**
* Exception class used to capture a stack trace in {@link #wtf}.
*/
private static class TerribleFailure extends Exception {
TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
}
/**
* Interface to handle terrible failures from {@link #wtf}.
*
* @hide
*/
public interface TerribleFailureHandler {
void onTerribleFailure(String tag, TerribleFailure what);
}
private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
public void onTerribleFailure(String tag, TerribleFailure what) {
// TODO
}
};
private Log() {
}
/**
* Send a {@link #VERBOSE} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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_native(LOG_ID_MAIN, 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. SUPPRESS 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 identifies
* 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_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
}
/**
* Send an {@link #ERROR} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* 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_native(LOG_ID_MAIN, 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 identifies
* 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) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
}
/**
* What a Terrible Failure: Report a condition that should never happen.
* The error will always be logged at level ASSERT with the call stack.
* Depending on system configuration, a report may be added to the
* {@link android.os.DropBoxManager} and/or the process may be terminated
* immediately with an error dialog.
* @param tag Used to identify the source of a log message.
* @param msg The message you would like logged.
*/
public static int wtf(String tag, String msg) {
return wtf(LOG_ID_MAIN, tag, msg, null, false);
}
/**
* Like {@link #wtf(String, String)}, but also writes to the log the full
* call stack.
* @hide
*/
public static int wtfStack(String tag, String msg) {
return wtf(LOG_ID_MAIN, tag, msg, null, true);
}
/**
* What a Terrible Failure: Report an exception that should never happen.
* Similar to {@link #wtf(String, String)}, with an exception to log.
* @param tag Used to identify the source of a log message.
* @param tr An exception to log.
*/
public static int wtf(String tag, Throwable tr) {
return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false);
}
/**
* What a Terrible Failure: Report an exception that should never happen.
* Similar to {@link #wtf(String, Throwable)}, with a message as well.
* @param tag Used to identify the source of a log message.
* @param msg The message you would like logged.
* @param tr An exception to log. May be null.
*/
public static int wtf(String tag, String msg, Throwable tr) {
return wtf(LOG_ID_MAIN, tag, msg, tr, false);
}
static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack) {
TerribleFailure what = new TerribleFailure(msg, tr);
int bytes = println_native(logId, ASSERT, tag, msg + '\n'
+ getStackTraceString(localStack ? what : tr));
sWtfHandler.onTerribleFailure(tag, what);
return bytes;
}
/**
* Sets the terrible failure handler, for testing.
*
* @return the old handler
*
* @hide
*/
public static TerribleFailureHandler setWtfHandler(TerribleFailureHandler handler) {
if (handler == null) {
throw new NullPointerException("handler == null");
}
TerribleFailureHandler oldHandler = sWtfHandler;
sWtfHandler = handler;
return oldHandler;
}
/**
* 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 "";
}
// This is to reduce the amount of log spew that apps do in the non-error
// condition of the network being unavailable.
Throwable t = tr;
while (t != null) {
if (t instanceof UnknownHostException) {
return "";
}
t = t.getCause();
}
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, false);
tr.printStackTrace(pw);
pw.flush();
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 identifies
* 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 int println(int priority, String tag, String msg) {
return println_native(LOG_ID_MAIN, priority, tag, msg);
}
/** @hide */ public static final int LOG_ID_MAIN = 0;
/** @hide */ public static final int LOG_ID_RADIO = 1;
/** @hide */ public static final int LOG_ID_EVENTS = 2;
/** @hide */ public static final int LOG_ID_SYSTEM = 3;
/** @hide */ public static /*native*/ int println_native(int bufID,
int priority, String tag, String msg) {
String out = String.format("`¯´[%d][%d] [%s] : %s", bufID, priority, tag, msg);
System.out.println(out);
return out.getBytes().length;
}
}

View File

@@ -0,0 +1,408 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
import com.android.internal.util.ArrayUtils;
/**
* SparseArray mapping longs to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more memory efficient
* than using a HashMap to map Longs to Objects, both because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.
*
* <p>Note that this container keeps its mappings in an array data structure,
* using a binary search to find keys. The implementation is not intended to be appropriate for
* data structures
* that may contain large numbers of items. It is generally slower than a traditional
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
*
* <p>To help with performance, the container includes an optimization when removing
* keys: instead of compacting its array immediately, it leaves the removed entry marked
* as deleted. The entry can then be re-used for the same key, or compacted later in
* a single garbage collection step of all removed entries. This garbage collection will
* need to be performed at any time the array needs to be grown or the the map size or
* entry values are retrieved.</p>
*
* <p>It is possible to iterate over the items in this container using
* {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
* <code>keyAt(int)</code> with ascending values of the index will return the
* keys in ascending order, or the values corresponding to the keys in ascending
* order in the case of <code>valueAt(int)<code>.</p>
*/
public class LongSparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
private long[] mKeys;
private Object[] mValues;
private int mSize;
/**
* Creates a new LongSparseArray containing no mappings.
*/
public LongSparseArray() {
this(10);
}
/**
* Creates a new LongSparseArray containing no mappings that will not
* require any additional memory allocation to store the specified
* number of mappings. If you supply an initial capacity of 0, the
* sparse array will be initialized with a light-weight representation
* not requiring any additional array allocations.
*/
public LongSparseArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = ContainerHelpers.EMPTY_LONGS;
mValues = ContainerHelpers.EMPTY_OBJECTS;
} else {
initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
mKeys = new long[initialCapacity];
mValues = new Object[initialCapacity];
}
mSize = 0;
}
@Override
@SuppressWarnings("unchecked")
public LongSparseArray<E> clone() {
LongSparseArray<E> clone = null;
try {
clone = (LongSparseArray<E>) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
/**
* Gets the Object mapped from the specified key, or <code>null</code>
* if no such mapping has been made.
*/
public E get(long key) {
return get(key, null);
}
/**
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
@SuppressWarnings("unchecked")
public E get(long key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, 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(long key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
mGarbage = true;
}
}
}
/**
* Alias for {@link #delete(long)}.
*/
public void remove(long key) {
delete(key);
}
/**
* Removes the mapping at the specified index.
*/
public void removeAt(int index) {
if (mValues[index] != DELETED) {
mValues[index] = DELETED;
mGarbage = true;
}
}
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
int n = mSize;
int o = 0;
long[] 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;
values[i] = null;
}
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(long key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, 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 = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
if (mSize >= mKeys.length) {
int n = ArrayUtils.idealLongArraySize(mSize + 1);
long[] nkeys = new long[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 LongSparseArray
* 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
* LongSparseArray stores.
*
* <p>The keys corresponding to indices in ascending order are guaranteed to
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
*/
public long 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
* LongSparseArray stores.
*
* <p>The values corresponding to indices in ascending order are guaranteed
* to be associated with keys in ascending order, e.g.,
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
*/
@SuppressWarnings("unchecked")
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
* LongSparseArray 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(long key) {
if (mGarbage) {
gc();
}
return ContainerHelpers.binarySearch(mKeys, 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 LongSparseArray.
*/
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(long 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.idealLongArraySize(pos + 1);
long[] nkeys = new long[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;
}
/**
* {@inheritDoc}
*
* <p>This implementation composes a string by iterating over its mappings. If
* this map contains itself as a value, the string "(this Map)"
* will appear in its place.
*/
@Override
public String toString() {
if (size() <= 0) {
return "{}";
}
StringBuilder buffer = new StringBuilder(mSize * 28);
buffer.append('{');
for (int i=0; i<mSize; i++) {
if (i > 0) {
buffer.append(", ");
}
long key = keyAt(i);
buffer.append(key);
buffer.append('=');
Object value = valueAt(i);
if (value != this) {
buffer.append(value);
} else {
buffer.append("(this Map)");
}
}
buffer.append('}');
return buffer.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* PrefixPrinter is a Printer which prefixes all lines with a given
* prefix.
*
* @hide
*/
public class PrefixPrinter implements Printer {
private final Printer mPrinter;
private final String mPrefix;
/**
* Creates a new PrefixPrinter.
*
* <p>If prefix is null or empty, the provided printer is returned, rather
* than making a prefixing printer.
*/
public static Printer create(Printer printer, String prefix) {
if (prefix == null || prefix.equals("")) {
return printer;
}
return new PrefixPrinter(printer, prefix);
}
private PrefixPrinter(Printer printer, String prefix) {
mPrinter = printer;
mPrefix = prefix;
}
public void println(String str) {
mPrinter.println(mPrefix + str);
}
}

View File

@@ -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);
}

View File

@@ -0,0 +1,99 @@
/*
* 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;
import java.io.StringWriter;
/**
* @hide
*/
public final class Slog {
private Slog() {
}
public static int v(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
}
public static int v(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
public static int d(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
}
public static int d(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
public static int i(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
}
public static int i(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
public static int w(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
}
public static int w(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
public static int w(String tag, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr));
}
public static int e(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
}
public static int e(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
public static int wtf(String tag, String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false);
}
public static int wtfStack(String tag, String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true);
}
public static int wtf(String tag, Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false);
}
public static int wtf(String tag, String msg, Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false);
}
public static int println(int priority, String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
}
}

View File

@@ -0,0 +1,423 @@
/*
* 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 memory efficient
* than using a HashMap to map Integers to Objects, both because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.
*
* <p>Note that this container keeps its mappings in an array data structure,
* using a binary search to find keys. The implementation is not intended to be appropriate for
* data structures
* that may contain large numbers of items. It is generally slower than a traditional
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
*
* <p>To help with performance, the container includes an optimization when removing
* keys: instead of compacting its array immediately, it leaves the removed entry marked
* as deleted. The entry can then be re-used for the same key, or compacted later in
* a single garbage collection step of all removed entries. This garbage collection will
* need to be performed at any time the array needs to be grown or the the map size or
* entry values are retrieved.</p>
*
* <p>It is possible to iterate over the items in this container using
* {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
* <code>keyAt(int)</code> with ascending values of the index will return the
* keys in ascending order, or the values corresponding to the keys in ascending
* order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
private int[] mKeys;
private Object[] mValues;
private int mSize;
/**
* 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. If you supply an initial capacity of 0, the
* sparse array will be initialized with a light-weight representation
* not requiring any additional array allocations.
*/
public SparseArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = ContainerHelpers.EMPTY_INTS;
mValues = ContainerHelpers.EMPTY_OBJECTS;
} else {
initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new Object[initialCapacity];
}
mSize = 0;
}
@Override
@SuppressWarnings("unchecked")
public SparseArray<E> clone() {
SparseArray<E> clone = null;
try {
clone = (SparseArray<E>) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
/**
* 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.
*/
@SuppressWarnings("unchecked")
public E get(int key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, 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 = ContainerHelpers.binarySearch(mKeys, 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);
}
/**
* Removes the mapping at the specified index.
*/
public void removeAt(int index) {
if (mValues[index] != DELETED) {
mValues[index] = DELETED;
mGarbage = true;
}
}
/**
* Remove a range of mappings as a batch.
*
* @param index Index to begin at
* @param size Number of mappings to remove
*/
public void removeAtRange(int index, int size) {
final int end = Math.min(mSize, index + size);
for (int i = index; i < end; i++) {
removeAt(i);
}
}
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;
values[i] = null;
}
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 = ContainerHelpers.binarySearch(mKeys, 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 = ~ContainerHelpers.binarySearch(mKeys, 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.
*
* <p>The keys corresponding to indices in ascending order are guaranteed to
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
*/
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.
*
* <p>The values corresponding to indices in ascending order are guaranteed
* to be associated with keys in ascending order, e.g.,
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
*/
@SuppressWarnings("unchecked")
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 ContainerHelpers.binarySearch(mKeys, 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.
* <p>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.
* <p>Note also that unlike most collections' {@code indexOf} methods,
* this method compares values using {@code ==} rather than {@code equals}.
*/
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;
}
/**
* {@inheritDoc}
*
* <p>This implementation composes a string by iterating over its mappings. If
* this map contains itself as a value, the string "(this Map)"
* will appear in its place.
*/
@Override
public String toString() {
if (size() <= 0) {
return "{}";
}
StringBuilder buffer = new StringBuilder(mSize * 28);
buffer.append('{');
for (int i=0; i<mSize; i++) {
if (i > 0) {
buffer.append(", ");
}
int key = keyAt(i);
buffer.append(key);
buffer.append('=');
Object value = valueAt(i);
if (value != this) {
buffer.append(value);
} else {
buffer.append("(this Map)");
}
}
buffer.append('}');
return buffer.toString();
}
}

View File

@@ -0,0 +1,292 @@
/*
* 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 memory efficient
* than using a HashMap to map Integers to Integers, both because it avoids
* auto-boxing keys and values and its data structure doesn't rely on an extra entry object
* for each mapping.
*
* <p>Note that this container keeps its mappings in an array data structure,
* using a binary search to find keys. The implementation is not intended to be appropriate for
* data structures
* that may contain large numbers of items. It is generally slower than a traditional
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
*
* <p>It is possible to iterate over the items in this container using
* {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
* <code>keyAt(int)</code> with ascending values of the index will return the
* keys in ascending order, or the values corresponding to the keys in ascending
* order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseIntArray implements Cloneable {
private int[] mKeys;
private int[] mValues;
private int mSize;
/**
* 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. If you supply an initial capacity of 0, the
* sparse array will be initialized with a light-weight representation
* not requiring any additional array allocations.
*/
public SparseIntArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = ContainerHelpers.EMPTY_INTS;
mValues = ContainerHelpers.EMPTY_INTS;
} else {
initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new int[initialCapacity];
}
mSize = 0;
}
@Override
public SparseIntArray clone() {
SparseIntArray clone = null;
try {
clone = (SparseIntArray) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
/**
* 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 = ContainerHelpers.binarySearch(mKeys, 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 = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
removeAt(i);
}
}
/**
* Removes the mapping at the given index.
*/
public void removeAt(int index) {
System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 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 = ContainerHelpers.binarySearch(mKeys, 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.
*
* <p>The keys corresponding to indices in ascending order are guaranteed to
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
*/
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.
*
* <p>The values corresponding to indices in ascending order are guaranteed
* to be associated with keys in ascending order, e.g.,
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
*/
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 ContainerHelpers.binarySearch(mKeys, 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;
}
/**
* {@inheritDoc}
*
* <p>This implementation composes a string by iterating over its mappings.
*/
@Override
public String toString() {
if (size() <= 0) {
return "{}";
}
StringBuilder buffer = new StringBuilder(mSize * 28);
buffer.append('{');
for (int i=0; i<mSize; i++) {
if (i > 0) {
buffer.append(", ");
}
int key = keyAt(i);
buffer.append(key);
buffer.append('=');
int value = valueAt(i);
buffer.append(value);
}
buffer.append('}');
return buffer.toString();
}
}

Some files were not shown because too many files have changed in this diff Show More