Android App Widget broadcast doesn't work - java

I have a widget with 1 image view and 1 text view.
I want to change image on click. Consider following code doesn't catch touch event
package com.sigrlami.rixvpn.widget;
import java.util.Random;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import com.sigrlami.rixvpn.R;
public class VpnWidgetProvider extends AppWidgetProvider {
private boolean currentStatus = false;
// log tag
private static final String LOG = "com.sigrlami.rixvpn.widget.VpnWidgetProvider";
//public static final String CLICK = "com.sigrlami.rixvpn.CLICK";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context, VpnWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds) {
// Create some random data
int number = (new Random().nextInt(100));
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.vpn_widget);
Log.w("WidgetExample", String.valueOf(number));
// Set the text
remoteViews.setTextViewText(R.id.layout_vpn_widget_tv_Check, String.valueOf(number));
// Register an onClickListener
Intent intent = new Intent(context, VpnWidgetProvider.class);
intent.setAction(appWidgetManager.ACTION_APPWIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.layout_vpn_widget_iv_Check, pendingIntent);
if (currentStatus = false) {
remoteViews.setImageViewResource(R.id.layout_vpn_widget_iv_Check, R.drawable.on);
} else {
remoteViews.setImageViewResource(R.id.layout_vpn_widget_iv_Check, R.drawable.off);
}
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
if (currentStatus == false) {
currentStatus = true;
} else {
currentStatus = false;
}
}
super.onReceive(context, intent);
}
}
Looking to this part through debugger shows nothing strange, but when I change to getActivity() it shows that I'm trying to start a activity that does not exist. I see that something is going on, but this is useless to me.
// Register an onClickListener
Intent intent = new Intent(context, VpnWidgetProvider.class);
intent.setAction(appWidgetManager.ACTION_APPWIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.layout_vpn_widget_iv_Check, pendingIntent);
But it works 1 time when app deployed to device.
Any suggestions what I have done wrong?

For handling click in AppWidgetProvider you need to use custom broadcast reciver as:
<receiver android:name="VpnWidgetProvider"
android:label="#string/widget_title" android:exported="false" android:icon="#drawable/volume">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.xxxx.xxxx.VpnWidgetProvider.ACTION_WIDGET_REFRESH"/>
<action android:name="android.appwidget.action.APPWIDGET_DELETED"/>
<action android:name="android.media.RINGER_MODE_CHANGED"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
and in AppWidgetProvider class:
public class VpnWidgetProvider extends AppWidgetProvider {
public static String ACTION_WIDGET_REFRESH = "ActionReceiverRefresh";
//your code here...
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
//you code here...
Intent intent = new Intent(context, VpnWidgetProvider.class);
intent.setAction(appWidgetManager.ACTION_WIDGET_REFRESH);//get action here
//you code here...
see this full working example for handling onclick on home Screen AppWidget:
Silenttoggle Home Screen Widget

Related

Add Button to Notification

I need a button in my Notification, however everything i find online is not working. I need it to cancel playing an alarm that will go off at a designated time. Can anyone link me some articles to read or tell me what code i should use in order to get this to work.
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.media.RingtoneManager;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import com.example.oceansscheduler.MainActivity;
import com.example.oceansscheduler.R;
public class AlarmReceiver extends BroadcastReceiver {
public void showNotification(Context context, String title, String message, Intent intent, int reqCode) {
PendingIntent pendingIntent = PendingIntent.getActivity(context, reqCode, intent, PendingIntent.FLAG_ONE_SHOT);
String CHANNEL_ID = "channel_name";// The id of the channel.
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_baseline_alarm_24)
.setContentTitle(title)
.setStyle(new NotificationCompat.BigTextStyle())
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentText(message)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Channel Name";// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
notificationManager.createNotificationChannel(mChannel);
}
notificationManager.notify(reqCode, notificationBuilder.build()); // 0 is the request code, it should be unique id
Log.d("showNotification", "showNotification: " + reqCode);
}
#Override
public void onReceive(Context context, Intent intent) {
SQLiteDatabase db = context.openOrCreateDatabase("NotificationDatabase", android.content.Context.MODE_PRIVATE, null);
Cursor data = db.rawQuery("SELECT * FROM PersonalNotif", null);
Log.d("Count", String.valueOf(data.getCount()));
if (data.getCount() > 0) {
data.moveToFirst();
String NameOfNotif = (data.getString(0));
Toast.makeText(context, NameOfNotif, Toast.LENGTH_LONG).show();
int reqCode = 1;
Intent intentNotif = new Intent(context, MainActivity.class);
showNotification(context, NameOfNotif, "Your Reminder is going off!", intentNotif, reqCode);
}
}
};
To add a button in Your notification, You need to use addAction function.
It requires an Action object which needs:
an icon (oddly),
a title,
a PendingIntent
The PendingItent can encapuslate an Intent that can be a Service that will be delegated to cancel playing the alarm or a Receiver that will do it.
Let's stick with a receiver. We can create one - CancelAlarmReceiver:
public class CancelAlarmReceiver extends BroadcastReceiver {
public static String ACTION_CANCEL = "actionCancelAlarm";
public CancelAlarmReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_CANCEL)) {
// Here You will cancel the alarm.
}
}
}
Remember to register it in the Manifest:
<receiver
android:name=".CancelAlarmReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.your.app.CancelAlarmReceiver.ACTION_CANCEL" />
</intent-filter>
</receiver>
Later on, when creating a notification with a builder, You will have to provide an action leading to our Receiver:
Intent cancelIntent = new Intent(this, CancelAlarmReceiver.class);
cancelIntent.setAction(ACTION_CANCEL);
PendingIntent cancelPendingIntent =
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(
new Notification.Action(
R.drawable.ic_alarm_cancel,
getString(R.string.cancel_alarm),
cancelPendingIntent
)
);
This should make sure that a button will appear by Your notification and it will trigger the receiver and disable the alarm (or whatever You will make it to do).

