Android SMS intent stuck with the same body and same recepient - java

So my android application detects when location changes and then it notifies the user and makes him take action either call a number or send SMS.
The SMS is sent to a saved number and its body is "I'm at " + fullAddress
private NotificationCompat.Builder buildNormal(CharSequence pTitle,String fullAddress) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this);
Intent in = new Intent(this,MainActivity.class);
PendingIntent pMainIntent = PendingIntent.getActivity(this, 0,
in, 0);
if(getSavedDataString("gNumber")!=null)
{
String url = getSavedDataString("gNumber");
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
//Intent smsIntent = new Intent(Intent.ACTION_SENDTO,Uri.parse("smsto:"
//+ Uri.encode(getSavedDataString("gNumber").substring(4))));
//intent.setData());
//startActivity(intent);
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
//smsIntent.setType("vnd.android-dir/mms-sms");
smsIntent.putExtra("address", getSavedDataString("gNumber").substring(4));
smsIntent.putExtra("sms_body","I'm at " + fullAddress);
smsIntent.setData(Uri.parse("smsto:"
+ Uri.encode(getSavedDataString("gNumber").substring(4))));
PendingIntent psmsIntent = PendingIntent.getActivity(this, 0,
smsIntent, 0);
builder.addAction(android.R.drawable.ic_menu_call, "Call", pIntent);
builder.addAction(android.R.drawable.sym_action_email, "Send SMS", psmsIntent);
}
else
{
builder.addAction(0, "Choose Guardian", pMainIntent);
}
builder.setAutoCancel(true).setDefaults(Notification.DEFAULT_ALL);
// set the shown date
builder.setWhen(System.currentTimeMillis());
// the title of the notification
builder.setContentTitle(pTitle);
// set the text for pre API 16 devices
builder.setContentText(pTitle);
// set the action for clicking the notification
builder.setContentIntent(pMainIntent);
// set the notifications icon
builder.setSmallIcon(R.drawable.ic_home);
//builder.setSound(android.)
// set the small ticker text which runs in the tray for a few seconds
builder.setTicker("Location Change Alert");
// set the priority for API 16 devices
//builder.setVibrate(pattern)
builder.setPriority(Notification.PRIORITY_DEFAULT);
return builder;
}
it shows here that the notification that shows to the user contains 2 actions to call or to send message and it sends it to the presaved number gNumber
The problem is after i press the action to send sms and then discard that message without sending it also deleting it from draft and all that.
and then the app detects another location change so it sends a different notification with different fullAddress the intent is still stuck at the same text body!!
I also tried to change the recipient and it gets stuck on the old recipient too. I have to either restart the device or send the message I once discarded.
I also tried to change from ACTION_VIEW to ACTION_SEND or ACTION_SENDTO but all in vain.
I want to know if there's a solution to this intent getting stuck on the same body and recipient other than changing this intent totally and using SMSManager
Help please.

When your app requests a PendingIntent, the system keeps a token on behalf of your app to perform an action as though your app is actually doing it. It is done this way so that, even if your app is killed, whatever process receives the PendingIntent can still follow through with it.
When these tokens are created, certain info is recorded, e.g. the operation, the the action, etc. If your app were to request another PendingIntent with the same info, the same token will be returned. Now, the info used to determine if they are the same or different does not include the extras that the Intent itself carries. So when your app requests the same SMS operation with only different Intent extras, you're going to get the same token with the original extras over and over again, unless you pass a flag to indicate differently.
As for the difference between the flags: FLAG_CANCEL_CURRENT "ensures that only entities given the new data will be able to launch it. If this assurance is not an issue, consider FLAG_UPDATE_CURRENT." In your case, I don't think this is an issue, so FLAG_UPDATE_CURRENT should be sufficient. If it is a concern, use FLAG_CANCEL_CURRENT.
The quoted is directly from the docs here.

Related

Android 10 - Using PackageManager to install new version of apk instead of Intents doesn't really work

