android support! thanks to TachiWeb devs.

This commit is contained in:
Aria Moradi
2021-01-02 04:57:20 +03:30
parent ced07d4e1e
commit 1e46a0c78c
291 changed files with 68699 additions and 16 deletions

View File

@@ -0,0 +1,471 @@
/*
* 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 com.android.internal.util;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;
import libcore.util.EmptyArray;
import java.lang.reflect.Array;
import java.util.*;
/**
* ArrayUtils contains some methods that you can call to find out
* the most efficient increments by which to grow arrays.
*/
public class ArrayUtils {
private static final int CACHE_SIZE = 73;
private static Object[] sCache = new Object[CACHE_SIZE];
private ArrayUtils() { /* cannot be instantiated */ }
public static byte[] newUnpaddedByteArray(int minLen) {
return new byte[minLen];
}
public static char[] newUnpaddedCharArray(int minLen) {
return new char[minLen];
}
public static int[] newUnpaddedIntArray(int minLen) {
return new int[minLen];
}
public static boolean[] newUnpaddedBooleanArray(int minLen) {
return new boolean[minLen];
}
public static long[] newUnpaddedLongArray(int minLen) {
return new long[minLen];
}
public static float[] newUnpaddedFloatArray(int minLen) {
return new float[minLen];
}
public static Object[] newUnpaddedObjectArray(int minLen) {
return new Object[minLen];
}
/**
* Checks if the beginnings of two byte arrays are equal.
*
* @param array1 the first byte array
* @param array2 the second byte array
* @param length the number of bytes to check
* @return true if they're equal, false otherwise
*/
public static boolean equals(byte[] array1, byte[] array2, int length) {
if (length < 0) {
throw new IllegalArgumentException();
}
if (array1 == array2) {
return true;
}
if (array1 == null || array2 == null || array1.length < length || array2.length < length) {
return false;
}
for (int i = 0; i < length; i++) {
if (array1[i] != array2[i]) {
return false;
}
}
return true;
}
/**
* Returns an empty array of the specified type. The intent is that
* it will return the same empty array every time to avoid reallocation,
* although this is not guaranteed.
*/
@SuppressWarnings("unchecked")
public static <T> T[] emptyArray(Class<T> kind) {
if (kind == Object.class) {
return (T[]) EmptyArray.OBJECT;
}
int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
Object cache = sCache[bucket];
if (cache == null || cache.getClass().getComponentType() != kind) {
cache = Array.newInstance(kind, 0);
sCache[bucket] = cache;
// Log.e("cache", "new empty " + kind.getName() + " at " + bucket);
}
return (T[]) cache;
}
/**
* Checks if given array is null or has zero elements.
*/
public static boolean isEmpty(@Nullable Collection<?> array) {
return array == null || array.isEmpty();
}
/**
* Checks if given array is null or has zero elements.
*/
public static <T> boolean isEmpty(@Nullable T[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
public static boolean isEmpty(@Nullable int[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
public static boolean isEmpty(@Nullable long[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
public static boolean isEmpty(@Nullable byte[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
public static boolean isEmpty(@Nullable boolean[] array) {
return array == null || array.length == 0;
}
/**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
* @return true if the value is present in the array
*/
public static <T> boolean contains(@Nullable T[] array, T value) {
return indexOf(array, value) != -1;
}
/**
* Return first index of {@code value} in {@code array}, or {@code -1} if
* not found.
*/
public static <T> int indexOf(@Nullable T[] array, T value) {
if (array == null) return -1;
for (int i = 0; i < array.length; i++) {
if (Objects.equals(array[i], value)) return i;
}
return -1;
}
/**
* Test if all {@code check} items are contained in {@code array}.
*/
public static <T> boolean containsAll(@Nullable T[] array, T[] check) {
if (check == null) return true;
for (T checkItem : check) {
if (!contains(array, checkItem)) {
return false;
}
}
return true;
}
/**
* Test if any {@code check} items are contained in {@code array}.
*/
public static <T> boolean containsAny(@Nullable T[] array, T[] check) {
if (check == null) return false;
for (T checkItem : check) {
if (contains(array, checkItem)) {
return true;
}
}
return false;
}
public static boolean contains(@Nullable int[] array, int value) {
if (array == null) return false;
for (int element : array) {
if (element == value) {
return true;
}
}
return false;
}
public static boolean contains(@Nullable long[] array, long value) {
if (array == null) return false;
for (long element : array) {
if (element == value) {
return true;
}
}
return false;
}
public static long total(@Nullable long[] array) {
long total = 0;
if (array != null) {
for (long value : array) {
total += value;
}
}
return total;
}
public static int[] convertToIntArray(List<Integer> list) {
int[] array = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}
/**
* Adds value to given array if not already present, providing set-like
* behavior.
*/
@SuppressWarnings("unchecked")
public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
final T[] result;
final int end;
if (array != null) {
if (contains(array, element)) return array;
end = array.length;
result = (T[])Array.newInstance(kind, end + 1);
System.arraycopy(array, 0, result, 0, end);
} else {
end = 0;
result = (T[])Array.newInstance(kind, 1);
}
result[end] = element;
return result;
}
/**
* Removes value from given array if present, providing set-like behavior.
*/
@SuppressWarnings("unchecked")
public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) {
if (array != null) {
if (!contains(array, element)) return array;
final int length = array.length;
for (int i = 0; i < length; i++) {
if (Objects.equals(array[i], element)) {
if (length == 1) {
return null;
}
T[] result = (T[])Array.newInstance(kind, length - 1);
System.arraycopy(array, 0, result, 0, i);
System.arraycopy(array, i + 1, result, i, length - i - 1);
return result;
}
}
}
return array;
}
/**
* Adds value to given array if not already present, providing set-like
* behavior.
*/
public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
if (cur == null) {
return new int[] { val };
}
final int N = cur.length;
for (int i = 0; i < N; i++) {
if (cur[i] == val) {
return cur;
}
}
int[] ret = new int[N + 1];
System.arraycopy(cur, 0, ret, 0, N);
ret[N] = val;
return ret;
}
/**
* Removes value from given array if present, providing set-like behavior.
*/
public static @Nullable int[] removeInt(@Nullable int[] cur, int val) {
if (cur == null) {
return null;
}
final int N = cur.length;
for (int i = 0; i < N; i++) {
if (cur[i] == val) {
int[] ret = new int[N - 1];
if (i > 0) {
System.arraycopy(cur, 0, ret, 0, i);
}
if (i < (N - 1)) {
System.arraycopy(cur, i + 1, ret, i, N - i - 1);
}
return ret;
}
}
return cur;
}
/**
* Removes value from given array if present, providing set-like behavior.
*/
public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
if (cur == null) {
return null;
}
final int N = cur.length;
for (int i = 0; i < N; i++) {
if (Objects.equals(cur[i], val)) {
String[] ret = new String[N - 1];
if (i > 0) {
System.arraycopy(cur, 0, ret, 0, i);
}
if (i < (N - 1)) {
System.arraycopy(cur, i + 1, ret, i, N - i - 1);
}
return ret;
}
}
return cur;
}
/**
* Adds value to given array if not already present, providing set-like
* behavior.
*/
public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
if (cur == null) {
return new long[] { val };
}
final int N = cur.length;
for (int i = 0; i < N; i++) {
if (cur[i] == val) {
return cur;
}
}
long[] ret = new long[N + 1];
System.arraycopy(cur, 0, ret, 0, N);
ret[N] = val;
return ret;
}
/**
* Removes value from given array if present, providing set-like behavior.
*/
public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
if (cur == null) {
return null;
}
final int N = cur.length;
for (int i = 0; i < N; i++) {
if (cur[i] == val) {
long[] ret = new long[N - 1];
if (i > 0) {
System.arraycopy(cur, 0, ret, 0, i);
}
if (i < (N - 1)) {
System.arraycopy(cur, i + 1, ret, i, N - i - 1);
}
return ret;
}
}
return cur;
}
public static @Nullable long[] cloneOrNull(@Nullable long[] array) {
return (array != null) ? array.clone() : null;
}
public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
return (array != null) ? new ArraySet<T>(array) : null;
}
public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
if (cur == null) {
cur = new ArraySet<>();
}
cur.add(val);
return cur;
}
public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {
if (cur == null) {
return null;
}
cur.remove(val);
if (cur.isEmpty()) {
return null;
} else {
return cur;
}
}
public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
return (cur != null) ? cur.contains(val) : false;
}
public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
cur = new ArrayList<>();
}
cur.add(val);
return cur;
}
public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
return null;
}
cur.remove(val);
if (cur.isEmpty()) {
return null;
} else {
return cur;
}
}
public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
return (cur != null) ? cur.contains(val) : false;
}
public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) {
if (array == null || size == 0) {
return null;
} else if (array.length == size) {
return array;
} else {
return Arrays.copyOf(array, size);
}
}
/**
* Returns true if the two ArrayLists are equal with respect to the objects they contain.
* The objects must be in the same order and be reference equal (== not .equals()).
*/
public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) {
if (a == b) {
return true;
}
final int sizeA = a.size();
final int sizeB = b.size();
if (a == null || b == null || sizeA != sizeB) {
return false;
}
boolean diff = false;
for (int i = 0; i < sizeA && !diff; i++) {
diff |= a.get(i) != b.get(i);
}
return !diff;
}
/**
* Removes elements that match the predicate in an efficient way that alters the order of
* elements in the collection. This should only be used if order is not important.
* @param collection The ArrayList from which to remove elements.
* @param predicate The predicate that each element is tested against.
* @return the number of elements removed.
*/
public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection,
@NonNull java.util.function.Predicate<T> predicate) {
if (collection == null) {
return 0;
}
final int size = collection.size();
int leftIdx = 0;
int rightIdx = size - 1;
while (leftIdx <= rightIdx) {
// Find the next element to remove moving left to right.
while (leftIdx < size && !predicate.test(collection.get(leftIdx))) {
leftIdx++;
}
// Find the next element to keep moving right to left.
while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) {
rightIdx--;
}
if (leftIdx >= rightIdx) {
// Done.
break;
}
Collections.swap(collection, leftIdx, rightIdx);
leftIdx++;
rightIdx--;
}
// leftIdx is now at the end.
for (int i = size - 1; i >= leftIdx; i--) {
collection.remove(i);
}
return size - leftIdx;
}
}

