org.lol.reddit.common.General.java Source code

Java tutorial

Introduction

Here is the source code for org.lol.reddit.common.General.java

Source

/*******************************************************************************
 * This file is part of RedReader.
 *
 * RedReader is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedReader is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedReader.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package org.lol.reddit.common;

import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.*;
import android.util.Log;
import android.util.TypedValue;
import android.widget.Toast;
import org.apache.http.StatusLine;
import org.holoeverywhere.app.Activity;
import org.holoeverywhere.app.AlertDialog;
import org.holoeverywhere.preference.SharedPreferences;
import org.lol.reddit.R;
import org.lol.reddit.activities.BugReportActivity;
import org.lol.reddit.cache.RequestFailureType;
import org.lol.reddit.fragments.ErrorPropertiesDialog;
import org.lol.reddit.reddit.APIResponseHandler;

import java.io.*;
import java.net.URI;
import java.security.MessageDigest;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class General {

    public static final Handler UI_THREAD_HANDLER = new Handler(Looper.getMainLooper());

    private static long lastBackPress = -1;

    public static boolean onBackPressed() {

        if (lastBackPress < SystemClock.uptimeMillis() - 300) {
            lastBackPress = SystemClock.uptimeMillis();
            return true;
        }

        return false;
    }

    private static Typeface monoTypeface;

    public static Typeface getMonoTypeface(Context context) {

        if (monoTypeface == null) {
            monoTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/VeraMono.ttf");
        }

        return monoTypeface;
    }

    public static Message handlerMessage(int what, Object obj) {
        final Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        return msg;
    }

    public static void moveFile(final File src, final File dst) throws IOException {

        if (!src.renameTo(dst)) {

            copyFile(src, dst);

            if (!src.delete()) {
                src.deleteOnExit();
            }
        }
    }

    public static void copyFile(final File src, final File dst) throws IOException {

        final FileInputStream fis = new FileInputStream(src);
        final FileOutputStream fos = new FileOutputStream(dst);

        copyFile(fis, fos);
    }

    public static void copyFile(final InputStream fis, final File dst) throws IOException {
        final FileOutputStream fos = new FileOutputStream(dst);
        copyFile(fis, fos);
    }

    public static void copyFile(final InputStream fis, final OutputStream fos) throws IOException {

        final byte[] buf = new byte[32 * 1024];

        int bytesRead;
        while ((bytesRead = fis.read(buf)) > 0) {
            fos.write(buf, 0, bytesRead);
        }

        fis.close();
        fos.close();
    }

    public static boolean isCacheDiskFull(final Context context) {
        final StatFs stat = new StatFs(getBestCacheDir(context).getPath());
        return (long) stat.getBlockSize() * (long) stat.getAvailableBlocks() < 128 * 1024 * 1024;
    }

    public static File getBestCacheDir(final Context context) {

        final File externalCacheDir = context.getExternalCacheDir();

        if (externalCacheDir != null) {
            return externalCacheDir;
        }

        return context.getCacheDir();
    }

    public static int dpToPixels(final Context context, final float dp) {
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                context.getResources().getDisplayMetrics()));
    }

    public static void quickToast(final Context context, final int textRes) {
        quickToast(context, context.getString(textRes));
    }

    public static void quickToast(final Context context, final String text) {
        UI_THREAD_HANDLER.post(new Runnable() {
            public void run() {
                Toast.makeText(context, text, Toast.LENGTH_LONG).show();
            }
        });
    }

    public static void quickToast(final Context context, final String text, final int duration) {
        UI_THREAD_HANDLER.post(new Runnable() {
            public void run() {
                Toast.makeText(context, text, duration).show();
            }
        });
    }

    public static boolean isTablet(final Context context, final SharedPreferences sharedPreferences) {

        final PrefsUtility.AppearanceTwopane pref = PrefsUtility.appearance_twopane(context, sharedPreferences);

        switch (pref) {
        case AUTO:
            return (context.getResources().getConfiguration().screenLayout
                    & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
        case NEVER:
            return false;
        case FORCE:
            return true;
        default:
            BugReportActivity.handleGlobalError(context, "Unknown AppearanceTwopane value " + pref.name());
            return false;
        }
    }

    public static boolean isConnectionWifi(final Context context) {
        final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        return info != null && info.isConnected();
    }

    public static RRError getGeneralErrorForFailure(Context context, RequestFailureType type, Throwable t,
            StatusLine status, String url) {

        final int title, message;

        switch (type) {
        case CANCELLED:
            title = R.string.error_cancelled_title;
            message = R.string.error_cancelled_message;
            break;
        case PARSE:
            title = R.string.error_parse_title;
            message = R.string.error_parse_message;
            break;
        case CACHE_MISS:
            title = R.string.error_unexpected_cache_title;
            message = R.string.error_unexpected_cache_message;
            break;
        case STORAGE:
            title = R.string.error_unexpected_storage_title;
            message = R.string.error_unexpected_storage_message;
            break;
        case CONNECTION:
            // TODO check network and customise message
            title = R.string.error_connection_title;
            message = R.string.error_connection_message;
            break;
        case MALFORMED_URL:
            title = R.string.error_malformed_url_title;
            message = R.string.error_malformed_url_message;
            break;
        case DISK_SPACE:
            title = R.string.error_disk_space_title;
            message = R.string.error_disk_space_message;
            break;
        case REQUEST:

            if (status != null) {
                switch (status.getStatusCode()) {
                case 403:
                    title = R.string.error_403_title;
                    message = R.string.error_403_message;
                    break;
                case 404:
                    title = R.string.error_404_title;
                    message = R.string.error_404_message;
                    break;
                case 502:
                case 503:
                case 504:
                    title = R.string.error_redditdown_title;
                    message = R.string.error_redditdown_message;
                    break;
                default:
                    title = R.string.error_unknown_api_title;
                    message = R.string.error_unknown_api_message;
                    break;
                }
            } else {
                title = R.string.error_unknown_api_title;
                message = R.string.error_unknown_api_message;
            }

            break;
        case REDDIT_REDIRECT:
            title = R.string.error_403_title;
            message = R.string.error_403_message;
            break;

        default:
            title = R.string.error_unknown_title;
            message = R.string.error_unknown_message;
            break;
        }

        return new RRError(context.getString(title), context.getString(message), t, status, url);
    }

    public static RRError getGeneralErrorForFailure(Context context, final APIResponseHandler.APIFailureType type) {

        final int title, message;

        switch (type) {

        case INVALID_USER:
            title = R.string.error_403_title;
            message = R.string.error_403_message;
            break;

        case BAD_CAPTCHA:
            title = R.string.error_bad_captcha_title;
            message = R.string.error_bad_captcha_message;
            break;

        case NOTALLOWED:
            title = R.string.error_403_title;
            message = R.string.error_403_message;
            break;

        case SUBREDDIT_REQUIRED:
            title = R.string.error_subreddit_required_title;
            message = R.string.error_subreddit_required_message;
            break;

        default:
            title = R.string.error_unknown_api_title;
            message = R.string.error_unknown_api_message;
            break;
        }

        return new RRError(context.getString(title), context.getString(message));
    }

    // TODO add button to show more detail
    public static void showResultDialog(final Activity context, final RRError error) {
        UI_THREAD_HANDLER.post(new Runnable() {
            public void run() {
                final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
                alertBuilder.setNeutralButton(R.string.dialog_close, null);
                alertBuilder.setNegativeButton(R.string.button_moredetail, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        ErrorPropertiesDialog.newInstance(error).show(context);
                    }
                });
                alertBuilder.setTitle(error.title);
                alertBuilder.setMessage(error.message);
                alertBuilder.create().show();
            }
        });
    }

    private static final Pattern urlPattern = Pattern
            .compile("^(https?)://([^/]+)/+([^\\?#]+)((?:\\?[^#]+)?)((?:#.+)?)$");

    public static URI uriFromString(String url) {

        try {
            return new URI(url);

        } catch (Throwable t1) {
            try {

                Log.i("RR DEBUG uri", "Beginning aggressive parse of '" + url + "'");

                final Matcher urlMatcher = urlPattern.matcher(url);

                if (urlMatcher.find()) {

                    final String scheme = urlMatcher.group(1);
                    final String authority = urlMatcher.group(2);
                    final String path = urlMatcher.group(3).length() == 0 ? null : "/" + urlMatcher.group(3);
                    final String query = urlMatcher.group(4).length() == 0 ? null : urlMatcher.group(4);
                    final String fragment = urlMatcher.group(5).length() == 0 ? null : urlMatcher.group(5);

                    try {
                        return new URI(scheme, authority, path, query, fragment);
                    } catch (Throwable t3) {

                        if (path != null && path.contains(" ")) {
                            return new URI(scheme, authority, path.replace(" ", "%20"), query, fragment);
                        } else {
                            return null;
                        }
                    }

                } else {
                    return null;
                }

            } catch (Throwable t2) {
                return null;
            }
        }
    }

    public static String sha1(final byte[] plaintext) {

        final MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("SHA-1");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        digest.update(plaintext, 0, plaintext.length);
        final byte[] hash = digest.digest();
        final StringBuilder result = new StringBuilder(hash.length * 2);
        for (byte b : hash)
            result.append(String.format("%02X", b));
        return result.toString();
    }

    // Adapted from Android:
    // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/net/Uri.java?av=f
    public static Set<String> getUriQueryParameterNames(final Uri uri) {

        if (uri.isOpaque()) {
            throw new UnsupportedOperationException("This isn't a hierarchical URI.");
        }

        final String query = uri.getEncodedQuery();
        if (query == null) {
            return Collections.emptySet();
        }

        final Set<String> names = new LinkedHashSet<String>();
        int pos = 0;
        while (pos < query.length()) {
            int next = query.indexOf('&', pos);
            int end = (next == -1) ? query.length() : next;

            int separator = query.indexOf('=', pos);
            if (separator > end || separator == -1) {
                separator = end;
            }

            String name = query.substring(pos, separator);
            names.add(Uri.decode(name));

            // Move start to end of name.
            pos = end + 1;
        }

        return Collections.unmodifiableSet(names);
    }

    public static int divideCeil(int num, int divisor) {
        return (num + divisor - 1) / divisor;
    }

    public static void checkThisIsUIThread() {
        if (!isThisUIThread()) {
            throw new RuntimeException("Called from invalid thread");
        }
    }

    public static boolean isThisUIThread() {
        return Looper.getMainLooper().getThread() == Thread.currentThread();
    }

    public static <E> List<E> listOfOne(E obj) {
        final ArrayList<E> result = new ArrayList<E>(1);
        result.add(obj);
        return result;
    }
}