Android IntentReceiver never receives custom intent from WidgetProvider - java

(This is my first SE question ever, but I've relied heavily on this site for it's fantastic community as I've bumbled around learning Java and Android!)
I'm creating an Android widget that (for the time being) has only one button that functions as a two-sided dice. Eventually this widget will support all major RPG dice sizes (d6, d8, d20, etc), but for now I'm just trying to get the intent/receiver system working.
Currently nothing happens when I hit the d2 button in my widget. So far as I can tell by debugging my custom intent is fired, but the onReceive in my IntentReceiver never catches it. Any assistance you can provide would be much appreciated!
Here is my WidgetProvider:
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
remoteViews.setOnClickPendingIntent(R.id.btnReset, buildButtonPendingIntent(context));
Log.e(null, "Setup remote views & Onclick");
Toast.makeText(context, "Test", Toast.LENGTH_SHORT).show();
pushWidgetUpdate(context, remoteViews);
}
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("ca.sulli.rpgdicewidget.intent.action.D2");
Log.e(null, "Setting new ButtonPendingIntent");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
Log.e(null, "Updating widget!");
ComponentName myWidget = new ComponentName(context, MyWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, remoteViews);
}
}
And here is my receiver:
public class MyWidgetIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e(null,"Checking intent by receiver");
if(intent.getAction().equals("ca.sulli.rpgdicewidget.intent.action.D2")){
Log.e(null,"Correct intent received!");
updateWidgetPictureAndButtonListener(context);
}
}
private void updateWidgetPictureAndButtonListener(Context context) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
Log.e(null,"Updating text since the intent was received!");
remoteViews.setTextViewText(R.id.txtResult, "Intent Received! ");
remoteViews.setOnClickPendingIntent(R.id.btnD2, MyWidgetProvider.buildButtonPendingIntent(context));
MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
}
}
And for completions' sake, my manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ca.sulli.rpgdicewidget"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="ca.sulli.rpgdicewidget.intent.action.D2" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
</application>
</manifest>
And the appwidget-provider:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="200dp" android:minHeight="70dp" android:initialLayout="#layout/main" android:updatePeriodMillis="30000">
</appwidget-provider>
Many thanks for any help provided, and many thanks for the help this community has already provided for me by answering so many other questions!

I cannot see anywhere in your code where you are using the PendingIntent that you have created, you can use the alarmmanager to schedule a message, presumably immediately, using code like this:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent);
Broadcast messages are quite complex though, so you may want to weigh up if you want to use them, you could consider using a regular intent and context.sendBroadcast instead

Related

Android broadcast not received from widget

I Have a widget that upon button press I send broadcast to service. But I am not receving any broadcast in my onReceive().
My intention is basically on widget button click, it tellls service to perform some action.
But I am unable to receive any broadcast from widget in service.
Here is my widget code -
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews;
ComponentName componentName;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
componentName = new ComponentName(context, MyWidgetProvider.class);
remoteViews.setOnClickPendingIntent(R.id.play,getPendingSelfIntent(context, "PLAY",componentName));
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews;
ComponentName componentName;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
componentName = new ComponentName(context, MyService.class);
if (intent.getAction().equals("PLAY")) {
Log.d("hi","PLAY0");
remoteViews.setOnClickPendingIntent(R.id.engine_lock_unlock,getPendingSelfIntent(context,"PLAY",componentName));
serviceIntent = new Intent(context,MyService.class);
serviceIntent.setAction("PLEASE_PLAY");
Log.d("hi","PLAY1");
context.sendBroadcast(serviceIntent);
}
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
protected PendingIntent getPendingSelfIntent(Context context, String action, ComponentName componentName) {
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(action);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, componentName);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
In MyService,
public class ServiceWidgetReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("hi","PLAY2");
if (intent.getAction().equals("PLEASE_PLAY")) {
}
}
}
My MAnifest looks like this -
<receiver android:name=".widget.MyWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/homescreen_widget_preview" />
</receiver>
<receiver android:name=".service.MyService$ServiceWidgetReceiver" />
I only get the logs -
PLAY0
PLAY1
Why I dont get my broadcast???
Seams that your receiver has no intent-filter provided. Try to add this in your mainfest file:
<receiver android:name=".service.MyService$ServiceWidgetReceiver">
<intent-filter>
<action android:name="PLEASE_PLAY" />
</intent-filter>
</receiver>
I assume that you have implement the action in intent-filter like Myon said, but the still no broadcast to the onReceive. you may try this:
protected PendingIntent getPendingSelfIntent(Context context, String action, ComponentName componentName) {
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(action);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, componentName);
//this line replace the original
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Actually, i have facing the similar problem yesterday that my widget work fine on my android 5.1 phone. However, I find it cannot perform click on android 7.0 sony phone. I still trying to find out whether is the sony phone os problem or android 7.0 or after problem because after the upgrade of the 7.0 or after, there is so many different issues appeared as they changed quite a lot in the API. Anyway, I used the PendingIntent.FLAG_UPDATE_CURRENT solved the problem I have on 7.0
I just think will directly register the receiver class to manifest like this be work. The service binded doesnt directly affect the receive, as the only thing affect the receiver is context. So, maybe just the receive class is enough.
<receiver android:name="packageName.ServiceWidgetReceiver">
<intent-filter>
<action android:name="PLEASE_PLAY" />
</intent-filter>
</receiver>
I found out the mistake I was doing. I had to registerreceiver and unregister it in Service itself rather in Manifest.
This worked for me.