View File

@@ -0,0 +1,370 @@
/*
* 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 com.android.internal.util;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
/**
* This is a quick and dirty implementation of XmlSerializer that isn't horribly
* painfully slow like the normal one. It only does what is needed for the
* specific XML files being written with it.
*/
public class FastXmlSerializer implements XmlSerializer {
private static final String ESCAPE_TABLE[] = new String[] {
"&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;", // 0-7
"&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;", // 8-15
"&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;", // 16-23
"&#24;", "&#25;", "&#26;", "&#27;", "&#28;", "&#29;", "&#30;", "&#31;", // 24-31
null, null, "&quot;", null, null, null, "&amp;", null, // 32-39
null, null, null, null, null, null, null, null, // 40-47
null, null, null, null, null, null, null, null, // 48-55
null, null, null, null, "&lt;", null, "&gt;", null, // 56-63
};
private static final int DEFAULT_BUFFER_LEN = 32*1024;
private static String sSpace = " ";
private final int mBufferLen;
private final char[] mText;
private int mPos;
private Writer mWriter;
private OutputStream mOutputStream;
private CharsetEncoder mCharset;
private ByteBuffer mBytes;
private boolean mIndent = false;
private boolean mInTag;
private int mNesting = 0;
private boolean mLineStart = true;
public FastXmlSerializer() {
this(DEFAULT_BUFFER_LEN);
}
/**
* Allocate a FastXmlSerializer with the given internal output buffer size. If the
* size is zero or negative, then the default buffer size will be used.
*
* @param bufferSize Size in bytes of the in-memory output buffer that the writer will use.
*/
public FastXmlSerializer(int bufferSize) {
mBufferLen = (bufferSize > 0) ? bufferSize : DEFAULT_BUFFER_LEN;
mText = new char[mBufferLen];
mBytes = ByteBuffer.allocate(mBufferLen);
}
private void append(char c) throws IOException {
int pos = mPos;
if (pos >= (mBufferLen-1)) {
flush();
pos = mPos;
}
mText[pos] = c;
mPos = pos+1;
}
private void append(String str, int i, final int length) throws IOException {
if (length > mBufferLen) {
final int end = i + length;
while (i < end) {
int next = i + mBufferLen;
append(str, i, next<end ? mBufferLen : (end-i));
i = next;
}
return;
}
int pos = mPos;
if ((pos+length) > mBufferLen) {
flush();
pos = mPos;
}
str.getChars(i, i+length, mText, pos);
mPos = pos + length;
}
private void append(char[] buf, int i, final int length) throws IOException {
if (length > mBufferLen) {
final int end = i + length;
while (i < end) {
int next = i + mBufferLen;
append(buf, i, next<end ? mBufferLen : (end-i));
i = next;
}
return;
}
int pos = mPos;
if ((pos+length) > mBufferLen) {
flush();
pos = mPos;
}
System.arraycopy(buf, i, mText, pos, length);
mPos = pos + length;
}
private void append(String str) throws IOException {
append(str, 0, str.length());
}
private void appendIndent(int indent) throws IOException {
indent *= 4;
if (indent > sSpace.length()) {
indent = sSpace.length();
}
append(sSpace, 0, indent);
}
private void escapeAndAppendString(final String string) throws IOException {
final int N = string.length();
final char NE = (char)ESCAPE_TABLE.length;
final String[] escapes = ESCAPE_TABLE;
int lastPos = 0;
int pos;
for (pos=0; pos<N; pos++) {
char c = string.charAt(pos);
if (c >= NE) continue;
String escape = escapes[c];
if (escape == null) continue;
if (lastPos < pos) append(string, lastPos, pos-lastPos);
lastPos = pos + 1;
append(escape);
}
if (lastPos < pos) append(string, lastPos, pos-lastPos);
}
private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
final char NE = (char)ESCAPE_TABLE.length;
final String[] escapes = ESCAPE_TABLE;
int end = start+len;
int lastPos = start;
int pos;
for (pos=start; pos<end; pos++) {
char c = buf[pos];
if (c >= NE) continue;
String escape = escapes[c];
if (escape == null) continue;
if (lastPos < pos) append(buf, lastPos, pos-lastPos);
lastPos = pos + 1;
append(escape);
}
if (lastPos < pos) append(buf, lastPos, pos-lastPos);
}
public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
IllegalArgumentException, IllegalStateException {
append(' ');
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
append("=\"");
escapeAndAppendString(value);
append('"');
mLineStart = false;
return this;
}
public void cdsect(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void comment(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void docdecl(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
flush();
}
public XmlSerializer endTag(String namespace, String name) throws IOException,
IllegalArgumentException, IllegalStateException {
mNesting--;
if (mInTag) {
append(" />\n");
} else {
if (mIndent && mLineStart) {
appendIndent(mNesting);
}
append("</");
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
append(">\n");
}
mLineStart = true;
mInTag = false;
return this;
}
public void entityRef(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
private void flushBytes() throws IOException {
int position;
if ((position = mBytes.position()) > 0) {
mBytes.flip();
mOutputStream.write(mBytes.array(), 0, position);
mBytes.clear();
}
}
public void flush() throws IOException {
//Log.i("PackageManager", "flush mPos=" + mPos);
if (mPos > 0) {
if (mOutputStream != null) {
CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
CoderResult result = mCharset.encode(charBuffer, mBytes, true);
while (true) {
if (result.isError()) {
throw new IOException(result.toString());
} else if (result.isOverflow()) {
flushBytes();
result = mCharset.encode(charBuffer, mBytes, true);
continue;
}
break;
}
flushBytes();
mOutputStream.flush();
} else {
mWriter.write(mText, 0, mPos);
mWriter.flush();
}
mPos = 0;
}
}
public int getDepth() {
throw new UnsupportedOperationException();
}
public boolean getFeature(String name) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getNamespace() {
throw new UnsupportedOperationException();
}
public String getPrefix(String namespace, boolean generatePrefix)
throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
public Object getProperty(String name) {
throw new UnsupportedOperationException();
}
public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void processingInstruction(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void setFeature(String name, boolean state) throws IllegalArgumentException,
IllegalStateException {
if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
mIndent = true;
return;
}
throw new UnsupportedOperationException();
}
public void setOutput(OutputStream os, String encoding) throws IOException,
IllegalArgumentException, IllegalStateException {
if (os == null)
throw new IllegalArgumentException();
if (true) {
try {
mCharset = Charset.forName(encoding).newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
} catch (IllegalCharsetNameException e) {
throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
encoding).initCause(e));
} catch (UnsupportedCharsetException e) {
throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
encoding).initCause(e));
}
mOutputStream = os;
} else {
setOutput(
encoding == null
? new OutputStreamWriter(os)
: new OutputStreamWriter(os, encoding));
}
}
public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
IllegalStateException {
mWriter = writer;
}
public void setPrefix(String prefix, String namespace) throws IOException,
IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void setProperty(String name, Object value) throws IllegalArgumentException,
IllegalStateException {
throw new UnsupportedOperationException();
}
public void startDocument(String encoding, Boolean standalone) throws IOException,
IllegalArgumentException, IllegalStateException {
append("<?xml version='1.0' encoding='utf-8' standalone='"
+ (standalone ? "yes" : "no") + "' ?>\n");
mLineStart = true;
}
public XmlSerializer startTag(String namespace, String name) throws IOException,
IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(">\n");
}
if (mIndent) {
appendIndent(mNesting);
}
mNesting++;
append('<');
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
mInTag = true;
mLineStart = false;
return this;
}
public XmlSerializer text(char[] buf, int start, int len) throws IOException,
IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(">");
mInTag = false;
}
escapeAndAppendString(buf, start, len);
if (mIndent) {
mLineStart = buf[start+len-1] == '\n';
}
return this;
}
public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
IllegalStateException {
if (mInTag) {
append(">");
mInTag = false;
}
escapeAndAppendString(text);
if (mIndent) {
mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\n');
}
return this;
}
}

