please help me I am trying to get text from stack of notifications. I am getting following error.
java.lang.NoSuchFieldException: No field mActions in class
Landroid/app/Notification$BuilderRemoteViews; (declaration of
'android.app.Notification$BuilderRemoteViews' appears in
/system/framework/framework.jar)
I am using NotificationListenerService and
private List<String> getMessages(Notification notification) {
RemoteViews views = notification.bigContentView;
if (views == null) views = notification.contentView;
if (views == null) return null;
List<String> text = new ArrayList<String>();
try {
Field field = views.getClass().getDeclaredField(Constants.ACTIONS);
field.setAccessible(true);
#SuppressWarnings("unchecked")
ArrayList<Parcelable> actions = (ArrayList<Parcelable>) field.get(views);
for (Parcelable p : actions) {
Parcel parcel = Parcel.obtain();
p.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
int tag = parcel.readInt();
if (tag != 2) continue;
parcel.readInt();
String methodName = parcel.readString();
if (methodName == null) {
continue;
} else if (methodName.equals(Constants.SET_TEXT)) {
parcel.readInt();
methodName.getBytes();
String gettingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel).toString().trim();
text.add(gettingText);
} else if (methodName.equals(Constants.SET_TIME)) {
parcel.readInt();
String gettingText = new SimpleDateFormat("h:mm a").format(new Date(parcel.readLong()));
text.add(gettingText);
}
parcel.recycle();
}
} catch (Exception e) {
Log.e("NotificationClassifier", e.toString());
}
return text;
}
This is working fine in android 4,5 but's its getting crash on Android 7, Getting error like mAction field not available.
Please any one help me to solve this, I am stuck from two days.
Thank you
You are using reflection to access method names and you are not switching the code for multiple platforms. The fields/methods that you are trying to access, change over time on multiple versions of the OS, so if you really want to have the reflection, you have to study what changes they were.
Generally, reflection should really be last resort, since on Android, the base code varies from version to version, and even from manufacturer to manufacturer.
Related
I am trying to update an element in a dynamodb table but it never updates I've done some digging and found that in the updateItem function it doesn't think that the anything in the document has changed any adivice on how fix this (also I am able to get element no problem)
Document builder = table.getMemoById(Room);
builder.commit();
builder.put("room_status","clean");
Document tmp = table.curr_table.updateItem(builder,
new Primitive(Room),
new UpdateItemOperationConfig().withReturnValues(ReturnValue.UPDATED_NEW));
Log.d(TAG, tmp.toString());
after using the debugger I found that the issue is in Primitive.java where the last line and this.value is compared to this.value but needs to be other.value the file is read only any suggestion on how to fix this
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final Primitive other = (Primitive) obj;
return Objects.equal(this.type, other.type) && Objects.equal(this.value, this.value);
}
turns out if you use the current version of the library 2.9.2 this is fixed I was using a much older version
In my app I need to monitorize recently added or updated packages, but since Oreo this is a hard task.
To do it I have a service that runs every X time to detect the new installed/updated apps.
The main core of this service is to call the getChangedPackages function from the PackageManager, but this function always returns null, even if I install or update any app from or not from the Play Store in the interval between two consequtive calls to getChangedPackages.
https://developer.android.com/reference/android/content/pm/PackageManager.html#getChangedPackages(int)
I need to request any permission to call this function? Is the getChangedPackages buggy?
private void _doProcess()
{
try
{
PackageManager package_manager = getPackageManager();
int sequence_number = ApplicationPreferences.getInteger(this, GET_CHANGED_PACKAGES_SEQUENCE_NUMBER_KEY, 0);
ChangedPackages changed_packages = package_manager.getChangedPackages(sequence_number);
LogUtilities.show(this, String.format("Retrieve recently apps installs/updates using sequence number %d returns %s", sequence_number, changed_packages == null ? "null" : "a not null object"));
if (changed_packages == null) changed_packages = package_manager.getChangedPackages(0);
LogUtilities.show(this, String.format("Retrieve recently apps installs/updates using sequence number %d returns %s", sequence_number, changed_packages == null ? "null" : "a not null object"));
if (changed_packages != null)
{
List<String> packages_names = changed_packages.getPackageNames();
LogUtilities.show(this, String.format("%d recently installed/updated apps", packages_names == null ? 0 : packages_names.size()));
if (packages_names != null) for (String package_name : packages_names) PackagesUpdatedReceiver.doProcessPackageUpdate(this, new Intent(isNewInstall(package_manager, package_name) ? Intent.ACTION_PACKAGE_ADDED : Intent.ACTION_PACKAGE_REPLACED).setData(Uri.parse(String.format("package:%s", package_name))));
LogUtilities.show(this, String.format("Storing %s is the sequence number for next iteration", changed_packages.getSequenceNumber()));
ApplicationPreferences.putInteger(this, GET_CHANGED_PACKAGES_SEQUENCE_NUMBER_KEY, changed_packages.getSequenceNumber());
}
else
{
LogUtilities.show(this, String.format("Storing %s is the sequence number for next iteration", sequence_number + 1));
ApplicationPreferences.putInteger(this, GET_CHANGED_PACKAGES_SEQUENCE_NUMBER_KEY, sequence_number + 1);
}
}
catch (Exception e)
{
LogUtilities.show(this, e);
}
}
My experimental results so far have shown that this PackageManager API method getChangedPackages() is not reliable: quite often the returned ChangedPackages value contains many unchanged packages. So I’ve decided to implement a similar feature in a class called PackageUtils, as shown below. The idea is to poll for all the installed packages, as shown in method getInstalledPackageNames() below, and compare the string list with a previously saved one. This comparison boils down to comparing 2 string lists, as shown in method operate2StringLists() below. To get a set of removed packages, use GET_1_MINUS_2_OR_REMOVED as operation. To get a set of added packages, use GET_2_MINUS_1_OR_ADDED as operation.
public class PackageUtils {
public static final int GET_1_MINUS_2_OR_REMOVED = 0;
public static final int GET_2_MINUS_1_OR_ADDED = 1;
// Get all the installed package names
public static List<String> getInstalledPackageNames(Context context) {
List<String> installedPackageNames = new ArrayList<>();
try {
PackageManager packageManager = context.getPackageManager();
List<ApplicationInfo> appInfoList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo appInfo : appInfoList) {
installedPackageNames.add(appInfo.packageName);
}
} catch (Exception e) {
e.printStackTrace();
}
return installedPackageNames;
}
// Compare 2 string lists and return differences.
public static Set<String> operate2StringLists(List<String> pkgList1, List<String> pkgList2, int operation) {
Set<String> result = null;
Set<String> pkgSet1 = new HashSet<String>(pkgList1);
Set<String> pkgSet2 = new HashSet<String>(pkgList2);
switch (operation) {
case GET_1_MINUS_2_OR_REMOVED:
pkgSet1.removeAll(pkgSet2);
result = pkgSet1;
break;
case GET_2_MINUS_1_OR_ADDED:
pkgSet2.removeAll(pkgSet1);
result = pkgSet2;
break;
default:
break;
}
return result;
}
}
The code has been tested on an Android Oreo device. It can reliably detect all added and removed packages between 2 time instances. However, it can’t detect updated packages in-between.
Finally got it. You have to create a variable called sequenceNumber, and update it every time you query changed packages.
private static int sequenceNumber = 0;
...
PackageManager pm = getContext().getPackageManager();
ChangedPackages changedPackages = pm.getChangedPackages(sequenceNumber);
if(changedPackages != null)
sequenceNumber = changedPackages.getSequenceNumber();
I programmed an app that can send a message to twitter with an image attached. It works! I tested it on several devices and asked other people to do the same. It even works for a Direct Message when a twitter friend is selected. However, it does not work when "Direct Message" is selected. This forces the user to select a friend directly instead of selecting him via "Direct Message" (which is really strange) otherwise the picture is not attached. Just have a look at the screenshot:
Here is my Xamarin Android programming code. Let me know how to fix it. Currently, all options work, even selecting my friend but not "Direct Message". I also need to tell that I do not have any issue with the twitter text I expect to see in the tweet.
public bool TweetImage(Bitmap imageToTweet)
{
var messageIntent = context.FindMessageIntent(this.twitterConstants.PackageName);
if (messageIntent == null)
{
return false;
}
string outputFileBMP = SaveBitmap(imageToTweet);
context.Tweet(messageIntent, outputFileBMP, this.twitterConstants.DefaultTwitterText, this.twitterConstants.ChooserMessage);
return true;
}
and
public static Intent FindMessageIntent(this ContextWrapper contextWrapper, params string[] packageNames)
{
Intent wantedIntent = new Intent();
wantedIntent.SetType("text/plain");
var resolveInfos = contextWrapper.PackageManager.QueryIntentActivities(wantedIntent, PackageInfoFlags.MatchDefaultOnly);
var result = (from r in resolveInfos
from p in packageNames
where p == r.ActivityInfo.PackageName
select p).FirstOrDefault();
if (result != null)
{
wantedIntent.SetPackage(result);
return wantedIntent;
}
return null;
}
and
public static void Tweet(this ContextWrapper contextWrapper, Intent messageIntent, string filePath = null, string message = null, string chooserMessage = null)
{
if (filePath != null)
{
using (var file = new Java.IO.File(filePath))
{
messageIntent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(file));
}
}
if (message != null)
{
messageIntent.PutExtra(Intent.ExtraText, message);
}
if (chooserMessage != null)
{
using (var chooser = Intent.CreateChooser(messageIntent, chooserMessage))
{
contextWrapper.StartActivity(chooser);
}
return;
}
contextWrapper.StartActivity(messageIntent);
}
Please note that I am using Android and need a solution based on Android (intent based).
Sadly, Twitter don't provide API access for uploading images via DM.
If you are able to use Twitter's private API, you should be able to attach a media_id to your DM. But other than that, you're out of luck.
Sorry.
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
I have a Tab Activity and with in Tab, im using Activity Group. and using LocalActivityManger,
im trying to destroy an Activty using the following function call provided in LocalActivityManger class
manager.destroyActivity(mIdList.get(index), true);
in the code. but later i found that there is a bug in Android impl for this
The exact source of the problem is in the following chunk of code in LocalActivityManager.java:
public Window destroyActivity(String id, boolean finish) {
LocalActivityRecord r = mActivities.get(id);
Window win = null;
if (r != null) {
win = performDestroy(r, finish);
if (finish) {
mActivities.remove(r);
}
}
return win;
}
The variable mActivities is the hashmap containing the activity records and it uses the id passed into startActivity() as the key. In this method, the object passed in for the key is a LocalActivityRecord instead of the id string. This results in the hashmap not finding the entry and thus not removing it.
More info refer this link. http://code.google.com/p/android/issues/detail?id=879More
and i found a work around for this issue and im using following function to fix the problem.
public boolean destroy(String id) {
if(manager != null){
manager.destroyActivity(id, false);
try {
final Field mActivitiesField = LocalActivityManager.class.getDeclaredField("mActivities");
if(mActivitiesField != null){
mActivitiesField.setAccessible(true);
#SuppressWarnings("unchecked")
final Map<String, Object> mActivities = (Map<String, Object>)mActivitiesField.get(manager);
if(mActivities != null){
mActivities.remove(id);
}
final Field mActivityArrayField = LocalActivityManager.class.getDeclaredField("mActivityArray");
if(mActivityArrayField != null){
mActivityArrayField.setAccessible(true);
#SuppressWarnings("unchecked")
final ArrayList<Object> mActivityArray = (ArrayList<Object>)mActivityArrayField.get(manager);
if(mActivityArray != null){
for(Object record : mActivityArray){
final Field idField = record.getClass().getDeclaredField("id");
if(idField != null){
idField.setAccessible(true);
final String _id = (String)idField.get(record);
if(id.equals(_id)){
mActivityArray.remove(record);
break;
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
return false;
}
now the problem is, this fix is working fine in Android API versions 2.1,2.2 and 2.3 but i tested in 3.0 . but it is failing there. no exceptions.
I want to know in which API version this bug has been fixed.
And also what fix can i make for this so that it will work fine in all the API versions after 2.1 .
Thank u