me.zhang.bingo.Utility.java Source code

Java tutorial

Introduction

Here is the source code for me.zhang.bingo.Utility.java

Source

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 me.zhang.bingo;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import me.zhang.bingo.muzei.MuzeiInstallationReceiver.MuzeiInstallationStatus;
import me.zhang.bingo.sync.BingoSyncAdapter;
import timber.log.Timber;

import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Environment.getExternalStorageDirectory;
import static android.preference.PreferenceManager.getDefaultSharedPreferences;
import static android.support.v4.content.ContextCompat.checkSelfPermission;
import static me.zhang.bingo.muzei.MuzeiInstallationReceiver.MUZEI_INSTALLED;
import static me.zhang.bingo.muzei.MuzeiInstallationReceiver.MUZEI_NOT_INSTALLED;

public class Utility {

    private static final String PREFERENCE_EXTRACTS = "extracts_preferences";

    // Format used for storing dates in the database.  ALso used for converting those strings
    // back into date objects for comparison/processing.
    public static final String DATE_FORMAT = "yyyyMMdd";

    private Utility() {
        //no instance
    }

    /**
     * Checks if the app has permission to write to device storage
     * <p>
     * If the app does not has permission then the user will be prompted to grant permissions
     *
     * @param context Context
     */
    public static boolean hasStoragePermissions(Context context) {
        // Check if we have write permission
        int permission = checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        return permission == PackageManager.PERMISSION_GRANTED;
    }

    public static String extractQueryParam(String url) {
        Uri uri = Uri.parse(url);
        String query = uri.getQueryParameter("q");
        Timber.i("query -> " + query);
        return query;
    }

    /**
     * Whether url is valid.
     *
     * @param rawUrl Raw url
     * @return Is valid.
     */
    public static boolean matchUrl(String rawUrl) {
        Pattern p = Pattern.compile("^(http://|https://)?(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?$");
        Matcher m = p.matcher(rawUrl);
        return m.matches();
    }

    /**
     * Returns true if the network is available or about to become available.
     *
     * @param c Context used to get the ConnectivityManager
     * @return true if the network is available
     */
    public static boolean isNetworkAvailable(Context c) {
        ConnectivityManager cm = (ConnectivityManager) c.getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    /**
     * This method converts dp unit to equivalent pixels, depending on device density.
     *
     * @param dp      A value in dp (density independent pixels) unit. Which we need to convert
     *                into pixels
     * @param context Context to get resources and device specific display metrics
     * @return A float value to represent px equivalent to dp depending on device density
     */
    public static float convertDpToPixel(float dp, Context context) {
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    }

    /**
     * This method converts device specific pixels to density independent pixels.
     *
     * @param px      A value in px (pixels) unit. Which we need to convert into db
     * @param context Context to get resources and device specific display metrics
     * @return A float value to represent dp equivalent to px value
     */
    public static float convertPixelsToDp(float px, Context context) {
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    }

    public static boolean isMuzeiInstalled(Context context) {
        PackageManager pm = context.getPackageManager();
        try {
            pm.getPackageInfo(context.getString(R.string.muzei_package), PackageManager.GET_ACTIVITIES);
            Utility.setMuzeiInstallationStatus(context, MUZEI_INSTALLED);
            return true;
        } catch (PackageManager.NameNotFoundException ignored) {
        }
        Utility.setMuzeiInstallationStatus(context, MUZEI_NOT_INSTALLED);
        return false;
    }

    @SuppressWarnings("WrongConstant")
    @MuzeiInstallationStatus
    public static int getMuzeiInstallationStatus(Context context) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getInt(context.getString(R.string.pref_muzei_status_key), MUZEI_NOT_INSTALLED);
    }