View File

@@ -0,0 +1,451 @@
/*
* 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 com.android.internal.util;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.text.TextUtils;
import java.util.Collection;
/**
* Simple static methods to be called at the start of your own methods to verify
* correct arguments and state.
*/
public class Preconditions {
public static void checkArgument(boolean expression) {
if (!expression) {
throw new IllegalArgumentException();
}
}
/**
* Ensures that an expression checking an argument is true.
*
* @param expression the expression to check
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(boolean expression, final Object errorMessage) {
if (!expression) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
}
/**
* Ensures that an expression checking an argument is true.
*
* @param expression the expression to check
* @param messageTemplate a printf-style message template to use if the check fails; will
* be converted to a string using {@link String#format(String, Object...)}
* @param messageArgs arguments for {@code messageTemplate}
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(boolean expression,
final String messageTemplate,
final Object... messageArgs) {
if (!expression) {
throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
}
}
/**
* Ensures that an string reference passed as a parameter to the calling
* method is not empty.
*
* @param string an string reference
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException();
}
return string;
}
/**
* Ensures that an string reference passed as a parameter to the calling
* method is not empty.
*
* @param string an string reference
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
final Object errorMessage) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
return string;
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static @NonNull <T> T checkNotNull(final T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param messageTemplate a printf-style message template to use if the check fails; will
* be converted to a string using {@link String#format(String, Object...)}
* @param messageArgs arguments for {@code messageTemplate}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static @NonNull <T> T checkNotNull(final T reference,
final String messageTemplate,
final Object... messageArgs) {
if (reference == null) {
throw new NullPointerException(String.format(messageTemplate, messageArgs));
}
return reference;
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param message exception message
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(final boolean expression, String message) {
if (!expression) {
throw new IllegalStateException(message);
}
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(final boolean expression) {
checkState(expression, null);
}
/**
* Check the requested flags, throwing if any requested flags are outside
* the allowed set.
*
* @return the validated requested flags.
*/
public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
if ((requestedFlags & allowedFlags) != requestedFlags) {
throw new IllegalArgumentException("Requested flags 0x"
+ Integer.toHexString(requestedFlags) + ", but only 0x"
+ Integer.toHexString(allowedFlags) + " are allowed");
}
return requestedFlags;
}
/**
* Ensures that that the argument numeric value is non-negative.
*
* @param value a numeric int value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was negative
*/
public static @IntRange(from = 0) int checkArgumentNonnegative(final int value,
final String errorMessage) {
if (value < 0) {
throw new IllegalArgumentException(errorMessage);
}
return value;
}
/**
* Ensures that that the argument numeric value is non-negative.
*
* @param value a numeric int value
*
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was negative
*/
public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
if (value < 0) {
throw new IllegalArgumentException();
}
return value;
}
/**
* Ensures that that the argument numeric value is non-negative.
*
* @param value a numeric long value
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was negative
*/
public static long checkArgumentNonnegative(final long value) {
if (value < 0) {
throw new IllegalArgumentException();
}
return value;
}
/**
* Ensures that that the argument numeric value is non-negative.
*
* @param value a numeric long value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was negative
*/
public static long checkArgumentNonnegative(final long value, final String errorMessage) {
if (value < 0) {
throw new IllegalArgumentException(errorMessage);
}
return value;
}
/**
* Ensures that that the argument numeric value is positive.
*
* @param value a numeric int value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value
* @throws IllegalArgumentException if {@code value} was not positive
*/
public static int checkArgumentPositive(final int value, final String errorMessage) {
if (value <= 0) {
throw new IllegalArgumentException(errorMessage);
}
return value;
}
/**
* Ensures that the argument floating point value is a finite number.
*
* <p>A finite number is defined to be both representable (that is, not NaN) and
* not infinite (that is neither positive or negative infinity).</p>
*
* @param value a floating point value
* @param valueName the name of the argument to use if the check fails
*
* @return the validated floating point value
*
* @throws IllegalArgumentException if {@code value} was not finite
*/
public static float checkArgumentFinite(final float value, final String valueName) {
if (Float.isNaN(value)) {
throw new IllegalArgumentException(valueName + " must not be NaN");
} else if (Float.isInfinite(value)) {
throw new IllegalArgumentException(valueName + " must not be infinite");
}
return value;
}
/**
* Ensures that the argument floating point value is within the inclusive range.
*
* <p>While this can be used to range check against +/- infinity, note that all NaN numbers
* will always be out of range.</p>
*
* @param value a floating point value
* @param lower the lower endpoint of the inclusive range
* @param upper the upper endpoint of the inclusive range
* @param valueName the name of the argument to use if the check fails
*
* @return the validated floating point value
*
* @throws IllegalArgumentException if {@code value} was not within the range
*/
public static float checkArgumentInRange(float value, float lower, float upper,
String valueName) {
if (Float.isNaN(value)) {
throw new IllegalArgumentException(valueName + " must not be NaN");
} else if (value < lower) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
} else if (value > upper) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
}
return value;
}
/**
* Ensures that the argument int value is within the inclusive range.
*
* @param value a int value
* @param lower the lower endpoint of the inclusive range
* @param upper the upper endpoint of the inclusive range
* @param valueName the name of the argument to use if the check fails
*
* @return the validated int value
*
* @throws IllegalArgumentException if {@code value} was not within the range
*/
public static int checkArgumentInRange(int value, int lower, int upper,
String valueName) {
if (value < lower) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
} else if (value > upper) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
}
return value;
}
/**
* Ensures that the argument long value is within the inclusive range.
*
* @param value a long value
* @param lower the lower endpoint of the inclusive range
* @param upper the upper endpoint of the inclusive range
* @param valueName the name of the argument to use if the check fails
*
* @return the validated long value
*
* @throws IllegalArgumentException if {@code value} was not within the range
*/
public static long checkArgumentInRange(long value, long lower, long upper,
String valueName) {
if (value < lower) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
} else if (value > upper) {
throw new IllegalArgumentException(
String.format(
"%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
}
return value;
}
/**
* Ensures that the array is not {@code null}, and none of its elements are {@code null}.
*
* @param value an array of boxed objects
* @param valueName the name of the argument to use if the check fails
*
* @return the validated array
*
* @throws NullPointerException if the {@code value} or any of its elements were {@code null}
*/
public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
if (value == null) {
throw new NullPointerException(valueName + " must not be null");
}
for (int i = 0; i < value.length; ++i) {
if (value[i] == null) {
throw new NullPointerException(
String.format("%s[%d] must not be null", valueName, i));
}
}
return value;
}
/**
* Ensures that the {@link Collection} is not {@code null}, and none of its elements are
* {@code null}.
*
* @param value a {@link Collection} of boxed objects
* @param valueName the name of the argument to use if the check fails
*
* @return the validated {@link Collection}
*
* @throws NullPointerException if the {@code value} or any of its elements were {@code null}
*/
public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
final C value, final String valueName) {
if (value == null) {
throw new NullPointerException(valueName + " must not be null");
}
long ctr = 0;
for (T elem : value) {
if (elem == null) {
throw new NullPointerException(
String.format("%s[%d] must not be null", valueName, ctr));
}
++ctr;
}
return value;
}
/**
* Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
*
* @param value a {@link Collection} of boxed elements.
* @param valueName the name of the argument to use if the check fails.
* @return the validated {@link Collection}
*
* @throws NullPointerException if the {@code value} was {@code null}
* @throws IllegalArgumentException if the {@code value} was empty
*/
public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
final String valueName) {
if (value == null) {
throw new NullPointerException(valueName + " must not be null");
}
if (value.isEmpty()) {
throw new IllegalArgumentException(valueName + " is empty");
}
return value;
}
/**
* Ensures that all elements in the argument floating point array are within the inclusive range
*
* <p>While this can be used to range check against +/- infinity, note that all NaN numbers
* will always be out of range.</p>
*
* @param value a floating point array of values
* @param lower the lower endpoint of the inclusive range
* @param upper the upper endpoint of the inclusive range
* @param valueName the name of the argument to use if the check fails
*
* @return the validated floating point value
*
* @throws IllegalArgumentException if any of the elements in {@code value} were out of range
* @throws NullPointerException if the {@code value} was {@code null}
*/
public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
String valueName) {
checkNotNull(value, valueName + " must not be null");
for (int i = 0; i < value.length; ++i) {
float v = value[i];
if (Float.isNaN(v)) {
throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
} else if (v < lower) {
throw new IllegalArgumentException(
String.format("%s[%d] is out of range of [%f, %f] (too low)",
valueName, i, lower, upper));
} else if (v > upper) {
throw new IllegalArgumentException(
String.format("%s[%d] is out of range of [%f, %f] (too high)",
valueName, i, lower, upper));
}
}
return value;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
package com.f2prateek;
//TODO Consider if we can change this package into an Android dependency

View File

@@ -0,0 +1,34 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class BooleanAdapter implements Preference.Adapter<Boolean> {
static final BooleanAdapter INSTANCE = new BooleanAdapter();
@Override public Boolean get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getBoolean(key, false);
}
@Override public void set(@NonNull String key, @NonNull Boolean value,
@NonNull SharedPreferences.Editor editor) {
editor.putBoolean(key, value);
}
}

