How to find high resoultion icon using PacakageManager - android

I'm doing an app that need the higher resolution icons of each app.
I have done some research since this morning but none of the answers I found work.
Here are two of them and what is wrong for me.
FYI, I have retrieved all the "packageinfo" from the packagemanager, I'm finding everything I need but the high resolution icon...
1. using getDrawableForDensity:
ActivityInfo info = packageManager.getActivityInfo(componentName, PackageManager.GET_META_DATA);
Resources resources;
try {
resources = mPackageManager.getResourcesForApplication(
info.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
resources = null;
}
if (resources != null) {
int iconId = info.getIconResource();
if (iconId != 0) {
Drawable d;
try {
d = resources.getDrawableForDensity(iconId, DisplayMetrics.DENSITY_XHIGH);
} catch (Resources.NotFoundException e) {
d = null;
}
return d;
}
}
My problem for this one is that I don't understand what to put for componentName. How can I "construct" it with the information I got from packagemanager ?
2.Other solution
Retrieving xhdpi app icons from packageManager?
// Get the application's resources
Resources res = mPackageManager.getResourcesForApplication(appInfo);
// Get a copy of the configuration, and set it to the desired resolution
Configuration config = res.getConfiguration();
Configuration originalConfig = new Configuration(config);
config.densityDpi = DisplayMetrics.DENSITY_XHIGH;
// Update the configuration with the desired resolution
DisplayMetrics dm = res.getDisplayMetrics();
res.updateConfiguration(config, dm);
// Grab the app icon
Drawable appIcon = res.getDrawable(appInfo.icon);
// Set our configuration back to what it was
res.updateConfiguration(originalConfig, dm);
for this one I have a problem with this line:
Drawable appIcon = res.getDrawable(appInfo.icon);
Error I get about "icon":
icon cannot be resolved or is not a field

Try this, it is similar to the code that you have but it seems to work for me :
//Get HiRes Icon
Drawable appIcon;
List<Application> applications = new ArrayList<Application>();
for (ApplicationInfo item : getInstalledApplications(packageManager)) {
try {
Resources resourcesForApplication = packageManager.getResourcesForApplication(item);
Configuration config = resourcesForApplication.getConfiguration();
Configuration originalConfig = new Configuration(config);
DisplayMetrics displayMetrics = resourcesForApplication.getDisplayMetrics();
DisplayMetrics originalDisplayMetrics = resourcesForApplication.getDisplayMetrics();
displayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
resourcesForApplication.updateConfiguration(config, displayMetrics);
appIcon = resourcesForApplication.getDrawable(item.icon);
resourcesForApplication.updateConfiguration(originalConfig, originalDisplayMetrics);
} catch (PackageManager.NameNotFoundException e) {
Log.e("check", "error getting Hi Res Icon :", e);
appIcon = item.loadIcon(packageManager);
}
Application app = new Application();
app.setTitle(item.loadLabel(packageManager).toString());
app.setPackageName(item.packageName);
// app.setImage(item.loadIcon(packageManager));
app.setImage(appIcon);
applications.add(app);
}
}

This is only speculation as I'm not a particularly good Android programmer but:
In the first solution, you could probably retrieve a list of every application installed on a device by a method getInstalledApplications(int flags) of PackageManager class.
See
http://developer.android.com/reference/android/content/pm/PackageManager.html#getInstalledApplications(int)
So as a code something like this:
///This retrieves information on every application installed on device, see documentation
///for flags
List<ApplicationInfo> applications = mPackageManager.getInstalledApplications(int flags);
///Then retrieve Resources for every application with looping through all the applications
for (ApplicationInfo info : applications) {
Resources res = mPackageManager.getResourcesForApplication(info);
///And now you can do what you already wrote yourself and try fetching icon for every
///'res' you did in the first solution.
}
This is assuming that you want to show every application.
About solution 2:
I'm assuming appInfo is of 'ApplicationInfo' class. It has a public field 'icon' that is inherited from the 'PackageItemInfo'-class. Make sure your appInfo is any of the sub classes of 'PackageItemInfo' class and it should work. If it does not work, there is probably something wrong with the Android manifest.xml of the given application and it can not retrieve the required integer.
You could try retrieving the icons by 'getApplicationIcon'-method of the 'PackageManager'-class. Once again
List<ApplicationInfo> applications = mPackageManager.getInstalledApplications(int flags);
List<Drawable> icons = new List<Drawable>;
for (ApplicationInfo app : applications) {
icons.add(mPackageManager.getApplicationIcon(app));
}
Of course, this means you are going twice through the list of applications, short of.