The way my apk updates currently is through the new apk installing itself over the old one(while not overwriting the local database or settings).
So since Android 10(API 29) ACTION_VIEW was deprecated so this doesn't really work anymore:
Intent intent = new Intent(Intent.ACTION_VIEW);
//output file is the apk downloaded earlier
intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
startActivity(intent);
Following different answers I've found over the internet I need to start using PackageInstaller instead. Looking at the demo found in the Android docs I get to this:
Intent intent = new Intent(PSMentorActivity.this,InstallApkSessionApi.class);
intent.putExtra("apkFile",outputFile);
this.startActivity(intent);
Where InstallApkSessionApi contains a button that when pressed should start the install window:
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
addApkToInstallSession(file, session);
// Create an install status receiver.
Context context = InstallApkSessionApi.this;
Intent intent = new Intent(context, InstallApkSessionApi.class);
intent.setAction(PACKAGE_INSTALLED_ACTION);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();
// Commit the session (this will start the installation workflow).
session.commit(statusReceiver);
Simple enough, albeit more complicated compared to the past. The response I get in onNewIntent is always:
case PackageInstaller.STATUS_FAILURE:
Toast.makeText(this, "Install failed!10 " + status + ", " + message,
Toast.LENGTH_SHORT).show();
break;
where the status and message take the following values: status=1, message= "INSTALL_FAILED_INTERNAL_ERROR: Permission denied".
So I assumed it was a problem with permissions. I already had permissions in place over reading and writing to storage. Other related permissions are: INSTALL_PACKAGES and REQUEST_INSTALL_PACKAGES which I cannot use due to the first not being intended for third party uses and the latter being signature level.
Is there something I am terribly missing or is there not a way for me to update my Apk without going through google play?
I've faced the same issue and tried the same way(PackageInstaller) just like you did. It doesn't work.
So, here is a solution for you,
if(android.os.Build.VERSION.SDK_INT >= 29){
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.fromFile(outputFile));
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
}else{
Intent intent = new Intent(Intent.ACTION_VIEW);
//output file is the apk downloaded earlier
intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-
archive");
startActivity(intent);
}
I have tested in Android 10 (Google Pixel 2, One+7, Samsung s10) it's working fine. If you are still facing any problem please let me know.
Note: Your version code must be greater than the old one.
So after help and some more searching the great internet, I've been able to make both methods work for me. I still don't really understand what causes the problem. Previously I was creating the Uri used in the intent from the file directly with Uri.fromFile(file). This works for anything under Android 10. The new way I handle this is by using a provider and getting the file using that.
Current method, to be used for a while until I can properly implement PackageManager installation(still have some issues to fix).
Uri urlapk = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID+".fileProvider",outputFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(urlapk, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Using PackageManager just as specified in my question with the following difference (the inputStream is now being build from an Uri):
private void addApkToInstallSession(Uri uri, PackageInstaller.Session session)
throws IOException {
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
InputStream is = getContentResolver().openInputStream(uri)) {
byte[] buffer = new byte[16384];
int n;
while ((n = is.read(buffer)) >= 0) {
packageInSession.write(buffer, 0, n);
}
}
}
The main problem I have with PackageManager is that it closes my app while it installs providing no default feedback to the user. So I guess I will have to "make" that feedback. I will move on to PackageManager as ACTION_VIEW is deprecated for apks.

How to set reply action in below nougat version like whatsapp?

Am trying to set reply action in push notification like Whatsapp. How to show popup window like whatsapp for replying in push notification.
I have to open a dialog like below image when click of reply.
Direct reply is available on devices with Android N or higher.
First, you need to build remote input, that can be passed into notification builder.
RemoteInput remoteInput = new RemoteInput.Builder(KEY_INLINE_REPLY)
.setLabel("Response")
.build();
Then you can create your notification
NotificationCompat.Action replyAction =
new NotificationCompat.Action.Builder(android.R.drawable.ic_custom_icon,"Respond", respondPendingIntent)
.addRemoteInput(remoteInput)
.build();
nofitication.addAction(replyAction);
Next, we need to retrieve the input. In the component started by the pending intent (e.g. an Activity or Service), the remote input is available on the Intent. The user’s input is accessed using the same key that was used when building the remote input:
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
CharSequence reply = remoteInput.getCharSequence(KEY_INLINE_REPLY);
//do something awesome with the reply
}
After the reply has been entered, a progress spinner is displayed to indicate that something is happening. It is up to you to stop the spinner, once the reply has been processed. There are at least a couple of ways to handle this:
Cancel the notification by calling cancel
Re-issue the notification, and include an updated message (e.g. “Successful reply”)
You should add backwards compatibility
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//we are running Nougat
respondIntent = new Intent(context, NotificationIntentService.class);
respondPendingIntent = PendingIntent.getService(context, 0, respondIntent, PendingIntent.FLAG_CANCEL_CURRENT);
} else {
//we are running a version prior to Nougat
respondIntent = new Intent(context, MainActivity.class);
respondPendingIntent = PendingIntent.getActivity(context, 0, respondIntent, PendingIntent.FLAG_CANCEL_CURRENT);
}
You can check more here Direct reply in Android N