View File

@@ -0,0 +1,40 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class EnumAdapter<T extends Enum<T>> implements Preference.Adapter<T> {
private final Class<T> enumClass;
EnumAdapter(Class<T> enumClass) {
this.enumClass = enumClass;
}
@Override public T get(@NonNull String key, @NonNull SharedPreferences preferences) {
String value = preferences.getString(key, null);
assert value != null; // Not called unless key is present.
return Enum.valueOf(enumClass, value);
}
@Override
public void set(@NonNull String key, @NonNull T value, @NonNull SharedPreferences.Editor editor) {
editor.putString(key, value.name());
}
}

View File

@@ -0,0 +1,34 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class FloatAdapter implements Preference.Adapter<Float> {
static final FloatAdapter INSTANCE = new FloatAdapter();
@Override public Float get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getFloat(key, 0f);
}
@Override public void set(@NonNull String key, @NonNull Float value,
@NonNull SharedPreferences.Editor editor) {
editor.putFloat(key, value);
}
}

View File

@@ -0,0 +1,34 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class IntegerAdapter implements Preference.Adapter<Integer> {
static final IntegerAdapter INSTANCE = new IntegerAdapter();
@Override public Integer get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getInt(key, 0);
}
@Override public void set(@NonNull String key, @NonNull Integer value,
@NonNull SharedPreferences.Editor editor) {
editor.putInt(key, value);
}
}

