I'm having some trouble retrieving icons for installed Android App. The following code returns icons for all apps, however, some apps are returned with small icons (perhaps from drawable - ldpi folder) while some with large icons.
List<PackageInfo> package = getPackageManager().getInstalledPackages(0);
for(PackageInfo p : package){
iApp.icon = p.applicationInfo.loadIcon(getPackageManager());
}
How Can I get icons which are all of the same size, just like in Manage Application section of Android?
I want to add something to previous answer what applies to Android 3.0 and greater.
You can notice that icons retrieved in this standard way (i mean applicationInfo.loadIcon and other typical methods) are smaller than icons you see in launcher app. Scale up just makes icons blurrier. If you want big icons you can use next code (i took it from launcher source code you can find here and changed a bit). Pay your attention to activityManager.getLauncherLargeIconDensity method.
public Drawable getFullResDefaultActivityIcon() {
return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
}
public Drawable getFullResIcon(Resources resources, int iconId) {
Drawable d;
try {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
int iconDpi = activityManager.getLauncherLargeIconDensity();
d = resources.getDrawableForDensity(iconId, iconDpi);
} catch (Resources.NotFoundException e) {
d = null;
}
return (d != null) ? d : getFullResDefaultActivityIcon();
}
public Drawable getFullResIcon(String packageName, int iconId) {
Resources resources;
try {
resources = mContext.getPackageManager().getResourcesForApplication(packageName);
} catch (PackageManager.NameNotFoundException e) {
resources = null;
}
if (resources != null) {
if (iconId != 0) {
return getFullResIcon(resources, iconId);
}
}
return getFullResDefaultActivityIcon();
}
public Drawable getFullResIcon(ResolveInfo info) {
return getFullResIcon(info.activityInfo);
}
public Drawable getFullResIcon(ActivityInfo info) {
Resources resources;
try {
resources = mContext.getPackageManager().getResourcesForApplication(info.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
resources = null;
}
if (resources != null) {
int iconId = info.getIconResource();
if (iconId != 0) {
return getFullResIcon(resources, iconId);
}
}
return getFullResDefaultActivityIcon();
}
private Drawable getAppIcon(ResolveInfo info) {
return getFullResIcon(info.activityInfo);
}
Hope it helps someone.
Apps might just have different sized icons. The Android Settings app loads icons just like you. It scales the icons when displaying them.
Here's a snippet from packages/apps/Settings/res/layout/manage_applications_item.xml:
<ImageView android:id="#+id/app_icon"
android:layout_width="#android:dimen/app_icon_size"
android:layout_height="#android:dimen/app_icon_size"
android:layout_marginRight="11dip"
android:layout_gravity="center_vertical"
android:scaleType="fitCenter"/>
Although, this has been answered a long time back, here is the complete function. Hope it will help others.
To get the icon, you should query for icon for different dpi.
Try this:
public static Drawable getIconFromPackageName(String packageName, Context context)
{
PackageManager pm = context.getPackageManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
{
try
{
PackageInfo pi = pm.getPackageInfo(packageName, 0);
Context otherAppCtx = context.createPackageContext(packageName, Context.CONTEXT_IGNORE_SECURITY);
int displayMetrics[] = {DisplayMetrics.DENSITY_XHIGH, DisplayMetrics.DENSITY_HIGH, DisplayMetrics.DENSITY_TV};
for (int displayMetric : displayMetrics)
{
try
{
Drawable d = otherAppCtx.getResources().getDrawableForDensity(pi.applicationInfo.icon, displayMetric);
if (d != null)
{
return d;
}
}
catch (Resources.NotFoundException e)
{
// Log.d(TAG, "NameNotFound for" + packageName + " # density: " + displayMetric);
continue;
}
}
}
catch (Exception e)
{
// Handle Error here
}
}
ApplicationInfo appInfo = null;
try
{
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
}
catch (PackageManager.NameNotFoundException e)
{
return null;
}
return appInfo.loadIcon(pm);
}
You must define in App class ;
private Drawable appIcon;
public Drawable getappIcon(){
return this.appIcon;
}
if you use RecyclerViewAdapter ;
List<App> list_app;
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.appIcon.setImageDrawable(list_app.get(position).getappIcon());
}
in MainActivity ;
private List<App> appList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
appList = new ArrayList<App>();
for (ApplicationInfo packageInfo : packages) {
Drawable drawableIcon =packageInfo.loadIcon(getPackageManager());
appList.add(new App (drawableIcon));
}
Related
I'm loading all apps from android and then I display them in my launcher (icon + name). Code looks like following:
public class PhoneAppItem
{
String mPackageName = null;
String mActivityName = null;
String mName = null;
ActivityInfo mActivityInfo = null;
public PhoneAppItem(String packageName, String activityName)
{
mPackageName = packageName;
mActivityName = activityName;
}
public void loadInfo()
{
PackageManager pm = MainApp.get().getPackageManager();
try
{
// following line throws the exception!
mActivityInfo = pm.getActivityInfo(new ComponentName(mPackageName, mActivityName), 0);
// some other code...
}
catch (PackageManager.NameNotFoundException e)
{
L.e(e);
mName = mPackageName;
}
catch (NullPointerException e)
{
L.e(e);
mName = mPackageName;
}
}
}
Package names and activity names for all my PhoneAppItem items are retrieved like following (for android < 5 which is relevant for the only yet known device having this issue):
List<PhoneAppItem> apps = new ArrayList<>();
ActivityManager activityManager = (ActivityManager) MainApp.get().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processInfos = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo processInfo : processInfos)
{
try
{
ApplicationInfo ai = pm.getApplicationInfo(processInfo.processName, 0);
if (!excludedPackages.contains(ai.packageName))
apps.add(new PhoneAppItem(ai.packageName, ai.className));
}
catch (PackageManager.NameNotFoundException e) {}
}
I now have a user that get's following exception:
android.content.pm.PackageManager$NameNotFoundException: ComponentInfo{com.package.myapp/com.package.myapp.app.MainApp}
at android.app.ApplicationPackageManager.getActivityInfo(ApplicationPackageManager.java:262)
at com.package.myap.classes.PhoneAppItem.h(PhoneAppItem.java:70)
...
Observations
the exception above is thrown for all apps, even for my own app
until now, this behaviour is unique to one user using following hardware: Lenovo Yoga Tablet HD+ (b8080), Android 4.4.2
Question
Does anyone have an idea why this could happen?
If processInfo.processName does not work, try another method of getting package:
processInfo.pkgList[0]
I'm trying to get the ApplicationInfo for Settings.ACTION_ACCESSIBILITY_SETTINGS or Settings.ACTION_BATTERY_SAVER_SETTINGS, so that I can launch them directly.
I tried following steps but it's return setting's ApplicationInfo.
private static final String[] SETTINGS_ACTION_MENUS = new String[]{
Settings.ACTION_ACCESSIBILITY_SETTINGS,Settings.ACTION_ADD_ACCOUNT};
public void getSettingPages(){
for(String menu : SETTINGS_ACTION_MENUS){
final Intent intent = new Intent(menu);
ComponentName componentName = intent.resolveActivity(packageManager);
if(componentName != null){
try {
ApplicationInfo info = packageManager.getApplicationInfo(componentName.getPackageName(),0);
if(packageManager.getLaunchIntentForPackage(info.packageName) != null){
launchableApps.add(info);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
}
I tried following steps but it's return setting's ApplicationInfo
That is because those Intent actions are tied to activities in the Settings app. Individual activities do not have their own ApplicationInfo.
I'd like to load icon from a running task package name like this
com.android.smspush.WapPushManager
You can get top running application by following code : once you get applicationInfo, you can get icon from info.
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED);
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo)(i.next());
try {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(
info.processName, PackageManager.GET_META_DATA));
Drawable ico = info.loadIcon(pm); // Icon of the application
Log.w("LABEL", c.toString());
} catch (Exception e) {
// Name Not FOund Exception
}
}
public class AppIconDrawable {
private HashMap<String, Drawable> drawables;
private static AppIconDrawable sharedInstance = null;
private AppIconDrawable(){
drawables = new HashMap<>();
}
public static AppIconDrawable getSharedInstance(){
if (sharedInstance == null)
sharedInstance = new AppIconDrawable();
return sharedInstance;
}
public void setDrawableForKey(String key, Drawable drawable){
drawables.put(key, drawable);
}
public Drawable getDrawableForKey(String key){
return drawables.get(key);
}
}
To save icon i used it, where rp.process = com.android.smspush.WapPushManager
PackageManager manager = getActivity().getPackageManager();
List<ActivityManager.RunningAppProcessInfo> listProcesses = manager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo info : listProcesses) {
try {
ApplicationInfo appinfo = manager.getApplicationInfo(info.processName, PackageManager.GET_META_DATA);
AppIconDrawable.getSharedInstance().setDrawableForKey(info.processName, manager.getApplicationIcon(appinfo));
} catch (PackageManager.NameNotFoundException e) {
AppIconDrawable.getSharedInstance().setDrawableForKey(info.processName, context.getResources().getDrawable(R.drawable.ic_android_default));
}
}
To get icon i used it, where rp.process = com.android.smspush.WapPushManager
holder.imgApp.setImageDrawable(AppIconDrawable.getSharedInstance().getDrawableForKey(rp.process));
guyz i need a little help again with the launcher icon theming :p
this is the method that changes icon in LauncherModel.java in ADWLauncher
static Drawable getIcon(PackageManager manager, Context context, ActivityInfo activityInfo) {
String themePackage=AlmostNexusSettingsHelper.getThemePackageName(context, Launcher.THEME_DEFAULT);
Drawable icon = null;
if(themePackage.equals(Launcher.THEME_DEFAULT)){
icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
}else{
// get from theme
Resources themeResources = null;
if(AlmostNexusSettingsHelper.getThemeIcons(context)){
activityInfo.name=activityInfo.name.toLowerCase().replace(".", "_");
try {
themeResources = manager.getResourcesForApplication(themePackage);
} catch (NameNotFoundException e) {
//e.printStackTrace();
}
if(themeResources!=null){
int resource_id = themeResources.getIdentifier(activityInfo.name, "drawable", themePackage);
if(resource_id!=0){
icon=themeResources.getDrawable(resource_id);
}
// use IconShader
if(icon==null){
if (compiledIconShaderName==null ||
compiledIconShaderName.compareTo(themePackage)!=0){
compiledIconShader = null;
resource_id = themeResources.getIdentifier("shader", "xml", themePackage);
if(resource_id!=0){
XmlResourceParser xpp = themeResources.getXml(resource_id);
compiledIconShader = IconShader.parseXml(xpp);
}
}
if(compiledIconShader!=null){
icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
try {
icon = IconShader.processIcon(icon, compiledIconShader);
} catch (Exception e) {}
}
}
}
}
if(icon==null){
icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
}else{
icon = Utilities.createIconThumbnail(icon, context);
}
}
return icon;
}
but there is no such method in the LauncherModel, instead it is inside IconCache (which is not in the ADWLauncher) (https://android.googlesource.com/platform/packages/apps/Launcher2/+/master/src/com/android/launcher2/IconCache.java)
how can i edit iconcache.java to implement that??
If you want to change your launcher icon you should check out my project that just just that. https://github.com/slightfoot/android-launcher-badges
How can I find whether a particular package or application, say: com.android.abc, exists on my Android device?
Call any of the below method with the package name.
import android.content.pm.PackageManager;
// ...
public boolean isPackageExisted(String targetPackage){
List<ApplicationInfo> packages;
PackageManager pm;
pm = getPackageManager();
packages = pm.getInstalledApplications(0);
for (ApplicationInfo packageInfo : packages) {
if(packageInfo.packageName.equals(targetPackage))
return true;
}
return false;
}
import android.content.pm.PackageManager;
public boolean isPackageExisted(String targetPackage){
PackageManager pm=getPackageManager();
try {
PackageInfo info=pm.getPackageInfo(targetPackage,PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return true;
}
Without using a try-catch block or iterating through a bunch of packages:
public static boolean isPackageInstalled(Context context, String packageName) {
final PackageManager packageManager = context.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(packageName);
if (intent == null) {
return false;
}
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
Kotlin
fun isPackageExist(context: Context, target: String): Boolean {
return context.packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null
}
Edit: Extension Function
fun Context.isPackageExist(target: String): Boolean {
return packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null
}
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
We can check like this:
if(getPackageManager().hasSystemFeature("android.software.webview") == true && isPackageExisted("com.google.android.webview")) {
if (Constant.isNetworkConnected(Activity.this)) {
//Your Intent
} else {
Toast.makeText(getApplicationContext(), resources.getString(R.string.internet_error), Toast.LENGTH_SHORT).show();
}
} else
{
Constant.showDialog(Activity.this,"Please install the webview");
}
}
Make method for package check ! this credit goes to "Kavi" https://stackoverflow.com/a/30708227/6209105
public boolean isPackageExisted(String targetPackage) {
List<ApplicationInfo> packages;
PackageManager pm;
pm = getPackageManager();
packages = pm.getInstalledApplications(0);
for (ApplicationInfo packageInfo : packages) {
if(packageInfo.packageName.equals(targetPackage))
{
return true;
}
}
return false;
}
You should use PackageManager's function called getInstalledPackages() to get the list of all installed packages and the search for the one you are interested in. Note that package name is located in PackageInfo.packageName field.
Since some devices have reported that the "getInstalledPackages" can cause TransactionTooLargeException (check here, here and here), I think you should also have a fallback like I did below.
This issue was supposed to be fixed on Android 5.1 (read here), but some still reported about it.
public static List<String> getInstalledPackages(final Context context) {
List<String> result = new ArrayList<>();
final PackageManager pm = context.getPackageManager();
try {
List<PackageInfo> apps = pm.getInstalledPackages(0);
for (PackageInfo packageInfo : apps)
result.add(packageInfo.packageName);
return result;
} catch (Exception ignored) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
BufferedReader bufferedReader = null;
try {
Process process = Runtime.getRuntime().exec("pm list packages");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
final String packageName = line.substring(line.indexOf(':') + 1);
result.add(packageName);
}
closeQuietly(bufferedReader);
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeQuietly(bufferedReader);
}
return result;
}
public static void closeQuietly(final Closeable closeable) {
if (closeable == null)
return;
try {
closeable.close();
} catch (final IOException e) {
}
}
If you just want to use adb:
adb shell "pm list packages"|cut -f 2 -d ":"
it will list all installed packages.
You can use pm.getPackageUid() instead of iterating over the pm.getInstalledApplications()
boolean isPackageInstalled;
PackageManager pm = getPackageManager();
int flags = 0;
try
{
pm.getPackageUid(packageName,flags);
isPackageInstalled = true;
}
catch (final PackageManager.NameNotFoundException nnfe)
{
isPackageInstalled = false;
}
return isPackageInstalled;
According to the Package visibility filtering changes in Android 11, you need to add this permission to your manifest to be able to list installed apps:
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
but Google doesn't recommend to use this way. You should use <queries> tag instead:
<manifest ...>
<queries>
<package android:name="com.app.package" />
...
</queries>
...
</manifest>
And in your code:
fun isAppInstalled(context: Context, packageId: String): Boolean {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager
.getApplicationInfo(packageId, PackageManager.ApplicationInfoFlags.of(0))
} else {
context.packageManager.getApplicationInfo(packageId, 0)
}
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
}