Android not recreating service even when using START_STICKY

I am trying to create a service and set an alarm through it. I need to run the service in background to keep the broadcaster reciever running even if the app is closed. I tried using START_STICKY, running service in a separate child process as well as a global process, all in vain. What should I do ?
Alarm.java
package com.simpleapps.simpleweather;
import ...
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP,150);
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show();
}
public void setAlarm(Context context)
{
Log.d("Alarm","Started");
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60, pi); // Millisec * Second * Minute
}
public void cancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
HelloService.java
package com.simpleapps.simpleweather;
import ...
public class HelloService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("Alarm","New Service");
alarm.setAlarm(this);
return START_STICKY;
}
#Override
public void onStart(Intent intent, int startId)
{
alarm.setAlarm(this);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simpleapps.simpleweather">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".today_details" />
<activity android:name=".forecast_details"/>
<receiver android:process=":remote" android:name=".Alarm" android:exported="true">
</receiver>
<service
android:name=".HelloService"
android:enabled="true">
</service>
</application>
</manifest>
Starting Service -
Intent intent = new Intent(this, HelloService.class);
startService(intent);
Update : It is working on every device except my Lollipop 5.0 device AsusZenfone2
I've tried your code and it's working ok on the emulator. One thing I've notice is that:
* setRepeating
* <b>Note:</b> Beginning in API 19, the trigger time passed to this method
* is treated as inexact: the alarm will not be delivered before this time, but
* may be deferred and delivered some time later. The OS will use
* this policy in order to "batch" alarms together across the entire system,
* minimizing the number of times the device needs to "wake up" and minimizing
* battery use. In general, alarms scheduled in the near future will not
* be deferred as long as alarms scheduled far in the future.
So I've change the Alarm to look like so (It's just illustration, you could do it without static fields):
public class Alarm extends BroadcastReceiver
{
private static boolean sAlarmCanceled = false;
#Override
public void onReceive(Context context, Intent intent)
{
if (sAlarmCanceled)
return;
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP,150);
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_SHORT).show();
scheduleNextAlarm(context);
}
public static void enableAlarm(Context context) {
sAlarmCanceled = false;
scheduleNextAlarm(context);
}
public static void disableAlarm() {
sAlarmCanceled = true;
}
private static void scheduleNextAlarm(Context context)
{
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_ONE_SHOT);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pi);
}
}
And now it get executed precisely every 10 sec. Service runs normal and I was able to remove Application task and see the alarm anyway.

Show notification at a specific time using AlarmManager and BroadcastReceiver in android is not working

I create an android application to view notification at a particular time when the application is not running background . I use AlarmMabager & BroadcastReceiver for above purpose .
This application can pass a notification at a specific time whether user is not starting the application .
Here are the steps which I use to do ,
MainActivity.java
public class MainActivity extends Activity
{
private PendingIntent pendingIntent;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, 7);
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.DAY_OF_MONTH, 7);
calendar.set(Calendar.HOUR_OF_DAY, 13);
calendar.set(Calendar.MINUTE, 40);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.AM_PM,Calendar.PM);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
} //end onCreate
}
MyReceiver.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent service1 = new Intent(context, MyAlarmService.class);
context.startService(service1);
}
}
MyAlarmService.java
public class MyAlarmService extends Service
{
private NotificationManager mManager;
#Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate()
{
// TODO Auto-generated method stub
super.onCreate();
}
#SuppressWarnings("static-access")
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
mManager = (NotificationManager) this.getApplicationContext().getSystemService(this.getApplicationContext().NOTIFICATION_SERVICE);
Intent intent1 = new Intent(this.getApplicationContext(),MainActivity.class);
Notification notification = new Notification(R.mipmap.ic_launcher,"This is a test message!", System.currentTimeMillis());
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(this.getApplicationContext(), "AlarmManagerDemo", "This is a test message!", pendingNotificationIntent);
mManager.notify(0, notification);
}
#Override
public void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyAlarmService"
android:enabled="true" />
<receiver android:name=".MyReceiver"/>
</application>
</manifest>
After completing all the steps I run the application in my device but it doesn't show any notification . Is there anything wrong ? What should I do to correct this .
Thank you .