View File

@@ -0,0 +1,34 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class LongAdapter implements Preference.Adapter<Long> {
static final LongAdapter INSTANCE = new LongAdapter();
@Override public Long get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getLong(key, 0L);
}
@Override public void set(@NonNull String key, @NonNull Long value,
@NonNull SharedPreferences.Editor editor) {
editor.putLong(key, value);
}
}

View File

@@ -0,0 +1,30 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
final class Preconditions {
static void checkNotNull(Object o, String message) {
if (o == null) {
throw new NullPointerException(message);
}
}
private Preconditions() {
throw new AssertionError("No instances");
}
}

View File

@@ -0,0 +1,127 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file has been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import rx.Observable;
import rx.functions.Action1;
/** A preference of type {@link T}. Instances can be created from {@link RxSharedPreferences}. */
public final class Preference<T> {
/** Stores and retrieves instances of {@code T} in {@link SharedPreferences}. */
public interface Adapter<T> {
/** Retrieve the value for {@code key} from {@code preferences}. */
T get(@NonNull String key, @NonNull SharedPreferences preferences);
/**
* Store non-null {@code value} for {@code key} in {@code editor}.
* <p>
* Note: Implementations <b>must not</b> call {@code commit()} or {@code apply()} on
* {@code editor}.
*/
void set(@NonNull String key, @NonNull T value, @NonNull SharedPreferences.Editor editor);
}
private final SharedPreferences preferences;
private final String key;
private final T defaultValue;
private final Adapter<T> adapter;
private final Observable<T> values;
Preference(SharedPreferences preferences, final String key, T defaultValue, Adapter<T> adapter,
Observable<String> keyChanges) {
this.preferences = preferences;
this.key = key;
this.defaultValue = defaultValue;
this.adapter = adapter;
this.values = keyChanges
.filter(key::equals)
.startWith("<init>") // Dummy value to trigger initial load.
.onBackpressureLatest()
.map(ignored -> get());
}
/** The key for which this preference will store and retrieve values. */
@NonNull
public String key() {
return key;
}
/** The value used if none is stored. May be {@code null}. */
@Nullable
public T defaultValue() {
return defaultValue;
}
/**
* Retrieve the current value for this preference. Returns {@link #defaultValue()} if no value is
* set.
*/
@Nullable
public T get() {
if (!preferences.contains(key)) {
return defaultValue;
}
return adapter.get(key, preferences);
}
/**
* Change this preference's stored value to {@code value}. A value of {@code null} will delete the
* preference.
*/
public void set(@Nullable T value) {
SharedPreferences.Editor editor = preferences.edit();
if (value == null) {
editor.remove(key);
} else {
adapter.set(key, value, editor);
}
editor.apply();
}
/** Returns true if this preference has a stored value. */
public boolean isSet() {
return preferences.contains(key);
}
/** Delete the stored value for this preference, if any. */
public void delete() {
set(null);
}
/**
* Observe changes to this preference. The current value or {@link #defaultValue()} will be
* emitted on first subscribe.
*/
@CheckResult @NonNull
public Observable<T> asObservable() {
return values;
}
/**
* An action which stores a new value for this preference. Passing {@code null} will delete the
* preference.
*/
@CheckResult @NonNull
public Action1<? super T> asAction() {
return (Action1<T>) this::set;
}
}