Related

DocumentsUI shows "Anonymous" application when requesting access to directory

One user reported that my app fails to request directory access when selecting a folder via the ACTION_OPEN_DOCUMENT_TREE intent.
For some reason it does not show my application, instead "Anonymous":
Translated: "Allow Anonymous to access files in Camera. This will let Anonymous access current and future content stored in Camera".
The user has a MIUI 12 with Android 11 on a Mi Note 10 lite.
I have the same just with a Mi Note 10, no issues ofc.
Checked the Android source code:
https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/refs/heads/master/src/com/android/documentsui/picker/ConfirmFragment.java#82
case TYPE_OEPN_TREE:
final Uri treeUri = mTarget.getTreeDocumentUri();
final BaseActivity activity = (BaseActivity) getActivity();
final String target = activity.getCurrentTitle();
final String text = getString(R.string.open_tree_dialog_title,
**getCallingAppName**(getActivity()), target);
message = getString(R.string.open_tree_dialog_message,
**getCallingAppName**(getActivity()), target);
builder.setTitle(text);
builder.setMessage(message);
builder.setPositiveButton(
R.string.allow,
(DialogInterface dialog, int id) -> {
pickResult.increaseActionCount();
mActions.finishPicking(treeUri);
});
break;
#NonNull
public static String getCallingAppName(Activity activity) {
final String anonymous = activity.getString(R.string.anonymous_application);
final String packageName = getCallingPackageName(activity);
if (TextUtils.isEmpty(packageName)) {
return anonymous;
}
final PackageManager pm = activity.getPackageManager();
ApplicationInfo ai;
try {
ai = pm.getApplicationInfo(packageName, 0);
} catch (final PackageManager.NameNotFoundException e) {
return anonymous;
}
CharSequence result = pm.getApplicationLabel(ai);
return TextUtils.isEmpty(result) ? anonymous : result.toString();
}
public static String getCallingPackageName(Activity activity) {
String callingPackage = activity.getCallingPackage();
// System apps can set the calling package name using an extra.
try {
ApplicationInfo info =
activity.getPackageManager().getApplicationInfo(callingPackage, 0);
if (isSystemApp(info) || isUpdatedSystemApp(info)) {
final String extra = activity.getIntent().getStringExtra(
Intent.EXTRA_PACKAGE_NAME);
if (extra != null && !TextUtils.isEmpty(extra)) {
callingPackage = extra;
}
}
} catch (NameNotFoundException e) {
// Couldn't lookup calling package info. This isn't really
// gonna happen, given that we're getting the name of the
// calling package from trusty old Activity.getCallingPackage.
// For that reason, we ignore this exception.
}
return callingPackage;
}
...and it seems that for whatever reason my packagename isn't found. How can can happen?
Asked him to install one of my other apps, and it happens there as well.
Asked him then to install another app from the playstore (FX File Explorer) and there it does not happen.
So it is specific to his device and my app.
So it turned out that this user having that issue turned off the MIUI Optimizations in the developer settings.
Bug report: συσκευη, εκδοση miui, Play store install (alpha 1021). It was impossible to specify a b i o s file or specify a game image directory in when MIUI optimizations are off. Turning them back on fixed the issue and directories are scanned normally. Also on the popup to allow folder access the app displays as "Anonymous" instead of AetherSX2 on my system. Some developer was talking about having the same issue here.

