package com.applang;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import static com.applang.Util.*;
import static com.applang.Util2.*;
public class Util1
{
public static boolean traverse(Cursor cursor, Job<Cursor> job, Object...params) {
if (cursor == null)
return false;
try {
boolean retval = false;
if (cursor.moveToFirst())
do {
if (job != null)
job.perform(cursor, params);
retval = true;
} while (cursor.moveToNext());
return retval;
} catch (Exception e) {
Log.e(TAG, "traversing cursor", e);
return false;
}
finally {
cursor.close();
}
}
public static ValMap getResults(Cursor cursor, final Function<String> key, final Function<Object> value) {
final ValMap map = vmap();
traverse(cursor, new Job<Cursor>() {
public void perform(Cursor c, Object[] params) throws Exception {
String k = key.apply(c);
Object v = value.apply(c);
map.put(k, v);
}
});
return map;
}
public static ValList getStrings(Cursor cursor) {
ValList list = vlist();
for (int i = 0; i < cursor.getColumnCount(); i++) {
list.add(cursor.getString(i));
}
return list;
}
public static LinearLayout linearLayout(Context context, int orientation, int width, int height) {
LinearLayout linear = new LinearLayout(context);
linear.setOrientation(orientation);
linear.setLayoutParams(new LinearLayout.LayoutParams(width, height));
return linear;
}
public static RelativeLayout relativeLayout(Context context, int width, int height) {
RelativeLayout relative = new RelativeLayout(context);
relative.setLayoutParams(new RelativeLayout.LayoutParams(width, height));
return relative;
}
public static ViewGroup.MarginLayoutParams marginLayoutParams(int width, int height, Integer... ltrb) {
ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(width, height);
layoutParams.setMargins(param(0, 0, ltrb), param(0, 1, ltrb), param(0, 2, ltrb), param(0, 3, ltrb));
return layoutParams;
}
public static Object[] iterateViews(ViewGroup viewGroup, int indent, Function<Object[]> func, Object... params) {
if (viewGroup != null) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View view = viewGroup.getChildAt(i);
params = func.apply(view, indent, params);
if (view instanceof ViewGroup) {
iterateViews((ViewGroup) view, indent + 1, func, params);
}
}
}
return params;
}
public static String viewLine(View v, int indent) {
String string = v.getTag() + " : " + v.getClass().getSimpleName();
if (v instanceof LinearLayout) {
LinearLayout l = (LinearLayout) v;
string += TAB +
(l.getOrientation() == LinearLayout.HORIZONTAL ?
"horizontal" : "vertical");
}
string += TAB + v.getLayoutParams();
return indentedLine(string, TAB, indent);
}
public static String viewHierarchy(ViewGroup container) {
String s = viewLine(container, 0);
Object[] params = iterateViews(container,
1,
new Function<Object[]>() {
public Object[] apply(Object... params) {
View v = param(null, 0, params);
int indent = param_Integer(null, 1, params);
Object[] parms = param(null, 2, params);
String s = (String) parms[0];
s += viewLine(v, indent);
parms[0] = s;
return parms;
}
},
objects(s)
);
return param_String("", 0, params);
}
public static View getContentView(Activity activity) {
View rootView = activity.findViewById(android.R.id.content);
ViewGroup viewGroup = (ViewGroup)rootView;
return viewGroup.getChildAt(0);
}
public static String[] providerPackages = strings("com.applang.provider");
public static Predicate<String> isProvider = new Predicate<String>() {
public boolean apply(String t) {
for (int i = 0; i < providerPackages.length; i++) {
if (t.startsWith(providerPackages[i]))
return true;
}
return false;
}
};
@SuppressWarnings("rawtypes")
public static ValList contentAuthorities(String[] packageNames, Object...params) {
ValList list = vlist();
try {
for (String packageName : packageNames) {
Class[] cls = getLocalClasses(packageName, params);
for (Class c : filter(asList(cls), false, new Predicate<Class>() {
public boolean apply(Class c) {
String name = c.getName();
return !name.contains("$")
&& !name.endsWith("Provider");
}
})) {
Object name = c.getDeclaredField("AUTHORITY").get(null);
if (name != null)
list.add(name.toString());
}
}
} catch (Exception e) {
Log.e(TAG, "contentAuthorities", e);
list.addAll(asList(strings(
"com.applang.provider.NotePad",
"com.applang.provider.WeatherInfo",
"com.applang.provider.PlantInfo")));
}
return list;
}
public static Object[] fullProjection(Object flavor) {
try {
Class<?> cls = Class.forName(flavor + "Provider");
Field field = cls.getDeclaredField("FULL_PROJECTION");
if (field == null)
return null;
else
return (Object[]) field.get(null);
} catch (Exception e) {
Log.e(TAG, "fullProjection", e);
return null;
}
}
public static Uri contentUri(String flavor, String path) {
Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(flavor)
.path(path)
.build();
return toStringUri(uri);
}
public static boolean isContentUri(String uriString) {
return uriString.toLowerCase().startsWith(ContentResolver.SCHEME_CONTENT);
}
public static Uri fileUri(String path, String fragment) {
return Uri.parse(path).buildUpon()
.scheme(ContentResolver.SCHEME_FILE)
.fragment(fragment)
.build();
}
public static boolean isFileUri(String uriString) {
return uriString.toLowerCase().startsWith(ContentResolver.SCHEME_FILE);
}
public static boolean isJarUri(String uriString) {
return uriString.toLowerCase().startsWith("jar:");
}
public static Uri toStringUri(Uri uri) {
return Uri.parse(uri.toString());
}
public static String appendId(String uriString, long id) {
return ContentUris.appendId(Uri.parse(uriString).buildUpon(), id).build().toString();
}
public static Long parseId(Long defaultValue, Uri uri) {
try {
return ContentUris.parseId(uri);
} catch (Exception e) {
return defaultValue;
}
}
public static String codeUri(String uriString, boolean decode) {
return decode ? Uri.decode(uriString) : Uri.encode(uriString);
}
public static boolean hasAuthority(Uri uri) {
return uri != null && notNullOrEmpty(uri.getAuthority());
}
public static Uri dbTable(Uri uri, String tableName) {
if (uri == null) return null;
Uri.Builder builder = uri.buildUpon();
if (hasAuthority(uri))
builder = builder.path(tableName);
else
builder = builder.fragment(tableName);
return builder.build();
}
public static String dbLegalize(Object name) {
if (notNullOrEmpty(name))
return stringValueOf(name).replaceAll("[ \\?\\*]", "_");
else
throw new RuntimeException("null or empty name not possible");
}
public static Uri dbTable(String uriString, String tableName) {
return dbTable(Uri.parse(uriString), tableName);
}
public static String dbTableName(Uri uri) {
if (uri == null)
return null;
else if (hasAuthority(uri)) {
boolean hasPath = notNullOrEmpty(uri.getPath());
return hasPath ? uri.getPathSegments().get(0) : "";
}
else
return uri.getFragment();
}
public static String dbTableName(String uriString) {
return dbTableName(Uri.parse(uriString));
}
public static String dbPath(String uriString) {
return Uri.parse(stringValueOf(uriString)).getPath();
}
public static ValMap schema(Context context, Uri uri) {
uri = dbTable(uri, null);
Cursor cursor = context.getContentResolver().query(
uri,
null,
"select name,sql from sqlite_master where type = 'table'",
null,
null);
final ValMap schema = vmap();
traverse(cursor, new Job<Cursor>() {
public void perform(Cursor c, Object[] params) throws Exception {
schema.put(c.getString(0), c.getString(1));
}
});
return schema;
}
public static ValMap table_info(Context context, Uri uri, String tableName) {
final ValMap info = vmap();
if (uri == null || nullOrEmpty(tableName))
return info;
uri = dbTable(uri, null);
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(
uri,
null,
String.format("pragma table_info(%s)", tableName),
null,
null);
info.getList("cid");
info.getList("name");
info.getList("type");
info.getList("notnull");
info.getList("dflt_value");
info.getList("pk");
traverse(cursor, new Job<Cursor>() {
public void perform(Cursor c, Object[] params) throws Exception {
for (int i = 0; i < c.getColumnCount(); i++) {
String columnName = c.getColumnName(i);
ValList column = (ValList) info.get(columnName);
if ("cid".equals(columnName) || "notnull".equals(columnName) || "pk".equals(columnName))
column.add(c.getInt(i));
else
column.add(c.getString(i));
}
}
});
ValList pk = info.getList("pk");
List<Integer> indices = filterIndex(pk, false, new Predicate<Object>() {
public boolean apply(Object t) {
return Integer.valueOf(t.toString()) > 0;
}
});
if (indices.size() == 1) {
pk.set(indices.get(0), -Integer.valueOf(pk.get(indices.get(0)).toString()));
}
ValList fieldNames = info.getList("name");
indices = filterIndex(pk, false, new Predicate<Object>() {
public boolean apply(Object t) {
return Integer.valueOf(t.toString()) < 0;
}
});
if (indices.size() == 1) {
info.put("PRIMARY_KEY", fieldNames.get(indices.get(0)));
}
return info;
}
public static int getFlavorVersion(String flavor, SQLiteDatabase db) {
Object[] params = {00};
traverse(getMetadata(db, flavor), new Job<Cursor>() {
public void perform(Cursor c, Object[] parms) throws Exception {
int index = c.getColumnIndex("version");
parms[0] = c.getInt(index);
}
}, params);
Integer version = (Integer) params[0];
return version;
}
private static Cursor getMetadata(SQLiteDatabase db, String flavor) {
db.execSQL("create table if not exists metadata (flavor text, version integer);");
return db.rawQuery("select * from metadata where flavor=?;", strings(flavor));
}
public static void setFlavorVersion(String flavor, SQLiteDatabase db, int version) {
if (flavor == null)
db.setVersion(version);
ContentValues values = new ContentValues();
values.put("version", version);
if (getFlavorVersion(flavor, db) > 0)
db.update("metadata", values, "flavor=?", strings(flavor));
else {
values.put("flavor", flavor);
db.insert("metadata", null, values);
}
}
public static int version(Context context, Uri uri) {
uri = dbTable(uri, null);
Cursor cursor = context.getContentResolver().query(
uri,
null,
"pragma user_version",
null,
null);
if (cursor != null && cursor.moveToFirst())
return cursor.getInt(0);
else
return 0;
}
public static ValList tables(Context context, Uri uri) {
final ValList tables = vlist();
if (uri != null && (!isFileUri(uri.toString()) || notNullOrEmpty(uri.getPath()))) {
uri = dbTable(uri, null);
Cursor cursor = context.getContentResolver().query(uri, null,
"select name from sqlite_master where type = 'table'",
null, null);
traverse(cursor, new Job<Cursor>() {
public void perform(Cursor c, Object[] params) throws Exception {
tables.add(c.getString(0));
}
});
}
return tables;
}
public static boolean table_exists(SQLiteDatabase db, String tableName) {
Object[] params = objects(false, tableName);
traverse(db.rawQuery("select name from sqlite_master where type = 'table'", null),
new Job<Cursor>() {
public void perform(Cursor c, Object[] parms) throws Exception {
String name = param_String("", 1, parms);
if (name.compareToIgnoreCase(c.getString(0)) == 0) {
parms[0] = true;
}
}
}, params);
return param_Boolean(null, 0, params);
}
public static boolean table_upgrade(final SQLiteDatabase db, final String tableName,
final Job<Void> creation, final Object...params)
{
boolean retval = false;
try {
if (table_exists(db, tableName)) {
db.execSQL("ALTER TABLE " + tableName + " RENAME TO temp_" + tableName);
Cursor c = db.rawQuery("select * from temp_" + tableName, null);
Object[] parms = {retval};
traverse(c, new Job<Cursor>() {
public void perform(Cursor c, Object[] parms) throws Exception {
ValList list = vlist();
for (int i = 0; i < c.getColumnCount(); i++) {
list.add(c.getColumnName(i));
}
creation.perform(null, params);
String cols = join(",", list.toArray());
db.execSQL(String.format(
"INSERT INTO %s (%s) SELECT %s from temp_%s",
tableName, cols, cols, tableName));
parms[0] = true;
}
}, parms);
retval = (Boolean) parms[0];
db.execSQL("DROP TABLE temp_" + tableName);
}
if (!retval) {
creation.perform(null, params);
retval = true;
}
}
catch (Exception e) {
Log.e(TAG, "upgrade failed", e);
retval = false;
}
return retval;
}
public static int recordCount(Context context, Uri uri) {
String tableName = dbTableName(uri);
uri = dbTable(uri, null);
Cursor cursor = context.getContentResolver().query(
uri,
null,
"select count(*) from " + tableName,
null,
null);
Object[] params = objects(0);
traverse(cursor, new Job<Cursor>() {
public void perform(Cursor c, Object[] params) throws Exception {
params[0] = c.getInt(0);
}
}, params);
return (Integer)params[0];
}
public static void turnForeignKeys(SQLiteDatabase db, boolean on) {
try {
String sql = String.format("pragma foreign_keys = %s", on ? "ON" : "OFF");
db.rawQuery(sql, null);
}
catch (SQLiteException e) {
Log.e(TAG, "foreign_keys", e);
}
}
public static String databaseName(Object flavor) {
try {
Class<?> c = Class.forName(flavor + "Provider");
return c.getDeclaredField("DATABASE_NAME").get(null).toString();
} catch (Exception e) {
return null;
}
}
public static String[] databases(Activity activity) {
ArrayList<String> list = alist();
ValList authorities = contentAuthorities(providerPackages, activity);
for (Object authority : authorities) {
String name = databaseName(authority);
if (notNullOrEmpty(name))
list.add(name);
}
return toStrings(list);
}
public static File getDatabaseFile(Context context, Uri uri) {
if (hasAuthority(uri)) {
try {
String name = databaseName(uri.getAuthority());
File path = context.getDatabasePath(name);
return path.getCanonicalFile();
} catch (IOException e) {
Log.e(TAG, "getDatabaseFile", e);
return null;
}
}
else if (uri != null)
return new File(uri.getPath());
else
return null;
}
public static ContentValues contentValues(ValMap info, List<Object> projection, Object...items) {
ContentValues values = new ContentValues();
ValList names = info.getList("name");
for (int i = 0; i < projection.size(); i++) {
String name = stringValueOf(projection.get(i));
int index = names.indexOf(name);
Object type = info.getListValue("type", index);
Object item = param(null, i, items);
if ("TEXT".equals(type))
values.put(name, (String) item);
else if ("INTEGER".equals(type))
values.put(name, toLong(null, stringValueOf(item)));
else if ("REAL".equals(type) || "FLOAT".equals(type) || "DOUBLE".equals(type))
values.put(name, toDouble(Double.NaN, stringValueOf(item)));
else if ("BLOB".equals(type))
values.put(name, (byte[]) item);
else
values.putNull(name);
}
return values;
}
public static ContentValues contentValuesFromQuery(String uriString, Object...items) {
ContentValues values = new ContentValues();
Uri uri = Uri.parse(uriString);
if (uri != null) {
String query = uri.getQuery();
if (query != null) {
ValList list = split(query, "&");
for (int i = 0; i < list.size(); i++) {
String[] parts = list.get(i).toString().split("=");
Object item = param(null, i, items);
if ("TEXT".equals(parts[1]))
values.put(parts[0], (String) item);
else if ("INTEGER".equals(parts[1]))
values.put(parts[0], toLong(null, stringValueOf(item)));
else if ("REAL".equals(parts[1]))
values.put(parts[0],
toDouble(Double.NaN, stringValueOf(item)));
else if ("BLOB".equals(parts[1]))
values.put(parts[0], (byte[]) item);
else
values.putNull(parts[0]);
}
}
}
return values;
}
public static final String[] PARENS = {"(", ")"};
public static final String[] BRACKETS = {"[", "]"};
public static final String[] BRACES = {"{", "}"};
public static boolean isNULL(Object value) {
return JSONObject.NULL.equals(value);
}
@SuppressWarnings("unchecked")
public static Object walkJSON(Object[] path, Object json, Function<Object> filter, Object...params) {
Object object = json;
if (path == null)
path = objects();
if (json instanceof JSONObject) {
JSONObject jo = (JSONObject) json;
ValMap map = vmap();
Iterator<String> it = jo.keys();
while (it.hasNext()) {
String key = it.next();
Object value = null;
try {
value = jo.get(key);
} catch (JSONException e) {}
Object[] path2 = arrayappend(path, key);
String string = String.valueOf(value);
if (string.startsWith(BRACKETS[0])) {
try {
JSONArray jsonArray = jo.getJSONArray(key);
value = walkJSON(path2, jsonArray, filter, params);
} catch (JSONException e) {
value = walkJSON(path2, value, filter, params);
}
}
else if (string.startsWith(BRACES[0])) {
try {
JSONObject jsonObject = jo.getJSONObject(key);
value = walkJSON(path2, jsonObject, filter, params);
} catch (JSONException e) {
value = walkJSON(path2, value, filter, params);
}
}
else
value = walkJSON(path2, value, filter, params);
map.put(key, value);
}
object = map;
}
else if (json instanceof JSONArray) {
JSONArray ja = (JSONArray) json;
ValList list = vlist();
for (int i = 0; i < ja.length(); i++) {
try {
Object value = ja.get(i);
list.add(walkJSON(arrayappend(path, i), value, filter, params));
} catch (JSONException e) {}
}
object = list;
}
else if (filter != null)
object = filter.apply(path, json, params);
return isNULL(object) ? null : object;
}
@SuppressWarnings("rawtypes")
public static void toJSON(Object[] path, JSONStringer stringer, String string, Object object, Function<Object> filter, Object...params) throws Exception {
if (notNullOrEmpty(string))
stringer.key(string);
if (path == null)
path = objects();
if (object instanceof Map) {
stringer.object();
Map map = (Map) object;
for (Object key : map.keySet()) {
toJSON(arrayappend(path, key), stringer, key.toString(), map.get(key), filter, params);
}
stringer.endObject();
}
else if (object instanceof Collection) {
stringer.array();
int i = 0;
Iterator it = ((Collection) object).iterator();
while (it.hasNext()) {
toJSON(arrayappend(path, i), stringer, "", it.next(), filter, params);
i++;
}
stringer.endArray();
}
else {
if (filter != null)
object = filter.apply(path, object, params);
stringer.value(object);
}
}
public static String readAsset(Context context, String fileName) {
StringBuffer sb = new StringBuffer();
try {
AssetManager am = context.getResources().getAssets();
InputStream is = am.open( fileName );
while( true ) {
int c = is.read();
if( c < 0 )
break;
sb.append( (char)c );
}
} catch (Exception e) {
Log.e(TAG, "readAsset", e);
}
return sb.toString();
}
public static byte[] getBytes(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, 0, stream);
return stream.toByteArray();
}
public static Bitmap getBitmap(byte[] bytes) {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
}