Java tutorial
/* * Kontalk Android client * Copyright (C) 2017 Kontalk Devteam <devteam@kontalk.org> * This program 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. * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.util; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.provider.ContactsContract; import android.support.annotation.AttrRes; import android.support.annotation.ColorRes; import android.support.v4.content.ContextCompat; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.util.SparseBooleanArray; import android.util.TypedValue; import android.view.Display; import android.view.Surface; import android.view.WindowManager; import android.widget.Toast; import org.kontalk.BuildConfig; import org.kontalk.R; import org.kontalk.authenticator.Authenticator; /** * System-related utilities. * @author Daniele Ricci */ public final class SystemUtils { private static final Pattern VERSION_CODE_MATCH = Pattern.compile("\\(([0-9]+)\\)$"); private static Uri sProfileUri; private SystemUtils() { } public static boolean isOlderVersion(Context context, String version) { Matcher m = VERSION_CODE_MATCH.matcher(version); if (m.find() && m.groupCount() > 0) { try { int versionCode = Integer.parseInt(m.group(1)); int currentVersion = getVersionCode(); return versionCode < currentVersion; } catch (Exception ignored) { } } // no version code found at the end - assume older version return true; } public static int getVersionCode() { return BuildConfig.VERSION_CODE; } public static String getVersionFullName(Context context) { return context.getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE); } /** * Returns true if on Gingerbread or earlier. * We need this to disable some fancy animations or graphics which would be * too difficult to make them work on these Android versions. Besides, even * Google doesn't want to support them anymore. */ public static boolean isLegacySystem() { return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB; } @SuppressWarnings("deprecation") public static Point getDisplaySize(Context context) { Point displaySize = null; WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); if (display != null) { displaySize = new Point(); if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB_MR2) { displaySize.set(display.getWidth(), display.getHeight()); } else { display.getSize(displaySize); } } return displaySize; } public static int getDisplayRotation(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); return manager.getDefaultDisplay().getRotation(); } /** * Returns the correct screen orientation based on the supposedly preferred * position of the device. * http://stackoverflow.com/a/16585072/1045199 */ public static int getScreenOrientation(Activity activity) { WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); Configuration configuration = activity.getResources().getConfiguration(); int rotation = windowManager.getDefaultDisplay().getRotation(); // Search for the natural position of the device if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) || configuration.orientation == Configuration.ORIENTATION_PORTRAIT && (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270)) { // Natural position is Landscape switch (rotation) { case Surface.ROTATION_0: return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; case Surface.ROTATION_90: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; case Surface.ROTATION_180: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; case Surface.ROTATION_270: return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; } } else { // Natural position is Portrait switch (rotation) { case Surface.ROTATION_0: return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; case Surface.ROTATION_90: return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; case Surface.ROTATION_180: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; case Surface.ROTATION_270: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; } } return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } public static void acquireScreenOn(Activity activity) { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } public static void releaseScreenOn(Activity activity) { activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } /** Returns the type name of the current network, or null. */ public static String getCurrentNetworkName(Context context) { ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connMgr.getActiveNetworkInfo(); return info != null ? info.getTypeName() : null; } public static int getCurrentNetworkType(Context context) { ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connMgr.getActiveNetworkInfo(); return info != null ? info.getType() : -1; } public static boolean isOnWifi(Context context) { return getCurrentNetworkType(context) == ConnectivityManager.TYPE_WIFI; } /** Checks for network availability. */ public static boolean isNetworkConnectionAvailable(Context context) { final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm.getBackgroundDataSetting()) { NetworkInfo info = cm.getActiveNetworkInfo(); if (info != null && info.getState() == NetworkInfo.State.CONNECTED) return true; } return false; } public static Bitmap getProfilePhoto(Context context) { // profile photo is available only since API level 14 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { ContentResolver cr = context.getContentResolver(); InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, ContactsContract.Profile.CONTENT_URI); if (input != null) { try { return BitmapFactory.decodeStream(input); } finally { try { input.close(); } catch (IOException ignore) { } } } } return null; } public static Uri getProfileUri(Context context) { if (sProfileUri == null) { // profile contact is available only since API level 14 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { sProfileUri = ContactsContract.Profile.CONTENT_URI; } else { // try with the phone number String phoneNumber = Authenticator.getDefaultAccountName(context); sProfileUri = lookupPhoneNumber(context, phoneNumber); } } return sProfileUri; } public static Uri lookupPhoneNumber(Context context, String phoneNumber) { Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)); Cursor cur = context.getContentResolver().query(uri, new String[] { ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.LOOKUP_KEY }, null, null, null); if (cur != null) { try { if (cur.moveToNext()) { long id = cur.getLong(0); String lookupKey = cur.getString(1); return ContactsContract.Contacts.getLookupUri(id, lookupKey); } } finally { cur.close(); } } return null; } /** * Provides clone functionality for the {@link SparseBooleanArray}. * See https://code.google.com/p/android/issues/detail?id=39242 */ public static SparseBooleanArray cloneSparseBooleanArray(SparseBooleanArray array) { final SparseBooleanArray clone = new SparseBooleanArray(); synchronized (array) { final int size = array.size(); for (int i = 0; i < size; i++) { int key = array.keyAt(i); clone.put(key, array.get(key)); } } return clone; } public static <T> T[] concatenate(T[] a, T[] b) { int aLen = a.length; int bLen = b.length; @SuppressWarnings("unchecked") T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen); System.arraycopy(a, 0, c, 0, aLen); System.arraycopy(b, 0, c, aLen, bLen); return c; } public static <T> T[] concatenate(T[] a, T b) { int aLen = a.length; @SuppressWarnings("unchecked") T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + 1); System.arraycopy(a, 0, c, 0, aLen); c[aLen] = b; return c; } public static <T> boolean contains(final T[] array, final T v) { for (final T e : array) if (e == v || v != null && v.equals(e)) return true; return false; } /** Instead of importing the whole commons-io :) */ public static long copy(final InputStream input, final OutputStream output) throws IOException { byte[] buffer = new byte[4096]; long count = 0; int n; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; } /** Closes the given stream, ignoring any errors. */ public static void closeStream(Closeable stream) { try { stream.close(); } catch (Exception ignored) { } } public static void openURL(Context context, String url) { try { context.startActivity(externalIntent(Intent.ACTION_VIEW, Uri.parse(url))); } catch (ActivityNotFoundException e) { Toast.makeText(context, R.string.chooser_error_no_browser, Toast.LENGTH_LONG).show(); } } public static void dial(Context context, CharSequence phone) { try { context.startActivity(externalIntent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone))); } catch (ActivityNotFoundException e) { Toast.makeText(context, R.string.chooser_error_no_dialer, Toast.LENGTH_LONG).show(); } } public static boolean isCallable(Context context, Intent intent) { List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } public static Intent externalIntent(String action) { return externalIntent(action, null); } public static Intent externalIntent(String action, Uri data) { Intent i = new Intent(action, data); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { i.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); } else { i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); } return i; } public static String getUserSerial(Context context) { //noinspection ResourceType Object userManager = context.getSystemService("user"); if (null == userManager) return ""; try { Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null); Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null); Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass()); Long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle); if (userSerial != null) { return String.valueOf(userSerial); } else { return ""; } } catch (Exception ignored) { } return ""; } public static CharacterStyle getColoredSpan(Context context, @ColorRes int colorResId) { return new ForegroundColorSpan(ContextCompat.getColor(context, colorResId)); } public static CharacterStyle getTypefaceSpan(int typeface) { return new StyleSpan(typeface); } public static int getThemedResource(Context context, @AttrRes int attrResId) { TypedValue value = new TypedValue(); if (!context.getTheme().resolveAttribute(attrResId, value, true)) throw new Resources.NotFoundException(); return value.resourceId; } }