at.diamonddogs.util.Utils.java Source code

Java tutorial

Introduction

Here is the source code for at.diamonddogs.util.Utils.java

Source

/*
 * Copyright (C) 2012, 2013 the diamond:dogs|group
 *
 * 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 at.diamonddogs.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Array;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.apache.commons.codec.binary.Hex;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Process;
import android.util.Base64;

import at.diamonddogs.data.adapter.database.DatabaseAdapter;

/**
 * Collection of general util methods
 */
public class Utils {

    private static final String TAG = Utils.class.getSimpleName();

    /**
     * Returns an array
     *
     * @param <T>    generic type of the items to place into an array
     * @param clazz  the class of generic type <T>
     * @param values an arbitrary number of values
     * @return an array containing all values passed to this method
     * @deprecated do not use this method, the implementation doesn't make a lot
     * of sense and furthermore, the whole method is somewhat
     * pointless.
     */
    @Deprecated
    public static <T> T[] asArray(Class<T> clazz, T... values) {
        @SuppressWarnings("unchecked")
        T[] array = (T[]) Array.newInstance(clazz, values.length);
        for (int i = 0; i < values.length; i++) {
            array[i] = values[i];
        }
        return array;
    }

    /**
     * Checks if a {@link Collection} is not <code>null</code> and not empty
     *
     * @param collection the collection to check
     * @return <code>true</code> if the collection wasn't null and is not empty,
     * <code>false</code> otherwise
     */
    public static boolean isEmpty(Collection<?> collection) {
        return (collection == null || collection.size() == 0);
    }

    /**
     * Checks if an is not <code>null</code> and not empty
     *
     * @param <T>   generic type of the array
     * @param array the array to check
     * @return <code>true</code> if the array wasn't null and is not empty,
     * <code>false</code> otherwise
     */
    public static <T> boolean isEmptyArray(T[] array) {
        return array == null || array.length == 0;
    }

    /**
     * Creates a {@link List} from a {@link Cursor}
     *
     * @param <T>             the generic type of the {@link List}
     * @param cursor          the {@link Cursor} to be converted to a {@link List}
     * @param databaseAdapter the {@link DatabaseAdapter} that will be used for conversion
     * @return a {@link List} containing objects created from the input
     * {@link Cursor}
     */
    public static <T> List<T> convertCursorToList(Cursor cursor, DatabaseAdapter<T> databaseAdapter) {
        List<T> list = new ArrayList<>();
        if (!checkCursor(cursor)) {
            return null;
        }
        cursor.moveToFirst();
        do {
            list.add(databaseAdapter.deserialize(cursor));
        } while (cursor.moveToNext());
        return list;
    }

    /**
     * Creates a {@link String} {@link List} from a {@link Cursor}
     *
     * @param cursor the input {@link Cursor}
     * @param name   the name of the colum
     * @return a {@link String} {@link List}
     */
    public static List<String> convertColumnToList(Cursor cursor, String name) {
        List<String> list = new ArrayList<>();
        if (!checkCursor(cursor)) {
            return null;
        }
        cursor.moveToFirst();
        do {
            list.add(cursor.getString(cursor.getColumnIndex(name)));
        } while (cursor.moveToNext());

        return list;
    }

    /**
     * Get available cache directory
     *
     * @param context a {@link Context}
     * @return a {@link File} pointing to a the external or internal cache
     * directory
     */
    public static File getCacheDir(Context context) {
        File path = context.getExternalCacheDir();
        if (path == null) {
            path = context.getCacheDir();
        }
        return path;
    }

    /**
     * Brings up the MAIN/LAUNCHER activity and clears the top
     *
     * @param context a {@link Context}
     */
    public static void returnToHome(Context context) {
        PackageManager pm = context.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setPackage(context.getPackageName());
        List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
        Intent homeIntent = new Intent("android.intent.action.MAIN");
        homeIntent.addCategory("android.intent.category.LAUNCHER");
        homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        homeIntent.setComponent(new ComponentName(context.getPackageName(), activities.get(0).activityInfo.name));
        context.startActivity(homeIntent);
    }

    /**
     * Checks if a timestamp (ms) is in the current month
     *
     * @param when a ms timestamp
     * @return <code>true</code> if it is <code>false</code> otherwise
     */
    public static boolean isSameMonth(long when) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(when);

        // cal.get(FIELD) does not work :( fields are not recomputed
        int thenYear = tmp.get(Calendar.YEAR);
        int thenMonth = tmp.get(Calendar.MONTH);

        tmp.setTimeInMillis(System.currentTimeMillis());
        int nowYear = tmp.get(Calendar.YEAR);
        int nowMonth = tmp.get(Calendar.MONTH);

