I'm developing an android app and part of it needs to read WhatsApp messages by the notifications and analyze them.
I'm using a NotificationListenerService and it is working, however, I'm having a problem that notifications are being "analyzed" twice when I get the notification and then get a Message from other chat.
What I want is to analyze each message (Notification) once.
I already tried to save the notification sortKey or the StatusBarNotification key in a HashSet and then check, if it already contains the key every time, however that does not work.
Here is the code that in onNotificationPosted function -
String pack = sbn.getPackageName();
if (pack.equals("com.whatsapp")) {
Bundle extras = sbn.getNotification().extras;
if (extras.getCharSequence("android.text") != null && extras.getString("android.title") != null) {
if (sbn.getNotification().getSortKey() != null) {
String title = extras.getString("android.title");
String text = extras.getCharSequence("android.text").toString();
//Checking if it's from specic group and analyzing the message and
//doing what needs to be done, not related to the problem.
}
}
}
The result I want is that every notification will be analyzed once and not get posted again if some other messages arrive in other chats
Without knowing the inner workings of WhatsApp, it's hard to tell what you should exactly do, because it appears they reuse Actions/Extras for various things (which makes sense anyway).
In this case though, you could keep a list/map of the ones you've already "analyzed" and if you get it again, discard it.
Related
I have an application at the Google Play and there are already a few hundred of users.
Now, I'm working on an update that will allow users to share user-to-user content via Firebase Dynamic Links.
In order to do so, I created a subdomain and all the required things and I added this code:
FirebaseDynamicLinks.getInstance()
.getDynamicLink( getIntent() )
.addOnSuccessListener( this, pendingDynamicLinkData -> {
Uri deepLink = null;
if (pendingDynamicLinkData != null) {
deepLink = pendingDynamicLinkData.getLink();
String bookID = deepLink.getQueryParameter( "id" );
if (bookID != null) {
startBookDetailActivity( bookID );
}
}
} )
.addOnFailureListener( this, e -> {
}
);
However, the users who already have the app installed on their phone don't have this piece of code in their application which means that if they click on the dynamic link it won't do the job.
Is there any other way I can handle the dynamic link for the period until all users get the latest version?
Thank you
You could have the user copy and past the code into the app but ultimately, this also requires that the app is updated to do so.
Perhaps you could use a cloud function that would return the data in the browser rather than the app, you could do this with a button that appears after a second and manually invoke the call.
But it might just be easier to encourage users to update and implement a callback system using real-time or firestore as a user inbox system for this kind of edge case.
Looking to handle a deep link from the Google Assistant. As I only have an emulator at the moment I am having trouble testing it (from what I have read it requires a real device). That said, I was wondering if I am handling it the correct way. I am unfamiliar with Kotlin and my code was turning into Spaghetti trying to integrate, so I put this together in my existing launcher activity just to try and get it bootstrapped for now. The manifest and actions.xml were set up like the fitness app tutorial.
Am I doing this correctly?
if (mAuth.getCurrentUser() != null) {
data = this.getIntent().getData();
if (data != null && data.isHierarchical()) {
uriData = data.toString();
containsStart = containsIgnoreCase(uriData,"start");
containsRun = containsIgnoreCase(uriData,"run");
if(containsStart && containsRun) {
Intent intent = new Intent(getApplication(), RunActivity.class);
intent.putExtra("runStart", true);
startActivity(intent);
}
}
else {
checkUserAccType();
}
//Else, if there is no current user, start the Authentication activity
}
A few observations and recommendation about your code:
Instead of using containsIgnoreCase uses getPath() and match the path. See example.
Also, for the activity parameter use URL query param instead of containsIgnoreCase. See example
Starting the activity or fragment. I assume startActivity and checkUserAccType will handle that part. See example.
// Else... section should go one line below.
Authentication. It looks fine. And it seems you're using Firebase by the getCurrent method signature. See example
I am working on stripe-terminal-android-app, to connect to BBPOS 2X Reader device,
wanted to click-item from list,(recyclerView).
I am trying to do:
when list of devices appears(readers), I am checking if readers.size()==1, then click first-device from list,else show recyclerView();
I have very less experience in Android(coming from JS, PY), :)
After going through debugger to understand flow of program-running, I used F8 key, or stepOver the functions one by one,
and where value is assigned to convert in displayble-format in adapter as here.
public ReaderAdapter(#NotNull DiscoveryViewModel viewModel) {
super();
this.viewModel = viewModel;
if (viewModel.readers.getValue() == null) {
readers = new ArrayList<>();
} else {
readers = viewModel.readers.getValue();
if(readers.size() == 1){
Log.e(TAG, "readers.size() is 1 "+ readers.size());
}
}
}
then in ReaderHolder-file, values are bind() as
void bind(#NotNull Reader reader) {
binding.setItem(reader);
binding.setHandler(clickListener);
binding.executePendingBindings();
}
}
I tried assigining button and manually clicking when only-one device appears, by clicing on reader[0], can't do that by findViewById inside Adapter file, to call onClick() method manually,
I tired another StackOverflow's answer but didn't understood, from here.
Main fragment is discovery-fragment,
how can I click first-device by checking readers.size()==1, then click onClick()?
my final-goal is to automate, whole stripe-terminal-payment process on android.
extra-info:
I am fetching data from python-odoo server, then using url, will open app through browser, (done this part), then device will be selected automatically as everytime-no any devices will be present except one,
so will automatically select that from recyclerView, then proceed.
I have asked for help in detailed way on GitHub-issues, and started learning Android's concepts for this app(by customizing stripe's demo app, which works great, but I wanted to avoid manually clicking/selection of devices).
I'm querying the calendar data like this:
// Constructor of the class
mCursor = context.getContentResolver().query(CalendarContract.Events.CONTENT_URI, mColumns, null, null, null);
updateEvents();
//contents of updateEvents:
events.clear();
mCursor.moveToFirst();
mLastUpdate = System.currentTimeMillis();
while (!mCursor.isAfterLast())
{
long end = mCursor.getLong(2);
if (end > mLastUpdate)
events.add(new Event(mCursor));
mCursor.moveToNext();
}
The code manages works on mobile device, however when it's run on a Wear device there appears to be no data.
I've found a WaerableCalendarContract, but it doesn't seem to contain the Events class that I use to fill the mColumns class to select the desired data.
How can I do the same on the Wear?
WearableCalendarContract describes a 24 hour long window (starting from the current time) of calendar data. You don't see Event there, because we transfer Instances objects. As you can see in base interface for Instances, it does include Events columns too, so you should be able to fetch the data that you need from there.
If you need more than 24 hours of data, you will need sync it yourself. Query the calendar on the phone and then for each event that interests you, construct a DataItem. This is a little tricky, so I would recommend using the WearableCalendarContract instead.
I think you have to sync your data to the Wear app manually, a.k.a fetch it from the ContentProvider on the phone and then send it to the wearable via the DataItem API. Read more about syncing data between phone<->wear HERE.
Hey I am trying to send MIDI data from a Java class to a MIDI device connected via USB. I did this once like 2 years ago and it worked, but I somehow can't find the project anymore.
The example Java code runs fine;
myMsg = new ShortMessage();
myMsg.setMessage(ShortMessage.NOTE_ON, 0, 60, 93);
timeStamp = -1;
Receiver rcvr = MidiSystem.getReceiver();
rcvr.send(myMsg, timeStamp);
Simple stuff. 5 lines of code and the message appears on the device. The problem is, that this way, only the standard device is set up and ready to receive MIDI. I can't ask my users to set the device of desire as standard device every time they want to use my application. (the Receiver acts as output destination/port to the input of the physical device I am connected to)
I am now trying to set up the Receiver by doing the following:
MidiDevice.Info[] infoA=MidiSystem.getMidiDeviceInfo();//array where all the device info goes
for (int x=0;x<infoA.length;x++){
System.out.println("in "+infoA[x]); //this displays all the devices
}
MidiSystem.getMidiDevice(infoA[d]); //d is set to an integer that represents the item number on the device list of the device I wanna send MIDI to
System.out.println(infoA[d]);//last check if the correct device is selected
MidiDevice MidiOutDevice = MidiSystem.getMidiDevice(infoA[d]); //setting this to "my" device in order to set the Receiver
maschineReceiver= MidiOutDevice.getReceiver();
Sequencer MidiOutSequencer = MidiSystem.getSequencer();
MidiOutSequencer.getTransmitter().setReceiver(maschineReceiver); //probably unnecessary last 2 line but I gave this a try in case it helps
if I now do maschineReceiver.send(myMsg, timeStamp);, nothing happens at all. I also tried different devices but it didn't get any better. I am sure it can't be a very hard difficult thing to do as it something I actually achieved 2 years ago when my coding skills were awful but I just can't find the mistake right now, no matter how often I reread the Java documentation, it just won't work whatever I do.
Thanks in advance
To actually reserve a device for your program, you need to use the MidiDevice method open:
if (!(device.isOpen())) {
try {
device.open();
} catch (MidiUnavailableException e) {
// Handle or throw exception...
}
}