How can I see the application directly underneath a soft keyboard in Android?

I am developing a soft keyboard that pipes data (not text) to a receiving intent. Is there any way to see the application/activity that the keyboard is currently overlaying? I am trying to preselect the intent action chooser and develop custom rules to get the data to go to the right place.
Just thought I'd answer my own question for this one. Here is the code that returns the activity from the top of the stack.
public String PullTop() {
final PackageManager pm = getPackageManager();
//Get the Activity Manager Object
ActivityManager aManager =
(ActivityManager) self.getSystemService(ACTIVITY_SERVICE);
//Get the list of running Applications
List<ActivityManager.RunningAppProcessInfo> rapInfoList = aManager.getRunningAppProcesses();
//Iterate all running apps to get their details
for (ActivityManager.RunningAppProcessInfo rapInfo : rapInfoList) {
//error getting package name for this process so move on
if (rapInfo.pkgList.length == 0)
continue;
try {
PackageInfo pkgInfo = pm.getPackageInfo(rapInfo.pkgList[0], PackageManager.GET_ACTIVITIES);
Log.i("Package",pkgInfo.packageName);
return pkgInfo.packageName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.d("", "NameNotFoundException :" + rapInfo.pkgList[0]);
}
}
return null;
}
To pipe the data to the right process just check for null and:
intent.setPackage(PullTop());

Correct name of installed applications

I am getting the names for my installed applications with below code and use them to see if any updates for this application is available.
But sometimes an incorrect name (MX Speler instead of MX Player) is being provided, as a result no updates are found.
Is there any better code i can/should use?
{
final PackageInfo pi = installedInfo != null ? installedInfo : downloadedInfo;
final PackageManager pm = getApplicationContext().getPackageManager();
ApplicationInfo ai;
try {
ai = pm.getApplicationInfo(pi ??, 0); //How to set the name of the installed application?
} catch (final NameNotFoundException e) {
ai = null;
}
final String applicationName = (String) (ai != null ? pm.getApplicationLabel(ai) : "(unknown)");
System.out.println("Application name : "+ applicationName);
}
You should not use labels as it may be different for every language or changed on each update. You should only rely on application's id (packageId) as this id stays unchanged for the whole life of the application.

How do I open the Account Settings for a specific Account?