Widget does not work if app is killed Android 11

I have an application which starts a service when the widget is tapped.
This is the class for the widget:
public class PlayWidget extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int currentWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.playwidget);
views.setTextViewText(R.id.bLevelText, "My widget");
Intent intent = new Intent(context, PlayService.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pending = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.imageButton11, pending);
appWidgetManager.updateAppWidget(currentWidgetId, views);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds[i], R.id.imageButton11);
}
}
}
This is the manifest declaration for the Widget:
<receiver
android:name=".widget.PlayWidget"
android:icon="#drawable/play">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/playwidget_info" />
</receiver>
This is the manifest declaration for the Service:
<service android:name=".widget.PlayService"/>
The problem is that on Android 11, when the app is killed and i press the widget, the Service won't start anymore. Anyone has an idea on how can i fix this issue?
I have found an workaround for this issue, by calling a BroadcastReceiver from the OnUpdate function, and then starting the Service from the BroadcastReceiver :
Intent intent = new Intent();
intent.setAction(START_SERVICE);
intent.setClassName(StartServiceReceiver.class.getPackage().getName(), StartServiceReceiver.class.getName());
PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.imageButton11, pending);
This is the code for the BroadcastReceiver:
public class StartServiceReceiver extends BroadcastReceiver {
public static final String START_SERVICE= "start_service";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(START_SERVICE)) {
context.startService(new Intent(context, PlayService.class));
}
}
}
And the manifest declaration for the BroadcastReceiver:
<receiver android:name=".StartServiceReceiver" android:label="#string/app_name"/>

How to send a notification at the exact time when the application is closed?

I am new to android studio. I need to create a note application with a reminder function. I decided to do this through the alarmmanager, but it only works when the application is open. Is it realistic to do this only through services?
I noticed that in the google keep application, when creating a reminder, a new service is created. How to do this?
Part of the code from the activity:
public void alarm(Calendar c) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
intent.putExtra("title",editTask.getText().toString());
PendingIntent pen = PendingIntent.getBroadcast(this, 1, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),pen);
AlertReciver.java
package denchic45.myapp.appmy;
import android.content.BroadcastReceiver;
import android.content.Intent; import android.widget.Toast;
import android.content.Context;
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent = new Intent(context, Services.class);
context.startService(intent);
Toast.makeText(context, "alarm", Toast.LENGTH_SHORT).show();
} }
Services.java
package denchic45.myapp.appmy;
import android.app.IntentService;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
public class Services extends IntentService {
public Services() {
super("public services");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Context context = getApplicationContext();
Toast.makeText(context, "WORK", Toast.LENGTH_SHORT).show();
final String CHANNEL_ID = "1";
if(Build.VERSION.SDK_INT = Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"001",
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("description");
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("dd")
.setSmallIcon(R.mipmap.ic_launcher);
notification.build();
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(1,notification.build());
} else {
NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("dd")
.setSmallIcon(R.drawable.note)
.setChannelId(CHANNEL_ID);
notification.build();
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(1,notification.build());
}
} }
Part of the code from the manifest:
<receiver android:name=".AlertReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".Services"/>

Logical Flow of all Intents (PendingIntents) in this app widget snippet