Android: open video picker and filter videos seen by length

This is my code for opening up the picker for Videos and Images - however I need to not show Videos that are longer than 5 minutes in length. Is this possible?
public void startChoosePhotoFromLibrary() {
if (checkOrRequestExternalStoreagePermission()) {
if (Build.VERSION.SDK_INT < 19) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/* video/*");
startActivityForResult(photoPickerIntent, PICK_PHOTO_ACTIVITY_REQUEST_CODE);
} else {
Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.setType("*/*");
photoPickerIntent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});
startActivityForResult(photoPickerIntent, PICK_PHOTO_ACTIVITY_REQUEST_CODE);
}
}
}
This is my code for opening up the picker for Videos and Images
ACTION_PICK does not use MIME types. ACTION_PICK picks from a collection of content, where that collection is identified by the Uri that you supply in the Intent.
Also, MIME types do not have spaces in them.
Is this possible?
Not via those Intent actions, or via any content-selection mechanism that is part of the Android SDK.
You are welcome to query the MediaStore for videos, and there may be a way to filter such videos by length. But then you would need to present your own UI for allowing the user to choose something from the query results (e.g., ListView, RecyclerView).

Make a Call in on number followed by # key

I am working on the calling app where I make call on button click but if the number just followed by # then it does not take the # key at the last of phone number.
For Example if I want to make a call on *123# from app then it only shows *123 in the calling screen in phone. Please suggest me where I am going wrong.
Here is my code for call on *123# on button click.
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + phoneNumber));
callIntent.setData(Uri.parse("tel:" + "*123#"));
startActivity(callIntent);
try this...
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ Uri.encode("*123#")));
startActivity(callIntent);
You need to escape the # as a URI entity: %23

when i invoke gmail to send some advice the bluetooth come out, too

this is my code to invoke gmail.
private void sendMail() {
// Device model
String PhoneModel = android.os.Build.MODEL;
// Android version
String AndroidVersion = android.os.Build.VERSION.RELEASE;
final Intent emailIntent = new Intent(
android.content.Intent.ACTION_SEND);
emailIntent.setType("plain/text");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
new String[] { "****#gmail.com"});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
"'some feedbace...");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "—— phoneModel:"
+ PhoneModel + ";ROM:" + AndroidVersion);
startActivity(Intent.createChooser(emailIntent, "Sending mail..."));
}
when i click the menu to invoke the gmail to send feedback,the bluetooth come out too,with the gmail,and waiting for me to select one.but i just want to invoke the gmail app.what's wrong with my code .anybody help please!
You can try this:
emailIntent.setType("application/octet-stream");
Or alternatively you can use PackageManager to build a more limited set of Intents, and show your own dialog for the user to select their email app.
but actually you are swimming against the tide of Android with what you're doing. Android is designed to allow for a message to be "Sent" and to show all apps that accept that intent, so be careful you don't remove options the user may actually want.
You can try using android.content.Intent.ACTION_SENDTO instead of ACTION_SEND. If you have multiple email clients installed it will still prompt you to choose one though.
Have a look at this question for more info.
If you absolutely have to use Gmail and not have android prompt the user you can try what is suggested in this answer (Note: I haven't tried this):
If you specifically want GMail, you have to be a bit cleverer. (Note
that the correct MIME type is actually "text/plain", not "plain/text".
Do to an implementation oddity, GMail seems to be the only activity
which responds to the latter, but this isn't a behavior I would count
on.)
private void sendMail() {
String body = "\n 机型:" + android.os.Build.MODEL + ";ROM:"
+ android.os.Build.VERSION.RELEASE;
Uri mailUri = Uri.parse("mailto:byirain#gmail.com");
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "'易学堂'问题反馈与建议");
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
startActivity(emailIntent);
}
I finally finished it, though the uri, like before

Categories

Resources