View File

@@ -0,0 +1,178 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file has been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Collections;
import java.util.Set;
import rx.Observable;
import rx.subscriptions.Subscriptions;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static com.f2prateek.rx.preferences.Preconditions.checkNotNull;
/** A factory for reactive {@link Preference} objects. */
public final class RxSharedPreferences {
private static final Float DEFAULT_FLOAT = 0f;
private static final Integer DEFAULT_INTEGER = 0;
private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
private static final Long DEFAULT_LONG = 0L;
/** Create an instance of {@link RxSharedPreferences} for {@code preferences}. */
@CheckResult @NonNull
public static RxSharedPreferences create(@NonNull SharedPreferences preferences) {
checkNotNull(preferences, "preferences == null");
return new RxSharedPreferences(preferences);
}
private final SharedPreferences preferences;
private final Observable<String> keyChanges;
private RxSharedPreferences(final SharedPreferences preferences) {
this.preferences = preferences;
this.keyChanges = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
final OnSharedPreferenceChangeListener listener = (preferences1, key) -> subscriber.onNext(key);
preferences.registerOnSharedPreferenceChangeListener(listener);
subscriber.add(Subscriptions.create(() -> preferences.unregisterOnSharedPreferenceChangeListener(listener)));
}).share();
}
/** Create a boolean preference for {@code key}. Default is {@code false}. */
@CheckResult @NonNull
public Preference<Boolean> getBoolean(@NonNull String key) {
return getBoolean(key, DEFAULT_BOOLEAN);
}
/** Create a boolean preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Boolean> getBoolean(@NonNull String key, @Nullable Boolean defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, BooleanAdapter.INSTANCE, keyChanges);
}
/** Create an enum preference for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public <T extends Enum<T>> Preference<T> getEnum(@NonNull String key,
@NonNull Class<T> enumClass) {
return getEnum(key, null, enumClass);
}
/** Create an enum preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public <T extends Enum<T>> Preference<T> getEnum(@NonNull String key, @Nullable T defaultValue,
@NonNull Class<T> enumClass) {
checkNotNull(key, "key == null");
checkNotNull(enumClass, "enumClass == null");
Preference.Adapter<T> adapter = new EnumAdapter<>(enumClass);
return new Preference<>(preferences, key, defaultValue, adapter, keyChanges);
}
/** Create a float preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Float> getFloat(@NonNull String key) {
return getFloat(key, DEFAULT_FLOAT);
}
/** Create a float preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Float> getFloat(@NonNull String key, @Nullable Float defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, FloatAdapter.INSTANCE, keyChanges);
}
/** Create an integer preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Integer> getInteger(@NonNull String key) {
//noinspection UnnecessaryBoxing
return getInteger(key, DEFAULT_INTEGER);
}
/** Create an integer preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Integer> getInteger(@NonNull String key, @Nullable Integer defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, IntegerAdapter.INSTANCE, keyChanges);
}
/** Create a long preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Long> getLong(@NonNull String key) {
//noinspection UnnecessaryBoxing
return getLong(key, DEFAULT_LONG);
}
/** Create a long preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Long> getLong(@NonNull String key, @Nullable Long defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, LongAdapter.INSTANCE, keyChanges);
}
/** Create a preference of type {@code T} for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public <T> Preference<T> getObject(@NonNull String key, @NonNull Preference.Adapter<T> adapter) {
return getObject(key, null, adapter);
}
/**
* Create a preference for type {@code T} for {@code key} with a default of {@code defaultValue}.
*/
@CheckResult @NonNull
public <T> Preference<T> getObject(@NonNull String key, @Nullable T defaultValue,
@NonNull Preference.Adapter<T> adapter) {
checkNotNull(key, "key == null");
checkNotNull(adapter, "adapter == null");
return new Preference<>(preferences, key, defaultValue, adapter, keyChanges);
}
/** Create a string preference for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public Preference<String> getString(@NonNull String key) {
return getString(key, null);
}
/** Create a string preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<String> getString(@NonNull String key, @Nullable String defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, StringAdapter.INSTANCE, keyChanges);
}
/** Create a string set preference for {@code key}. Default is an empty set. */
@TargetApi(HONEYCOMB)
@CheckResult @NonNull
public Preference<Set<String>> getStringSet(@NonNull String key) {
return getStringSet(key, Collections.emptySet());
}
/** Create a string set preference for {@code key} with a default of {@code defaultValue}. */
@TargetApi(HONEYCOMB)
@CheckResult @NonNull
public Preference<Set<String>> getStringSet(@NonNull String key,
@NonNull Set<String> defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, StringSetAdapter.INSTANCE, keyChanges);
}
}