I know that via the Account Manager I can access to the list of the accounts on the device.
Account[] accounts = AccountManager.get(this).getAccounts();
I know as well that using the android.settings.ACCOUNT_SYNC_SETTINGS I can open the Sync Settings for a specific account
Intent in=new Intent("android.settings.ACCOUNT_SYNC_SETTINGS");
in.putExtra("account", accounts[3]);
What I would like to do is to open the "Account Settings" for a specific account, like this:
And not like this:
General Approach:
The tricky part is that Android's definition of Account is pretty abstract, so depending on your use case you'll encounter accounts without these screens, or with multiple screens. These screens may not look like Preferences/Settings screens at all - they could be any Activity as defined by the Account authenticator.
Generally though, I think this is what you could do:
Use the getAuthenticatorTypes() method of AccountManager. This
will give you all of the AuthenticatorDescriptions. Depending on
your use case, you can pick the AuthenticatorDescription you care
about (based on the "type" value) and just further investigate that.
http://developer.android.com/reference/android/accounts/AccountManager.html#getAuthenticatorTypes()
The AuthenticatorDescription will tell you the
accountPreferencesId that defines the "hierarchy of
PreferenceScreen to be added to the settings page for the account".
Which in turn defines a "PreferenceScreen xml hierarchy that
contains a list of PreferenceScreens that can be invoked to manage
the authenticator".
http://developer.android.com/reference/android/accounts/AuthenticatorDescription.html
Use the accountPreferencesId and the package provided by the
AuthenticatorDescription to parse the Intents you need, allowing you
to navigate your user to them. Reference for what the XML will look
like:
http://developer.android.com/reference/android/accounts/AbstractAccountAuthenticator.html
tl;dr - the code:
Here's a method that finds the Activity action/class and starts it. It doesn't account for the fact that there may be multiple Activities defined in the Preferences XML referenced above. In fact, it doesn't account for a lot of error scenarios and can surely be optimized, but should serve as a decent proof of concept and starting point:
//somewhere in your app call this
//com.android.email works to open the email preferences on my Galaxy s4
startPreferenceActivity("com.android.email");
private void startPreferenceActivity(String type) {
AccountManager accountManager = AccountManager.get(this);
AuthenticatorDescription[] descriptions = accountManager.getAuthenticatorTypes();
AuthenticatorDescription neededDescription = null;
for (AuthenticatorDescription description : descriptions) {
if (description.type.contains(type)) {
neededDescription = description;
break;
}
}
if (neededDescription != null) {
String packageName = neededDescription.packageName;
int prefsId = neededDescription.accountPreferencesId;
try {
Resources resources = getPackageManager().getResourcesForApplication(packageName);
XmlResourceParser xpp = resources.getLayout(prefsId);
xpp.next();
String action = null;
String targetPackage = packageName; //default to the account pref package name...?
String targetClass = null;
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equals("intent")) {
int count = xpp.getAttributeCount();
for (int i = 0; i < count; i++) {
String name = xpp.getAttributeName(i);
if (name.equals("action")) {
action = xpp.getAttributeValue(i);
} else if (name.equals("targetPackage")) {
targetPackage = xpp.getAttributeValue(i);
} else if (name.equals("targetClass")) {
targetClass = xpp.getAttributeValue(i);
}
}
}
}
eventType = xpp.next();
}
if (action != null) {
startActivity(new Intent(action));
} else if (targetClass != null) {
startActivity(new Intent(createPackageContext(targetPackage, Context.CONTEXT_IGNORE_SECURITY), Class.forName(targetClass)));
}
} catch (PackageManager.NameNotFoundException e) {
} catch (Exception e) {
}
}
}
You may have database of your accounts info u can open it and design a similar style form for it this can solve your problem

What is android:sharedUserLabel and what added value does it add on top of android:sharedUserID?

The documentation (http://developer.android.com/guide/topics/manifest/manifest-element.html#uid) only states I can't use raw strings and the API level it was added, but doesn't explain why I would want to use it.
If I already set android:sharedUserID to "com.foo.bar" what value should I put in the string referenced by android:sharedUserLabel, and most importantly why!?
Thank you
As far as I understand from the AOSP actually you can use this label just to display a pretty name to a user (if you have several processes in the same uid). For instance, here is a part of code in the RunningState.java file:
// If we couldn't get information about the overall
// process, try to find something about the uid.
String[] pkgs = pm.getPackagesForUid(mUid);
// If there is one package with this uid, that is what we want.
if (pkgs.length == 1) {
try {
ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
mDisplayLabel = ai.loadLabel(pm);
mLabel = mDisplayLabel.toString();
mPackageInfo = ai;
return;
} catch (PackageManager.NameNotFoundException e) {
}
}
// If there are multiple, see if one gives us the official name
// for this uid.
for (String name : pkgs) {
try {
PackageInfo pi = pm.getPackageInfo(name, 0);
if (pi.sharedUserLabel != 0) {
CharSequence nm = pm.getText(name,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
mDisplayLabel = nm;
mLabel = nm.toString();
mPackageInfo = pi.applicationInfo;
return;
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
Basically, it does the following things. At first, it tries to get information about the overall process. If it has not find, it tries to get information using UID of the application as a parameter (this is a part of code that I've given here). If there is only one package with this UID the information about the process is got from this package. But if there are several packages (using shareUserId) then it iterates and tries to find official (pretty) name.
As a confirmation to my words I found the following string in MediaProvider:
<!-- Label to show to user for all apps using this UID. -->
<string name="uid_label">Media</string>
Thus, all process that uses android:sharedUserId="android.media" will have name Media.
I do not think that this feature will be used a lot by ordinary developers and is useful for them.

Categories

Resources