        Log.d(TAG, "comparing: " + nowMonth + "." + nowYear + " / " + thenMonth + "." + thenYear);
        return (thenYear == nowYear) && (thenMonth == nowMonth);
    }

    /**
     * Computes a MD5 hash from an input string
     *
     * @param input the input string
     * @return the MD5 hash or <code>null</code> if an error occured
     */
    public static String getMD5Hash(String input) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
            return new String(Hex.encodeHex(md.digest(input.getBytes())));
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        return null;
    }

    /**
     * Creates and fills an {@link Integer} array with integer values
     *
     * @param to size of array / max number to be added to array
     * @return an {@link Integer} array
     */
    public static Integer[] getDigitArray(int to) {
        to++;
        Integer[] ret = new Integer[to];
        for (int i = 0; i < to; i++) {
            ret[i] = i;
        }
        return ret;
    }

    /**
     * Computes a MD5 hash from an byte array
     *
     * @param data the input data
     * @return the MD5 hash or <code>null</code> if an error occured
     */
    public static String getMD5Hash(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            return new String(Hex.encodeHex(md.digest(data)));
        } catch (Throwable tr) {
            Log.w(TAG, "Could not md5 data");
            return null;
        }
    }

    /**
     * Checks a cursor for validity
     *
     * @param c the {@link Cursor} to check
     * @return <code>true</code> if the cursor is not <code>null</code>, not
     * closed and not empty, <code>false</code> otherwise
     */
    public static boolean checkCursor(Cursor c) {
        if (c == null || c.isClosed()) {
            return false;
        }

        if (c.getCount() <= 0) {
            c.close();
            return false;
        }
        return true;
    }

    /**
     * String to base64
     *
     * @param inMsg the message to be converted to base64
     * @return the base64 string
     */
    public static String encrypt(String inMsg) {
        return encrypt(inMsg.getBytes());
    }

    /**
     * Byte array to base64
     *
     * @param inMsg the message to be converted to base64
     * @return the base64 string
     */
    public static String encrypt(byte[] inMsg) {
        return Base64.encodeToString(inMsg, Base64.DEFAULT);
    }

    /**
     * Base64 string to string
     *
     * @param inMsg the message to be converted from base64
     * @return the string
     */
    public static String decrypt(String inMsg) {
        return decrypt(inMsg.getBytes());
    }

    /**
     * Base64 byte array to string
     *
     * @param encMsg the message to be converted from base64
     * @return the string
     */
    public static String decrypt(byte[] encMsg) {
        return new String(Base64.decode(encMsg, Base64.DEFAULT));
    }

    /**
     * Checks if the current process is a foreground process (visible by the
     * user)
     *
     * @param context a {@link Context}
     * @return <code>true</code> if the process is visible, <code>false</code>
     * otherwise
     */
    public static boolean isInForground(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        for (RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_VISIBLE
                    && appProcess.pid == Process.myPid()) {
                Log.i(TAG, "visible");
                return true;
            }
        }
        Log.i(TAG, "Running in background");
        return false;
    }

    /**
     * Converts input values to a {@link Calendar}
     *
     * @param dayOfWeek
     * @param hourOfDay
     * @param minute
     * @param second
     * @return a {@link Calendar}r with the provided date
     */
    public static final Calendar getScheduledDate(int dayOfWeek, int hourOfDay, int minute, int second) {
        Calendar c = Calendar.getInstance();
        int weekDay = c.get(Calendar.DAY_OF_WEEK);
        int days = dayOfWeek - weekDay;
        if (days < 0) {
            days += 7;
        }
        c.add(Calendar.DAY_OF_YEAR, days);
        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, second);
        return c;
    }

    /**
     * Checks if the current process is a foreground process and kills it if it
     * is not
     *
     * @param c a {@link Context}
     */
    public static final void commitCarefulSuicide(Context c) {
        try {
            if (!new ForegroundCheckTask().execute(c).get()) {
                android.os.Process.killProcess(android.os.Process.myPid());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * Same as {@link Utils#commitCarefulSuicide(Context)} but threaded (non
     * blocking)
     *
     * @param context
     */
    public static final void commitCarefulSuicideThreaded(final Context context) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ActivityManager activityManager = (ActivityManager) context
                        .getSystemService(Context.ACTIVITY_SERVICE);
                List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
                if (appProcesses == null) {
                    return;
                }

                Log.d(TAG, "app counter: " + appProcesses.size());
                final String packageName = context.getPackageName();
                for (RunningAppProcessInfo appProcess : appProcesses) {
                    Log.d(TAG, "process: " + appProcess.processName);
                    if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                            && appProcess.processName.equals(packageName)) {
                        Log.d(TAG, "isINF: " + true);
                        return;
                    }
                }
                Log.d(TAG, "isINF: " + false);
                commitSuicide();
            }
        }).start();

    }

    /**
     * Kills the process without asking questions
     */
    public static final void commitSuicide() {
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    /**
     * Creates a bitmap from an input uri
     *
     * @param c            a {@link Context}
     * @param uri          an image {@link Uri}
     * @param inSampleSize the sample size to be used when creating the bitmap
     * @return a {@link Bitmap}
     * @throws FileNotFoundException if the image file could not be found
     */
    public static final Bitmap getBitmapFromUri(Context c, Uri uri, int inSampleSize) throws FileNotFoundException {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = inSampleSize;
        return BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, options);
    }

    /**
     * Creates a bitmap from an input uri
     *
     * @param c   a {@link Context}
     * @param uri an image {@link Uri}
     * @return a {@link Bitmap}
     * @throws FileNotFoundException if the image file could not be found
     */
    public static final Bitmap getBitmapFromUri(Context c, String uri) throws FileNotFoundException {
        return BitmapFactory.decodeStream(c.getContentResolver().openInputStream(Uri.parse(uri)));
    }

    private static class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {

        private static final String TAG = ForegroundCheckTask.class.getSimpleName();

        @Override
        protected Boolean doInBackground(Context... params) {
            final Context context = params[0].getApplicationContext();
            boolean isInForeground = isAppOnForeground(context);
            Log.d(TAG, "isINF: " + isInForeground);
            return isInForeground;
        }

        private boolean isAppOnForeground(Context context) {
            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
            if (appProcesses == null) {
                return false;
            }
            final String packageName = context.getPackageName();
            for (RunningAppProcessInfo appProcess : appProcesses) {
                Log.d(TAG, "process: " + appProcess.processName);
                if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                        && appProcess.processName.equals(packageName)) {
                    return true;
                }
            }
            return false;
        }
    }
}