I am learning how to build home screen widget in Android. This code is for an app widget to toggle RingerMode from NORMAL to SILENT and vice-versa.
This works fine but I need a full in-sight of logical flow (i.e which gets initiated when, goes where, does what, dies when) of all the intents in this.
Please help me understand this topic clearer.
package com.dummies.android.silentmodetoggle;
import android.app.Activity;
import android.app.IntentService;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.util.Log;
import android.widget.RemoteViews;
public class AppWidget extends AppWidgetProvider {
public static String tag ="SilentModeToggleWidget";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d(tag, "onReceive() first line");
if(intent.getAction()==null)
{
//Do Something
Log.d(tag, "before startService()");
context.startService(new Intent(context, ToggleService.class));
}
else{
super.onReceive(context, intent);
}
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Do something in specified intervals
context.startService(new Intent(context, ToggleService.class));
}
public static class ToggleService extends IntentService{
public ToggleService(){
super("AppWidget$ToggleService");
Log.d(tag, "In ToggleService construcor");
}
#Override
protected void onHandleIntent(Intent arg0) {
Log.d(tag, "In ToggleService > onHandleIntent");
// TODO Auto-generated method stub
ComponentName cn = new ComponentName(this, AppWidget.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(this);
mgr.updateAppWidget(cn, buildUpdate(this));
}
private RemoteViews buildUpdate(Context context){
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
AudioManager audioManager = (AudioManager)context.getSystemService(Activity.AUDIO_SERVICE);
if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT){
updateViews.setImageViewResource(R.id.phoneState, R.drawable.phone_on);
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
else{
updateViews.setImageViewResource(R.id.phoneState, R.drawable.phone_silent);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
Intent i = new Intent(this, AppWidget.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.phoneState, pi);
return updateViews;
}
}
}
still not sure on what are u asking, but I'll try to answer, if not what u want, please explain in a different way.
Intent are usually started immediatly. You create an Intent can start it by calling startService or startActivity, so for example:
context.startService(new Intent(context, ToggleService.class));
on both times you wrote the above code, the service ToggleService is immediatly started.
PendingIntent on the other hand are saved to be started at later time, so for example
updateViews.setOnClickPendingIntent(R.id.phoneState, pi);
on the above line, the AppWidget Broadcast is started when the user clicks on R.id.phoneState in your HomeScreen AppWidget.
Each PendingIntent is stored in the system with a certain ID, this ID is the requestCode parameter (you used zero on your code)... that means, that if you create a different PendingIntent with the same ID it will override it, meaning a different action will be started when the user clicks on R.id.phoneState

Broadcasting SMS from android on boot complete

I am trying to get SMS broadcasted to few mobile numbers every time the sim card is changed. Unfortunately, it doesn't work when I try it on my device. Can someone identify the issue in my following code please. The onBoot permissions are all added.
public class SendSmsOnTheft extends BroadcastReceiver
{
static void sendSMS(String destinationAddress, String text, Context context)
{
Intent intent = new Intent(context, SendSmsOnTheft.class);
PendingIntent pendingintent = PendingIntent.getActivity(context, 0, intent, 0);
SmsManager.getDefault().sendTextMessage(destinationAddress, null, text, pendingintent, null);
}
public void onReceive(Context context, Intent intent)
{
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()))
{
Log.d("VogueTools", "Got the Boot Event>>>");
TelephonyManager telephonymanager = (TelephonyManager)context.getSystemService("phone");
SharedPreferences sharedpreferences = context.getSharedPreferences("file", 0);
String number1 = sharedpreferences.getString("no1", "");
String number2 = sharedpreferences.getString("no2", "");
String number3 = sharedpreferences.getString("no3", "");
String number4 = sharedpreferences.getString("no4", "");
String extra = ("Mobile of IMEI NO: ")+
telephonymanager.getDeviceId()+
" is currently used" +
" by the SIM card service provider:" +
telephonymanager.getSimOperatorName().toString();
String simno = sharedpreferences.getString("simno", "");
String serialno = ((TelephonyManager)context.getSystemService("phone")).getSimSerialNumber();
if (number1.length() == 0)
{
System.exit(0);
}
if (simno.equals(serialno))
{
sendSMS(number1, extra, context);
sendSMS(number2, extra, context);
sendSMS(number3, extra, context);
sendSMS(number4, extra, context);
}
}
System.exit(0);
}
}
Here is the code that I used in my app for the same purpose:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.TelephonyManager;
import android.telephony.gsm.SmsManager;
import android.util.Log;
import android.widget.Toast;
public class ListeningToBoot extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String urphone = tm.getLine1Number();
Log.v("Uphone","is "+urphone);
Toast.makeText(context, "MDN:"+urphone, Toast.LENGTH_SHORT).show();
SharedPreferences prefs = context.getSharedPreferences("MySimPreferences", Context.MODE_PRIVATE);
String mobile_No=prefs.getString("MDN", "un-known");
Log.v("from shared pref","MDN"+mobile_No);
String imei=prefs.getString("IMEI", "un-known");
Log.v("from shared pref","IMEI"+imei);
if(urphone.equals(mobile_No))
{
Log.v("MDN is same","shoudl do nothing");
Toast.makeText(context, "MDN no change", Toast.LENGTH_LONG).show();
}
else
{
Log.v("MDN is not same","send a message to someone");
SharedPreferences prefs_names = context.getSharedPreferences("MyPreferences", Context.MODE_PRIVATE);
String number_to_send=prefs_names.getString("Moblie_Number", "un-known");
Toast.makeText(context, "MDN changed", Toast.LENGTH_LONG).show();
String message_to_send="Your mobile number chagned:\nNew Number: "+urphone+"\nIMEI: "+imei;
SmsManager.getDefault().sendTextMessage(number_to_send, null, message_to_send, null,null);
}
}
}
}
Hope this helps.
Edit: Make sure you have given all the required permissions in manifest file.
I think we need a little more information in order to help you. Anyway, have you registered the receiver properly? You must have been something like this under application:
<receiver
android:name=".SendSmsOnTheft"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
With permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SEND_SMS" />

Categories