package com.malcom.library.android.utils; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.provider.Settings.Secure; import android.telephony.TelephonyManager; import android.util.Log; import com.malcom.library.android.MCMDefines; import com.malcom.library.android.module.core.MCMCoreAdapter; import com.malcom.library.android.utils.encoding.base64.Base64; import com.malcom.library.android.utils.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Map; import java.util.UUID; /** * This class will hold utility functions related with Android. * * @author Malcom Ventures, S.L. * @since 2012 * */ public class ToolBox { /** Http Method type for a request. */ public static enum HTTP_METHOD{POST,DELETE,GET}; private static final String LINE_FEED = "\n"; private static final String TAG = "Malcom Android ToolBox"; protected static final String PREFS_FILE = "device_id.xml"; protected static final String PREFS_DEVICE_ID = "device_id"; protected final static String SEPARATOR = ":"; protected static final String MALCOM_HEADER_PREFIX = "x-mcm-"; //--------------- APPLICATION RELATED -------------------------------------------------------------- /** * This method reads the info form the App. Manifest file. * * @return */ public static boolean application_isAppInDebugMode(Context context){ boolean res=false; try{ PackageInfo info = context.getPackageManager().getPackageInfo(context.getApplicationInfo().packageName, 0); int flags=info.applicationInfo.flags; if ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { // development mode res=true; } else { // release mode } }catch(Exception e){ Log.e("IS_DEBUG_MODE:ERROR",e.getMessage(),e); } return res; } // Net Related ----------------------------------------------------------------------------------------------------------------------------- /** * Makes a Http operation. * * This method set a parameters to the request that avoid being waiting * for the server response or once connected, being waiting to receive * the data. * * @param method Method type to execute. @See HTTP_METHOD. * @param url Url of the request. * @param jsonData The body content of the request (JSON). Can be null. * @param headers The headers to include in the request. * @return The content of the request if there is one. * @throws Exception */ public static String net_httpclient_doAction(HTTP_METHOD method, String url, String jsonData, Map<String, String> headers) throws IOException{ String responseData = null; DefaultHttpClient httpclient = new DefaultHttpClient(); // The time it takes to open TCP connection. httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, MCMCoreAdapter.CONNECTION_DEFAULT_TIMEOUT); // Timeout when server does not send data. httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, MCMCoreAdapter.CONNECTION_DEFAULT_DATA_RECEIVAL_TIMEOUT); // Some tuning that is not required for bit tests. //httpclient.getParams().setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false); httpclient.getParams().setParameter(CoreConnectionPNames.TCP_NODELAY, true); HttpRequestBase httpMethod = null; switch(method){ case POST: httpMethod = new HttpPost(url); //Add the body to the request. StringEntity se = new StringEntity(jsonData, "UTF-8"); ((HttpPost)httpMethod).setEntity(se); break; case DELETE: httpMethod = new HttpDelete(url); break; case GET: httpMethod = new HttpGet(url); break; } //Add the headers to the request. if(headers!=null){ for(String header:headers.keySet()){ httpMethod.setHeader(header, headers.get(header)); } } HttpResponse response = httpclient.execute(httpMethod); //Get the response body if there is one. HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); responseData = IOUtils.convertStreamToString(instream); Log.d(MCMDefines.LOG_TAG, "HTTP OPERATION: Read from server - return: " + responseData); } if (response.getStatusLine().getStatusCode() != 200) { throw new IOException("Http operation "+method.name()+" failed with error code " + response.getStatusLine().getStatusCode() + "("+ response.getStatusLine().getReasonPhrase() +")"); } return responseData; } /** * Checks if there is network connectivity. * * @param context * @return */ public static boolean network_haveNetworkConnection(Context context) { boolean haveConnectedWifi = false; boolean haveConnectedMobile = false; ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo[] netInfo = cm.getAllNetworkInfo(); for (NetworkInfo ni : netInfo) { if (ni.getTypeName().equalsIgnoreCase("WIFI")) if (ni.isAvailable() && ni.isConnected()) haveConnectedWifi = true; if (ni.getTypeName().equalsIgnoreCase("MOBILE")) if (ni.isAvailable() && ni.isConnected()) haveConnectedMobile = true; } return haveConnectedWifi || haveConnectedMobile; } /* public static boolean network_isOnline(Activity activity) { NetworkInfo info = ((ConnectivityManager)activity.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); if (info==null || !info.isConnected()) { return false; } if (info.isRoaming()) { // here is the roaming option you can change it if you want to disable internet while roaming, just return false return true; } return true; }*/ // Storage Related ----------------------------------------------------------------------------------------------------------------------------- /** * Gets the application internal storage path. * * @param context * @param file * @return */ public static File storage_getAppInternalStorageFilePath(Context context, String file){ String filePath = context.getFilesDir().getAbsolutePath();//returns current directory. return new File(filePath, file); } /** * This method copies the input to the specified output. * * @param is Input source * @param os Output destiny * @return Total bytes read */ public static int storage_copyStream(InputStream is, OutputStream os, int buffer_size) throws IOException{ int readbytes=0; if(buffer_size<=0){ buffer_size=1024; } try{ byte[] bytes=new byte[buffer_size]; for(;;){ int count=is.read(bytes, 0, buffer_size); if(count==-1) break; os.write(bytes, 0, count); readbytes+=count; } }catch(Exception e){ throw new IOException("Failed to save data ("+e.getMessage()+").",e); } return readbytes; } /** * Saves data to the application internal folder. * * @param context * @param fileName * @param data * @throws Exception */ public static synchronized void storage_storeDataInInternalStorage(Context context, String fileName, byte[] data) throws Exception{ try { /* We have to use the openFileOutput()-method * the ActivityContext provides, to * protect your file from others and * This is done for security-reasons. * We chose MODE_WORLD_READABLE, because * we have nothing to hide in our file */ FileOutputStream fOut = context.openFileOutput(fileName, Context.MODE_WORLD_READABLE); // Write the string to the file fOut.write(data); /* ensure that everything is really written out and close */ fOut.flush(); fOut.close(); } catch (Exception e) { throw new Exception("Error saving data to '" + fileName + "' (internal storage) : "+ e.getMessage(),e); } } /** * Reads data from the application internal storage data folder. * * @param context * @param fileName * @return * @throws Exception */ public static byte[] storage_readDataFromInternalStorage(Context context, String fileName) throws Exception{ FileInputStream fIn; try { fIn = context.openFileInput(fileName); byte[] buffer = new byte[fIn.available()]; fIn.read(buffer); fIn.close(); return buffer; } catch (Exception e) { throw new Exception("Error reading data '" + fileName + "' (internal storage) : "+ e.getMessage(),e); } } /** * Deletes a file from the application internal storage private folder. * * @param context * @param fileName * @throws Exception */ public static void storage_deleteDataFromInternalStorage(Context context, String fileName) throws Exception{ try { context.deleteFile(fileName); } catch (Exception e) { throw new Exception("Error deleting data '" + fileName + "' (internal storage) : "+ e.getMessage(),e); } } /** * Checks if a file exists in the application internal private data folder. * * @param context * @param fileName * @return */ public static boolean storage_checkIfFileExistsInInternalStorage(Context context, String fileName){ try { context.openFileInput(fileName); return true; } catch (FileNotFoundException e) { return false; } } // Media Related ----------------------------------------------------------------------------------------------------------------------------- /** * Loads a Bitmap image form the internal storage. * * @param context * @param fileName * @return * @throws Exception */ public static Bitmap media_loadBitmapFromInternalStorage(Context context, String fileName) throws Exception{ try{ FileInputStream is = context.openFileInput(fileName); Bitmap b = BitmapFactory.decodeStream(is); return b; } catch (Exception e) { throw new Exception("Error reading data '" + fileName + "' (internal storage) : "+ e.getMessage(),e); } } // Device Related ----------------------------------------------------------------------------------------------------------------------------- /** * Get the device Id (an Hexadecimal unique value of 64 bit) * @param context * @return */ public static String device_getId(Context context){ final SharedPreferences prefs = context.getSharedPreferences( PREFS_FILE, 0); final String id = prefs.getString(PREFS_DEVICE_ID, null ); UUID uuid = null; if (id != null) { // Usar esta id de las guardadas en persistencia uuid = UUID.fromString(id); } else { final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID); // http://stackoverflow.com/questions/6106681/android-how-are-you-dealing-with-9774d56d682e549c-android-id try { if (!"9774d56d682e549c".equals(androidId)) { uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8")); } else { // This access to TelephonyManager needs READ_PHONE_STATE. If we get rid of it // probably we won't need that permission anymore (update README.md if so). final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId(); uuid = deviceId!=null ? UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")) : UUID.randomUUID(); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } // Guardamos en persistencia prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit(); } String udid = uuid.toString(); try { udid = md5_calculateMD5(uuid); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } return udid; } // Crypto Related ----------------------------------------------------------------------------------------------------------------------------- /** * Calculates the MD5 of the spcified content. * * @param contentToEncode * @return * @throws NoSuchAlgorithmException */ public static String md5_calculateMD5(String contentToEncode) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(contentToEncode.getBytes()); String result = new String(Base64.encode(digest.digest())); return result; } /** * Calculates the MD5 of the spcified content. * * @param contentToEncode * @return * @throws NoSuchAlgorithmException */ public static String md5_calculateMD5(UUID contentToEncode) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(contentToEncode.toString().getBytes()); String result = new String(Base64.encode(digest.digest())); return result; } /** * Gets the data to be signed in one string. * * @param headers * @param contentType * @param date * @param verb * @param resource * @param contentMd5 * @return */ /*public static String deliveries_getDataToSign(String headers, String contentType, String date, String verb, String resource, String contentMd5) { System.out.println("____________________headers: "+headers); System.out.println("____________________contentType: "+contentType); System.out.println("____________________date: "+date); System.out.println("____________________verb: "+verb); System.out.println("____________________resource: "+resource); System.out.println("____________________contentMd5: "+contentMd5); StringBuilder result = new StringBuilder(); if (contentMd5 == null) contentMd5 = ""; if (contentType == null) contentType = ""; if (date == null) date = ""; if (headers == null) headers = LINE_FEED; result.append(verb).append(LINE_FEED) .append(contentMd5).append(LINE_FEED) .append(contentType).append(LINE_FEED) .append(date).append(LINE_FEED) .append(headers) .append(resource); System.out.println("__________________result: "+result); return result.toString(); }*/ public static String deliveries_getDataToSign(String headers, String contentType, String date, String verb, String resource, String contentMd5) { StringBuilder result = new StringBuilder(); if (contentMd5 == null) { contentMd5 = ""; } if (contentType == null) { contentType = ""; } if (date == null) { date = ""; } if (headers == null) { headers = LINE_FEED; } result.append(verb); result.append(System.getProperty("line.separator")); result.append(contentMd5); result.append(System.getProperty("line.separator")); result.append(contentType); result.append(System.getProperty("line.separator")); result.append(date); result.append(System.getProperty("line.separator")); result.append(headers); result.append(resource); // System.out.println("___________________________________: "+result.toString()); return result.toString(); } public static String getCanonicalizedMalcomHeaders(Map<String, String> headers) { StringBuilder canonicalizedMalcomHeaders = new StringBuilder(); for (String key : new ArrayList<String>(headers.keySet())) { if (key.startsWith(MALCOM_HEADER_PREFIX)) { String headerValue = headers.get(key); canonicalizedMalcomHeaders.append(key); canonicalizedMalcomHeaders.append(SEPARATOR); canonicalizedMalcomHeaders.append(headerValue); canonicalizedMalcomHeaders.append(LINE_FEED); } } if (canonicalizedMalcomHeaders.length() == 0) return null; return canonicalizedMalcomHeaders.toString(); } }