View File

@@ -0,0 +1,17 @@
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class StringAdapter implements Preference.Adapter<String> {
static final StringAdapter INSTANCE = new StringAdapter();
@Override public String get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getString(key, null);
}
@Override public void set(@NonNull String key, @NonNull String value,
@NonNull SharedPreferences.Editor editor) {
editor.putString(key, value);
}
}

View File

@@ -0,0 +1,22 @@
package com.f2prateek.rx.preferences;
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import java.util.Set;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@TargetApi(HONEYCOMB)
final class StringSetAdapter implements Preference.Adapter<Set<String>> {
static final StringSetAdapter INSTANCE = new StringSetAdapter();
@Override public Set<String> get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getStringSet(key, null);
}
@Override public void set(@NonNull String key, @NonNull Set<String> value,
@NonNull SharedPreferences.Editor editor) {
editor.putStringSet(key, value);
}
}

View File

@@ -0,0 +1,7 @@
package com.github.pwittchen.reactivenetwork.library
import android.net.NetworkInfo
class Connectivity {
val state = NetworkInfo.State.CONNECTED
}

View File

@@ -0,0 +1,14 @@
package com.github.pwittchen.reactivenetwork.library
import android.content.Context
import rx.Observable
/**
* Created by nulldev on 12/29/16.
*/
class ReactiveNetwork {
companion object {
fun observeNetworkConnectivity(context: Context) = Observable.just(Connectivity())!!
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.duktape;
import kotlin.NotImplementedError;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.Closeable;
/** A simple EMCAScript (Javascript) interpreter. */
public final class Duktape implements Closeable, AutoCloseable {
private ScriptEngineManager factory = new ScriptEngineManager();
private ScriptEngine engine = factory.getEngineByName("JavaScript");
/**
* Create a new interpreter instance. Calls to this method <strong>must</strong> matched with
* calls to {@link #close()} on the returned instance to avoid leaking native memory.
*/
public static Duktape create() {
return new Duktape();
}
private Duktape() {}
/**
* Evaluate {@code script} and return a result. {@code fileName} will be used in error
* reporting. Note that the result must be one of the supported Java types or the call will
* return null.
*
* @throws DuktapeException if there is an error evaluating the script.
*/
public synchronized Object evaluate(String script, String fileName) {
throw new NotImplementedError("Not implemented!");
}
/**
* Evaluate {@code script} and return a result. Note that the result must be one of the
* supported Java types or the call will return null.
*
* @throws DuktapeException if there is an error evaluating the script.
*/
public synchronized Object evaluate(String script) {
try {
return engine.eval(script);
} catch (ScriptException e) {
throw new DuktapeException(e.getMessage());
}
}
/**
* Provides {@code object} to JavaScript as a global object called {@code name}. {@code type}
* defines the interface implemented by {@code object} that will be accessible to JavaScript.
* {@code type} must be an interface that does not extend any other interfaces, and cannot define
* any overloaded methods.
* <p>Methods of the interface may return {@code void} or any of the following supported argument
* types: {@code boolean}, {@link Boolean}, {@code int}, {@link Integer}, {@code double},
* {@link Double}, {@link String}.
*/
public synchronized <T> void set(String name, Class<T> type, T object) {
throw new NotImplementedError("Not implemented!");
}
/**
* Attaches to a global JavaScript object called {@code name} that implements {@code type}.
* {@code type} defines the interface implemented in JavaScript that will be accessible to Java.
* {@code type} must be an interface that does not extend any other interfaces, and cannot define
* any overloaded methods.
* <p>Methods of the interface may return {@code void} or any of the following supported argument
* types: {@code boolean}, {@link Boolean}, {@code int}, {@link Integer}, {@code double},
* {@link Double}, {@link String}.
*/
public synchronized <T> T get(final String name, final Class<T> type) {
throw new NotImplementedError("Not implemented!");
}
/**
* Release the native resources associated with this object. You <strong>must</strong> call this
* method for each instance to avoid leaking native memory.
*/
@Override
public synchronized void close() {}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.duktape;
import android.support.annotation.Keep;
import java.util.regex.Pattern;
// Called from native code.
@SuppressWarnings("unused")
// Instruct ProGuard not to strip this type.
@Keep
public final class DuktapeException extends RuntimeException {
/**
* Duktape stack trace strings have multiple lines of the format " at func (file.ext:line)".
* "func" is optional, but we'll omit frames without a function, since it means the frame is in
* native code.
*/
private static final Pattern STACK_TRACE_PATTERN = null;
/** Java StackTraceElements require a class name. We don't have one in JS, so use this. */
private static final String STACK_TRACE_CLASS_NAME = "JavaScript";
public DuktapeException(String detailMessage) {
super(detailMessage);
}
}