org.kontalk.util.SystemUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.kontalk.util.SystemUtils.java

Source

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

}