    public static void setMuzeiInstallationStatus(Context context, @MuzeiInstallationStatus int status) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putInt(context.getString(R.string.pref_muzei_status_key), status);
        editor.apply();
    }

    public static void setShowMuzeiInstallationDialog(Context context, boolean shouldShow) {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = sp.edit();
        editor.putBoolean(context.getString(R.string.show_muzei_intallation_key), shouldShow);
        editor.apply();
    }

    public static boolean shouldShowMuzeiInstallationDialog(Context context) {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        return sp.getBoolean(context.getString(R.string.show_muzei_intallation_key), true);
    }

    public static String getExtractFromPreference(Context context, String query) {
        SharedPreferences sp = context.getSharedPreferences(PREFERENCE_EXTRACTS, MODE_PRIVATE);
        return sp.getString(query, ""); // Default value: ""
    }

    public static void putExtractToPreference(Context context, String query, String extract) {
        SharedPreferences sp = context.getSharedPreferences(PREFERENCE_EXTRACTS, MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(query, extract);
        editor.apply(); // android.app.SharedPreferencesImpl.EditorImpl#apply
    }

    /**
     * Clear all extracts.
     *
     * @param context Supplied context.
     */
    public static void clearExtractPreference(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PREFERENCE_EXTRACTS, MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.apply();
    }

    /*
    Note: register and unregister preference change listener always appear in pairs.
     */

    public static void registerExtractPreferenceChangeListener(Context context,
            SharedPreferences.OnSharedPreferenceChangeListener listener) {
        SharedPreferences sp = context.getSharedPreferences(PREFERENCE_EXTRACTS, MODE_PRIVATE);
        sp.registerOnSharedPreferenceChangeListener(listener);
    }

    public static void unregisterExtractPreferenceChangeListener(Context context,
            SharedPreferences.OnSharedPreferenceChangeListener listener) {
        SharedPreferences sp = context.getSharedPreferences(PREFERENCE_EXTRACTS, MODE_PRIVATE);
        sp.unregisterOnSharedPreferenceChangeListener(listener);
    }

    @SuppressWarnings("WrongConstant")
    @BingoSyncAdapter.ImageStatus
    public static int getImageStatus(Context context) {
        return getDefaultSharedPreferences(context).getInt(context.getString(R.string.pref_image_status_key),
                BingoSyncAdapter.IMAGE_STATUS_UNKNOWN);
    }

    public static void applyCustomFont(Context context, TextView targetView) {
        Typeface font = Typeface.createFromAsset(context.getAssets(), "IndieFlower.ttf");
        targetView.setTypeface(font);
    }

    public static Locale getChoosedLocale(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String language = prefs.getString(context.getString(R.string.pref_language_key),
                context.getString(R.string.pref_language_default));
        Timber.i("Language: %s", language);

        // Auto switch app language
        if (context.getString(R.string.pref_language_auto).equals(language)) {
            return Locale.getDefault();
        }
        String[] langAndCountry = language.split("-");
        return new Locale(langAndCountry[0], langAndCountry[1]);
    }

    public static void applyAppLanguage(Context context) {
        Locale myLocale = Utility.getChoosedLocale(context);
        Resources res = context.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        Configuration conf = res.getConfiguration();
        conf.locale = myLocale;
        res.updateConfiguration(conf, dm);
    }

    /**
     * Replace resolution related part of a image url.
     * For example:
     * http://www.bing.com/az/hprichbg/rb/PyramidsOfMeroe_ZH-CN10667861825_1920x1080.jpg
     * ->
     * http://www.bing.com/az/hprichbg/rb/PyramidsOfMeroe_ZH-CN10667861825_800x480.jpg
     *
     * @param context to get SharedPreferences
     * @param rawUrl  input url.
     * @return parsed url.
     */
    public static String getChoosedImageUrl(Context context, String rawUrl) {
        final String resolution = getChoosedImageResolution(context);
        final int lastIndexOfUnderscore = rawUrl.lastIndexOf('_');
        final int lastIndexOfDot = rawUrl.lastIndexOf('.');

        return rawUrl.substring(0, lastIndexOfUnderscore + 1) + resolution
                + rawUrl.substring(lastIndexOfDot, rawUrl.length());
    }

    public static String getChoosedImageResolution(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        final String chooseResolutionKey = context.getString(R.string.pref_resolution_key);
        return prefs.getString(chooseResolutionKey, context.getString(R.string.pref_resolution_default));
    }

    public static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap;

        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            if (bitmapDrawable.getBitmap() != null) {
                return bitmapDrawable.getBitmap();
            }
        }

        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
            // Single color bitmap will be created of 1x1 pixel.
            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
        } else {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
                    Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * Save image with specific file name to local disk.
     *
     * @param imageToSave   Bitmap to save.
     * @param imageFileName Image name.
     * @return Saved image file path.
     */
    @SuppressWarnings("WeakerAccess")
    public static String createDirectoryAndSaveImage(Bitmap imageToSave, String imageFileName) {
        File bingoDirectory = new File(getExternalStorageDirectory() + File.separator + "Bingo");
        if (!bingoDirectory.exists()) {
            boolean mkdirsResult = bingoDirectory.mkdirs();
            Timber.i("Make directory %s", mkdirsResult ? "succeed" : "failed");
        }

        final String imageExtension = ".jpg";
        if (!imageFileName.contains(imageExtension)) {
            imageFileName = imageFileName + imageExtension;
        }

        final File imageFile = new File(bingoDirectory, imageFileName);
        final String absImagePath = imageFile.getAbsolutePath();
        if (imageFile.exists()) {
            // Just return this image path.
            return absImagePath;
        }

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(imageFile);
            boolean success = imageToSave.compress(Bitmap.CompressFormat.JPEG, 100, out);
            return success ? absImagePath : null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * Invoke the system's media scanner to add your media file to the Media Provider's database,
     * making it available in the Android Gallery application and to other apps.
     *
     * @param context      Context to send broadcast.
     * @param mediaFileUri Your media file.
     */
    @SuppressWarnings("WeakerAccess")
    public static void notifyMediaScannerToAddYourFile(@NonNull Context context, @Nullable Uri mediaFileUri) {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(mediaFileUri);
        context.sendBroadcast(mediaScanIntent);
    }

    /**
     * Helper method to convert the database representation of the date into something to display
     * to users.  As classy and polished a user experience as "20170701" is, we can do better.
     *
     * @param context      Context to use for resource localization
     * @param rawStartDate The date string: "20170701"
     * @return a user-friendly representation of the date.
     */
    public static String getFriendlyDayString(Context context, String rawStartDate) {
        // The day string for forecast uses the following logic:
        // For today: "Today, July 1"
        // For yesterday:  "Yesterday"
        // For all days before that: "Wed Jun 28"

        Time time = new Time();
        time.setToNow();
        long currentTime = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, getChoosedLocale(context));
        long dateInMillis = 0;
        try {
            dateInMillis = sdf.parse(rawStartDate).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int julianDay = Time.getJulianDay(dateInMillis, time.gmtoff);
        int currentJulianDay = Time.getJulianDay(currentTime, time.gmtoff);

        if (julianDay == currentJulianDay) { // Today
            String today = context.getString(R.string.today);
            return context.getString(R.string.format_full_friendly_date, today,
                    getFormattedMonthDay(context, dateInMillis));
        } else if (julianDay == currentJulianDay - 1) { // Yesterday
            return context.getString(R.string.yesterday);
        } else {
            // Otherwise, use the form "Jun 28"
            SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("MMM d", getChoosedLocale(context));
            return shortenedDateFormat.format(dateInMillis);
        }
    }

    /**
     * Converts date in milliseconds to the format "Month day", e.g "June 24".
     *
     * @param dateInMillis The parsed date in milliseconds
     * @return The day in the form of a string formatted "December 6"
     */
    public static String getFormattedMonthDay(Context context, long dateInMillis) {
        SimpleDateFormat monthDayFormat = new SimpleDateFormat("MMMM d", getChoosedLocale(context));
        return monthDayFormat.format(dateInMillis);
    }

    /**
     * ????
     *
     * @param pid ?
     * @return ??
     */
    public static String getProcessName(int pid) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
            String processName = reader.readLine();
            if (!TextUtils.isEmpty(processName)) {
                processName = processName.trim();
            }
            return processName;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException exception) {
                exception.printStackTrace();
            }
        }
        return null;
    }

}