/**
** Copyright (c) 2010 Ushahidi Inc
** All rights reserved
** Contact: team@ushahidi.com
** Website: http://www.ushahidi.com
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: http://www.gnu.org/licenses/lgpl.html.
**
**
** If you have questions regarding the use of this file, please contact
** Ushahidi developers at team@ushahidi.com.
**
**/
package com.ushahidi.android.app.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
import java.util.TimeZone;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.location.Criteria;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.ushahidi.android.app.MainApplication;
import com.ushahidi.android.app.MapBoxTileProvider;
import com.ushahidi.android.app.OpenStreetMapTileProvider;
import com.ushahidi.android.app.Preferences;
import com.ushahidi.android.app.R;
import com.ushahidi.android.app.ui.phone.AboutActivity;
import com.ushahidi.android.app.ui.tablet.AboutFragment;
/**
* This is a utility class that has common methods to be used by most clsses.
*
* @author eyedol
*/
public class Util {
private static NetworkInfo networkInfo;
private static Random random = new Random();
private static final String VALID_EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@"
+ "[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
private static Pattern pattern;
private static Matcher matcher;
public static final int IO_BUFFER_SIZE = 8 * 1024;
/**
* joins two strings together
*
* @param first
* @param second
* @return
*/
public static String joinString(String first, String second) {
return first.concat(second);
}
/**
* Converts a string integer
*
* @param value
* @return
*/
public static int toInt(String value) {
return Integer.parseInt(value);
}
/**
* Capitalize any string given to it.
*
* @param text
* @return capitalized string
*/
public static String capitalizeString(String text) {
if (text.length() == 0)
return text;
return text.substring(0, 1).toUpperCase(Locale.getDefault())
+ text.substring(1).toLowerCase(Locale.getDefault());
}
/**
* Create csv
*
* @param Vector <String> text
* @return csv
*/
public static String implode(Vector<String> text) {
String implode = "";
int i = 0;
for (String value : text) {
implode += i == text.size() - 1 ? value : value + ",";
i++;
}
return implode;
}
/**
* Is there internet connection
*/
public static boolean isConnected(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
networkInfo = connectivity.getActiveNetworkInfo();
// NetworkInfo info
if (networkInfo != null && networkInfo.isConnected()
&& networkInfo.isAvailable()) {
return true;
}
return false;
}
/***
* Gets the state of Airplane Mode. * @param context * @return true if
* enabled.
*/
public static boolean isAirplaneModeOn(Context context) {
return Settings.System.getInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) != 0;
}
/**
* Truncates any given text.
*
* @param String text - the text to be truncated
* @return String
*/
public static String truncateText(String text) {
if (text.length() > 30) {
return text.substring(0, 25).trim() + "";
} else {
return text;
}
}
/**
* Limit a string to defined length
*
* @param int limit - the total length
* @param string limited - the limited string
*/
public static String limitString(String value, int length) {
StringBuilder buf = new StringBuilder(value);
if (buf.length() > length) {
buf.setLength(length);
buf.append(" ...");
}
return buf.toString();
}
public static String formatDate(String dateFormat, String date,
String toFormat) {
return formatDate(dateFormat, date, toFormat, null, null);
}
public static String datePattern(String dateFormat, Date date) {
return android.text.format.DateFormat.format(
"MMMM dd, yyyy 'at' hh:mm:ss aaa", date).toString();
}
/**
* Format date into more readable format.
*
* @param date - the date to be formatted.
* @return String
*/
public static String formatDate(String dateFormat, String date,
String toFormat, Locale fromLocale, Locale toLocale) {
String formatted = "";
DateFormat formatter = fromLocale == null ? new SimpleDateFormat(
dateFormat) : new SimpleDateFormat(dateFormat,
Locale.getDefault());
try {
Date dateStr = formatter.parse(date);
formatted = formatter.format(dateStr);
Date formatDate = formatter.parse(formatted);
formatter = toLocale == null ? new SimpleDateFormat(toFormat,
Locale.getDefault()) : new SimpleDateFormat(toFormat,
toLocale);
formatted = formatter.format(formatDate);
} catch (ParseException e) {
e.printStackTrace();
}
return formatted;
}
public static Date formatDate(String date) {
final SimpleDateFormat PARSER = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault());
try {
return new com.ushahidi.java.sdk.api.json.Date(PARSER.parse(date));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new Date();
}
/**
* For debugging purposes. Append content of a string to a file
*
* @param text
*/
public static void appendLog(String text) {
File logFile = new File(Environment.getExternalStorageDirectory(),
"ush_log.txt");
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
// BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile,
true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Extract Google geocode JSON data
*
* @apram json_data - the json data to be formatted.
* @return String
*/
/*
* public static String getFromLocation(double latitude, double longitude,
* Context context) { String json_data = ""; int status = 0; JSONArray
* jsonArray; try { if (Util.isConnected(context)) { MainGeocoder geoCoder =
* new MainGeocoder(context); json_data = geoCoder.reverseGeocode(latitude,
* longitude); } else { return ""; } if (json_data != null) { jsonObject =
* new JSONObject(json_data); status =
* jsonObject.getJSONObject("Status").getInt("code"); if (status == 200) {
* jsonArray = jsonObject.getJSONArray("Placemark"); return
* jsonArray.getJSONObject(0) .getJSONObject("AddressDetails")
* .getJSONObject("Country") .getJSONObject("AdministrativeArea")
* .getJSONObject("Locality") .getString("LocalityName"); } else { return
* ""; } } } catch (JSONException e) { return ""; // e.printStackTrace(); }
* catch (IOException e) { return ""; } return ""; }
*/
/**
* Show toast
*
* @param Context - the application's context
* @param Int - string resource id
* @return void
*/
public static void showToast(Context context, int i) {
int duration = Toast.LENGTH_LONG;
Toast.makeText(context, i, duration).show();
}
/**
* Validates an email address Credits:
* http://www.mkyong.com/regular-expressions
* /how-to-validate-email-address-with-regular-expression/
*
* @param String - email address to be validated
* @return boolean
*/
public static boolean validateEmail(String emailAddress) {
if (!TextUtils.isEmpty(emailAddress)) {
pattern = Pattern.compile(VALID_EMAIL_PATTERN);
matcher = pattern.matcher(emailAddress);
return matcher.matches();
}
return false;
}
/**
* Delete content of a folder recursively.
*
* @param String path - path to the directory.
* @return void
*/
public static void rmDir(String path) {
File dir = new File(path);
if (dir.isDirectory()) {
String[] children = dir.list();
Log.d("Directory", "dir.list returned some files" + children.length
+ "--");
for (int i = 0; i < children.length; i++) {
File temp = new File(dir, children[i]);
if (temp.isDirectory()) {
rmDir(temp.getName());
} else {
temp.delete();
}
}
dir.delete();
} else {
Log.d("Directory", "This is not a directory" + path);
}
}
/**
* Capitalize each word in a text.
*
* @param String text - The text to be capitalized.
* @return String
*/
public static String capitalize(String text) {
if (text != null) {
String[] words = text.split("\\s");
String capWord = "";
for (String word : words) {
capWord += capitalizeString(word) + " ";
return capWord;
}
}
return "";
}
/** this criteria will settle for less accuracy, high power, and cost */
public static Criteria createCoarseCriteria() {
Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_COARSE);
c.setAltitudeRequired(false);
c.setBearingRequired(false);
c.setSpeedRequired(false);
c.setCostAllowed(true);
c.setPowerRequirement(Criteria.POWER_HIGH);
return c;
}
/** this criteria needs high accuracy, high power, and cost */
public static Criteria createFineCriteria() {
Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);
c.setAltitudeRequired(false);
c.setBearingRequired(false);
c.setSpeedRequired(false);
c.setCostAllowed(true);
c.setPowerRequirement(Criteria.POWER_HIGH);
return c;
}
public static String generateFilename(boolean thumbnail) {
if (thumbnail) {
return randomString() + "_t.jpg";
}
return randomString() + ".jpg";
}
public static String randomString() {
return Long.toString(Math.abs(random.nextLong()), 10);
}
/**
* Checks that the device supports Camera.
*
* @param Context context - The calling activity's context.
* @return boolean - True if it supports otherwise false.
*/
public static boolean deviceHasCamera(Context context) {
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
/**
* Checks that the device supports Camera supports auto focus.
*
* @param Context context - The calling activity's context.
* @return boolean - True if it supports otherwise false.
*/
public static boolean deviceCameraHasAutofocus(Context context) {
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_AUTOFOCUS)) {
return true;
} else {
return false;
}
}
public static boolean isHoneycomb() {
// Can use static final constants like HONEYCOMB, declared in later
// versions
// of the OS since they are inlined at compile time. This is guaranteed
// behavior.
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
public static boolean isTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
public static boolean isHoneycombTablet(Context context) {
return isHoneycomb() && isTablet(context);
}
@SuppressWarnings("deprecation")
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
return display.getWidth();
}
public static String getDateTime() {
DateFormat df = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss", Locale.US);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(new Date());
}
public static String IMEI(Context context) {
TelephonyManager TelephonyMgr = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
return TelephonyMgr.getDeviceId(); // Requires READ_PHONE_STATE
}
/**
* Get the size in bytes of a bitmap.
*
* @param bitmap
* @return size in bytes
*/
@SuppressLint("NewApi")
public static int getBitmapSize(Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bitmap.getByteCount();
}
// Pre HC-MR1
return bitmap.getRowBytes() * bitmap.getHeight();
}
/**
* Check if external storage is built-in or removable.
*
* @return True if external storage is removable (like an SD card), false
* otherwise.
*/
@SuppressLint("NewApi")
public static boolean isExternalStorageRemovable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return Environment.isExternalStorageRemovable();
}
return true;
}
/**
* Get the external app cache directory.
*
* @param context The context to use
* @return The external cache dir
*/
@SuppressLint("NewApi")
public static File getExternalCacheDir(Context context) {
if (hasExternalCacheDir()) {
return context.getExternalCacheDir();
}
// Before Froyo we need to construct the external cache dir ourselves
final String cacheDir = "/Android/data/" + context.getPackageName()
+ "/cache/";
return new File(Environment.getExternalStorageDirectory().getPath()
+ cacheDir);
}
/**
* Check how much usable space is available at a given path.
*
* @param path The path to check
* @return The space available in bytes
*/
@SuppressLint("NewApi")
public static long getUsableSpace(File path) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return path.getUsableSpace();
}
final StatFs stats = new StatFs(path.getPath());
return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
}
/**
* Get the memory class of this device (approx. per-app memory limit)
*
* @param context
* @return
*/
public static int getMemoryClass(Context context) {
return ((ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
}
/**
* Convert a given string to a lower case based on the default locate set on
* the device.
*
* @param text
* @return
*/
public static String toLowerCase(String text, Context context) {
return text
.toLowerCase(context.getResources().getConfiguration().locale);
}
/**
* Sets the reports verification status.
*
* @param verify verify status code.
* @return The verification name
*/
public static String setVerificationStatus(int verify, Context context) {
final String s = verify == 0 ? context.getString(R.string.unverified)
: context.getString(R.string.verified);
return Util.capitalizeString(s);
}
/**
* Calculates the center coordinate of a {@link LatLngBounds}.
*
* @param bounds A {@link LatLngBounds} instance.
* @return the center coordinate of the given bounds.
*/
public static LatLng getCenter(LatLngBounds bounds) {
double n = bounds.northeast.latitude;
double e = bounds.northeast.longitude;
double s = bounds.southwest.latitude;
double w = bounds.southwest.longitude;
double lat = ((n + s) / 2.0);
double lon = ((e + w) / 2.0);
return new LatLng(lat, lon);
}
/**
* Sets which map tile to use
*
* @param context The calling Activity
* @param map The GoogleMap
*/
public static void setMapTile(Context context, GoogleMap map) {
// load preferences
Preferences.loadSettings(context);
TileOverlayOptions osm = new TileOverlayOptions()
.tileProvider(new OpenStreetMapTileProvider());
TileOverlayOptions mapbox = new TileOverlayOptions()
.tileProvider(new MapBoxTileProvider());
final String mapTile = Preferences.mapTiles;
if (map != null) {
map.setMapType(GoogleMap.MAP_TYPE_NONE);
map.addTileOverlay(osm).remove();
map.addTileOverlay(mapbox).remove();
map.clear();
if (mapTile.equals("google")) {
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
} else if (mapTile.equals("osm")) {
map.addTileOverlay(osm);
} else {
map.addTileOverlay(mapbox);
}
}
}
public static void showAbout(final SherlockFragmentActivity mActivity) {
if (Util.isTablet(mActivity.getApplicationContext())) {
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
Fragment prev = mActivity.getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out,
R.anim.slide_right_in, R.anim.slide_right_out);
ft.addToBackStack(null);
// Create and show the dialog.
AboutFragment newFragment = AboutFragment.newInstance();
newFragment.show(ft, "dialog");
} else {
Intent i = new Intent(mActivity.getApplicationContext(), AboutActivity.class);
mActivity.startActivity(i);
mActivity.overridePendingTransition(R.anim.home_enter,
R.anim.home_exit);
}
}
/**
* Check if OS version has built-in external cache dir method.
*
* @return
*/
public static boolean hasExternalCacheDir() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
}
public void log(String message) {
if (MainApplication.LOGGING_MODE)
Log.i(getClass().getName(), message);
}
public void log(String format, Object... args) {
if (MainApplication.LOGGING_MODE)
Log.i(getClass().getName(), String.format(format, args));
}
public void log(String message, Exception ex) {
if (MainApplication.LOGGING_MODE)
Log.e(getClass().getName(), message, ex);
}
}