package com.oasisfeng.android.util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;

import java.util.Arrays;
import java.util.Collection;

/** @author Oasis */
public class Apps {

    public static Apps of(final Context context) {
        return new Apps(context);
    }

    /** Check whether specified app is installed on the device, even if not installed in current user (Android 4.2+). */
    public boolean isInstalledOnDevice(final String pkg) {
        try { //noinspection WrongConstant,deprecation
            mContext.getPackageManager().getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
            return true;
        } catch (final NameNotFoundException e) {
            return false;
        }
    }

    /** Check whether specified app is installed in current user, even if hidden by system (Android 5+). */
    public boolean isInstalledInCurrentUser(final String pkg) {
        try { //noinspection WrongConstant,deprecation
            final ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return true;
            return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
        } catch (final NameNotFoundException e) {
            return false;
        }
    }

    /** Use {@link #isInstalledInCurrentUser(String)} or {@link #isInstalledOnDevice(String)} instead */
    @Deprecated public boolean isInstalled(final String pkg) {
        return isInstalledInCurrentUser(pkg);
    }

    public boolean isEnabled(final String pkg) throws NameNotFoundException {
        final ApplicationInfo app_info = mContext.getPackageManager().getApplicationInfo(pkg, 0);
        return app_info.enabled;
    }

    /** Check whether specified app is installed in current user, enabled and not hidden */
    public boolean isAvailable(final String pkg) {
        try {
            return isEnabled(pkg);
        } catch (final NameNotFoundException e) {
            return false;
        }
    }

    public boolean isInstalledBy(final String... installer_pkgs) {
        try {
            return Arrays.asList(installer_pkgs).contains(mContext.getPackageManager().getInstallerPackageName(mContext.getPackageName()));
        } catch(final IllegalArgumentException e) {
            return false;       // Should never happen
        }
    }

    public CharSequence getAppName(final String pkg) {
        try {
        	final ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(pkg, 0);
            return getAppName(info);
        } catch (final NameNotFoundException e) {
        	return "<?>";
        }
    }

    public CharSequence getAppName(final ApplicationInfo app_info) {
        try {
        	return app_info.loadLabel(mContext.getPackageManager());
        } catch (final RuntimeException e) {	// Including Resources.NotFoundException
        	return app_info.packageName;
        }
    }

    public String getAppNames(final Collection<String> pkgs, final String separator) {
        final StringBuilder app_names = new StringBuilder();
        final PackageManager pm = mContext.getPackageManager();
        for (final String pkg : pkgs) {
        	app_names.append(separator);
            final ApplicationInfo info;
            try { //noinspection WrongConstant,deprecation
                info = pm.getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
            } catch (final NameNotFoundException e) {
            	app_names.append("<?>");
            	continue;
            }
            try {
            	app_names.append(info.loadLabel(pm));
            } catch (final RuntimeException e) {	// Including Resources.NotFoundException
            	app_names.append(info.packageName);
            }
        }
        return app_names.substring(separator.length());
    }

    private Apps(final Context context) {
        mContext = context;
    }

    private final Context mContext;
}

@@ -235,16 +235,63 @@
 s.Build;
+%0Aimport android.support.annotation.CheckResult;
 %0A%0Aimport
@@ -597,32 +597,45 @@
 . */%0A    public 
+@CheckResult 
 boolean isInstal
@@ -1057,32 +1057,45 @@
 . */%0A    public 
+@CheckResult 
 boolean isInstal
@@ -1695,32 +1695,45 @@
 precated public 
+@CheckResult 
 boolean isInstal
@@ -1812,32 +1812,45 @@
   %7D%0A%0A    public 
+@CheckResult 
 boolean isEnable
@@ -2133,32 +2133,45 @@
 n */%0A    public 
+@CheckResult 
 boolean isAvaila
@@ -2347,16 +2347,29 @@
  public 
+@CheckResult 
 boolean 
@@ -2697,32 +2697,45 @@
   %7D%0A%0A    public 
+@CheckResult 
 CharSequence get
@@ -2767,32 +2767,73 @@
  %7B%0A        try %7B
+ //noinspection WrongConstant,deprecation
 %0A        %09final 
@@ -2900,33 +2900,71 @@
 cationInfo(pkg, 
-0
+PackageManager.GET_UNINSTALLED_PACKAGES
 );%0A            r
@@ -3088,16 +3088,29 @@
  public 
+@CheckResult 
 CharSequ
@@ -3391,16 +3391,29 @@
  public 
+@CheckResult 
 String g

Support uninstalled (in current user) packages in Apps.getAppName(String pkg).