AlarmManager broadcast not being received

I have been trying to slowly learn the Android API over the past month. I have read documentation, viewed examples and can't seem to figure out what I'm doing incorrectly. Basically the app sets an alarm 1 minute exactly after the app was started.
The issue I am currently having is after setting an alarm, it isn't being received. Here's what I have:
SetAlarmActivity.java
public class SetAlarmActivity extends AppCompatActivity {
private final String TAG = "AlarmTest";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_set_alarm);
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 1);
Log.d(TAG, "Alarm time is " + c.getTime());
// set the intent to launch our SetAlarmActivity
Intent alarmIntent = new Intent(SetAlarmActivity.this, SetAlarmActivity.class);
// retrieve a PendingIntent to perform a Broadcast
PendingIntent pendingAlarmIntent = PendingIntent.getBroadcast(SetAlarmActivity.this, 0, alarmIntent, 0);
// grab the Alarm Service and tell it to call our Intent at the set time
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingAlarmIntent);
}else{
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingAlarmIntent);
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends WakefulBroadcastReceiver {
private final String TAG = "AlarmTest";
#Override
public void onReceive(Context context, Intent intent){
Log.d(TAG, "Received broadcast!");
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="bz.bdu.alarmtest" >
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<activity android:name=".SetAlarmActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver" />
</application>
</manifest>
You have to create the intent between the Current activity and receiver class. change your code like this.
Intent intent = new Intent(SetAlarmActivity.this, AlarmReceiver.class);
change
Intent alarmIntent = new Intent(SetAlarmActivity.this,
SetAlarmActivity.class);
to
Intent alarmIntent = new Intent(SetAlarmActivity.this,
AlarmReceiver.class);
then its works fine

Get from Android BroadcastReceiver to a UI

I have a receiver that works well, but I can't seem to show a proper UI, although the toast appears correctly. As far as I can tell, this is caused by Android requiring the class to extend Activity, however, the class already extends BroadcastReceiver, so I can't do this.
So, I tried to do an Intent, but this failed too. There are no errors, but the screen doesn't show. Source code is below.
Broadcast (Method in AndyRoidAlarm)
public void setAlarm(){
Intent intent = new Intent(AndyRoidAlarm.this, Reciever.class);
PendingIntent sender = PendingIntent.getBroadcast(AndyRoidAlarm.this,
0, intent, 0);
// We want the alarm to go off 30 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
// Tell the user about what we did.
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(AndyRoidAlarm.this, "Alarm Scheduled for 30secs", Toast.LENGTH_LONG);
mToast.show();
}
Reciever
public class Reciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent i = new Intent();
i.setClass(context, AlarmRing.class);
}
}
Reciever V2
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent foo = new Intent(context, AlarmRing.class);
//foo.putExtra("id", "id");//example, if you wish to pass custom variables
context.startActivity(foo);
}
AlarmRing
public class AlarmRing extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
MediaPlayer mp = MediaPlayer.create(getBaseContext(), R.raw.sweetchild);
mp.start();
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.comaad.andyroidalarm"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".AndyRoidAlarm"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.comaad.andyroidalarm.Reciever" android:enabled="true">
<intent-filter>
<action android:name="com.comaad.andyroidalarm.Reciever"></action>
</intent-filter>
</receiver>
<activity android:name=".AlarmRing"></activity>
</application>
</manifest>
}
In a BroadcastReceiver onReceive() method, if you need a Context (e.g., to create an Intent), use the Context that is passed to you as a parameter of onReceive(). You even have this code in your onReceive() -- you're just not doing anything with the resulting Intent (e.g., calling startActivity()).
Intent foo = new Intent(this, AlarmRing.class);
foo.putExtra("id", id);//example, if you wish to pass custom variables
this.startActivity(foo);
Edit
Check out this example to use BroadcastReciever within an Activity. http://almondmendoza.com/2009/01/04/getting-battery-information-on-android/

Categories

Resources