Java tutorial
/* * 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; } }