RemoteViews to LocalBroadcastManager - java

LocalBroadcastManager does not receive broadcast intent from RemoteViews PendingIntent.
So if it is true then is there any idea or way out to do communicate in between RemoteViews and LocalBroadcastManager?
I am using RemoteViews for Notification custom view, which run within a foreground service.
And when click on button within RemoteViews, it will call a method within service.
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
contentView = new RemoteViews(getPackageName(), R.layout.custom);
Intent intent1 = new Intent("myintent");
PendingIntent pi = PendingIntent.getBroadcast(this, 1, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
contentView.setOnClickPendingIntent(R.id.button,pi);
But LocalBroadcastManager does not receive this.

Yes i kinda sort out this.
Using another BroadcastReceiver as middle man to receive broadcast for PendingIntent and sendbroadcast through LocalBroadcastManager which can receive by service's LBM

Related

How to reference a view in a customized notification

In the below posted code i am create a notification with a customized layout. the layout of the notification contains three action buttons.
the problem i have now is, i can not reference any of the buttons in the code so that I can navigate to another activity based on the action button clicked.what i am trying to do is when Action button 1
is clicked then Activity 1 shows up, when Action button 2 is clicked then Activity 2 shows up and so on.
Please let me know how to reference the views in customized layout of the notification?
code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Using RemoteViews to bind custom layouts into Notification
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);
String notification_title = "Notification_Title";
String notification_text = "Notification_Text";
// Open NotificationView Class on Notification Click
Intent intent = new Intent(this, NotificationReply.class);
// Send data to NotificationView Class
intent.putExtra("title", notification_title);
intent.putExtra("text", notification_text);
// Open NotificationView.java Activity
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
// Set Icon
.setSmallIcon(R.mipmap.ic_launcher)
// Set Ticker Message
.setTicker("Ticker")
// Dismiss Notification
.setAutoCancel(true)
// Set PendingIntent into Notification
.setContentIntent(pIntent)
// Set RemoteViews into Notification
.setContent(remoteViews);
Intent intentAction1 = new Intent(this, ActAction1.class);
PendingIntent pendingIntentActAction1 = PendingIntent.getBroadcast(this, 1,intentAction1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.btn_action1, pendingIntentActAction1);
Intent intentAction2 = new Intent(this, ActAction2.class);
PendingIntent pendingIntentActAction2 = PendingIntent.getBroadcast(this, 2,intentAction2, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.btn_action2, pendingIntentActAction2);
Intent intentAction3 = new Intent(this, ActAction3.class);
PendingIntent pendingIntentActAction3 = PendingIntent.getBroadcast(this, 3,intentAction3, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setPendingIntentTemplate(R.id.btn_action3, pendingIntentActAction3);
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Build Notification with Notification Manager
notificationmanager.notify(0, builder.build());
}
}
The key success for navigation is to use proper pending intent and use different values for your requestCode.
You could receive the event in broadcastReceiver building the pending intent (e,g, with params) that way:
private PendingIntent buildPendingIntent(String someurl) {
Intent intent= new Intent(mContext, SomeReceiver.class);
final Uri uri = Uri.parse(someurl);
intent.setData(uri);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(KEY, VALUE)
return PendingIntent.getBroadcast(mContext.getApplicationContext(),
CONSTANT_FOR_THIS_INTENT_TYPE, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
Or you could navigate to activity just by pending intent:
private PendingIntent buildPendingIntent2() {
Intent intent = new Intent(mContext, SomeActivity.class);
intent.putExtra(KEY, VALUE);
settingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
return PendingIntent.getActivity(mContext.getApplicationContext(),
OTHER_CONSTANT_FOR_OTHER_ACTION,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Please notice that CONSTANT_FOR_THIS_INTENT_TYPE and OTHER_CONSTANT_FOR_OTHER_ACTION must have different values
And after you have this pending intents you should attach them to your views:
view.setOnClickPendingIntent(com.app.btn1, buildPendingIntent1());
view.setOnClickPendingIntent(com.app.btn2, buildPendingIntent2());
You have to use RemoteViews#setOnClickPendingIntent() API:
Equivalent to calling setOnClickListener(android.view.View.OnClickListener) to launch the provided PendingIntent.
Intent firstIntent = new Intent(context, FirstActivity.class);
PendingIntent firstPendingIntent = PendingIntent.getBroadcast(this, 0, firstIntent, 0);
RemoteViews notificationView = ...
notificationView.setOnClickPendingIntent(R.id.first_button, firstPendingIntent);
You have to use RemoteViews#setOnClickPendingIntent() API:
I get your mistake you are trying to launch an activity with PendingIntent.getBroadcast() which only send a broadcast message, so ideally a broadcast receiver should be registered with the same intent filter action. In your case it should ideally be PendingIntent.getActivity
Now you can launch with the following pending intent the flag value was incorrect I can assume for everyone else, hence pending intent wasn't fired.
Intent firstIntent = new Intent(context, FirstActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(appContext, 101, firstIntent,
PendingIntent.FLAG_UPDATE_CURRENT); // For opening activity ideally this should work
If this doesn't work you can try sending a broadcast and listen for it to verify that broadcast is also sent or not:-
PendingIntent pendingIntent = PendingIntent.getBroadcast(appContext, 0, firstIntent, PendingIntent.FLAG_ONE_SHOT); // for sending broadcast and listens in broadcast reciever

How to make a button in a notification 'do something'

I am trying to make a simple stopwatch app that will display the time in a notification and give you a couple buttons that will allow you to start and stop the stopwatch.
How do I add a button to a notification? And how do I 'point' that button to a certain function?
Heres a picture of what I was thinking:
actionIntent = new Intent(this, MainActivity.class);
actionPendingIntent = PendingIntent.getService(this, 0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
timerNotification.addAction(android.R.drawable.ic_media_pause, "Start", actionPendingIntent);
This is what I currently have. Where in the intent would I put the function I want to execute?
Add Action to the notification and assign a pendingintent
If you want to custom your notification layout,you can use setContent() function with a RemoteViews of your custom layout.
Remote View mRemoteView = new RemoteViews(getPackageName(), R.layout.notification_general);
Notification.Builder mBuilder = new Notification.Builder(context);
mBuilder.setSmallIcon(R.mipmap.ic_battery)
.setContent(mRemoteView)
.setContentIntent(notificationPendingIntent);
mNotificationManager.notify(1, mBuilder.build());
To handle an notification button onClick event, you need to use separate PendingIntents(made from Intents with differecnt actions) for every button. Later in onReceive() you just check action of incoming Intent & execute different code depending on that. Remember to assign your Listener on manifest.
Intent generalIntent = new Intent(context, GeneralReceiver.class);
generalIntent.putExtra(REQUEST_CODE, ACTION_GENERAL);
PendingIntent generalPendingIntent =
PendingIntent.getBroadcast(context, 1, generalIntent, 0);
mRemoteView.setOnClickPendingIntent(R.id.btnNotificationGeneral, generalPendingIntent);
public static class GeneralReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Your code here
}
}

Instead of pendingIntent, execute function in Notification.addAction() . Is it possible?

I want a method to be executed when I press a button on my notification. For that purpose I am adding an action with a PendingIntent to my notification:
Intent intent = new Intent(context, AlertActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Notification notification = new Notification.Builder(MainActivity.this)
.setContentTitle("New Notification")
.setContentText("Click Here")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.addAction(R.mipmap.ic_launcher, "Test2", pendingIntent)
.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, notification);
That works, however I don't want to start an Activity when the user invokes the action. I just need to do some work.
For that purpose I implemented a Service which should be targeted by the PendingIntent instead:
public class MyServices extends IntentService {
public MyServices() {
super("MyServices");
}
#Override
protected void onHandleIntent(Intent intent) {
clearNotification();
}
public void clearNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(0);
Intent intent = new Intent(MyServices.this, MainActivity.class);
//Starting new activity just to check
startActivity(intent);
}
}
I create the PendingIntent like this:
final Intent intent = new Intent(context, MyServices.class);
final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
However when I invoke the action on my notification nothing happens. What am I doing wrong?
A Notification is not part of your application. It is managed by the OS. It just so happens that there are APIs you can use to show/cancel/etc notifications.
A pending intent allows for external code (Notifications for example) to launch your app/activity/service/broadcastreceiver. This cannot be done without a pending intent.
What my task is to execute some piece of code when a specific action button is clicked, and clear notification; without starting any activity
You don't have to start an activity. You can do it in a broadcastreceiver that has no UI. Or, as CommonsWare suggested, use an IntentService, depending on what what you are doing in your "piece of code". IntentServices handle work in a separate thread.

Android notification with RemoteViews - having activity associated with RemoteViews layout

I've been researching on how to create custom-layout notification using RemoteView.
So far, I am able to create a notification with contentView and bigContentView pointing to a RemoteView with a custom layout xml. However, what does not happen, is to have Activity (associated with custom layout) started when this RemoteView is created.
I've double checked and in my layout xml, it appears to have correct Activity class name:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
tools:context=".LLMNotificationActivity" >
..... the rest are standard layout items: images, buttons and text
</RelativeLayout>
In manifest file, right after main application main activity, notification activity is also added:
<activity
android:name=".LLMNotificationActivity"
android:label="#string/app_name">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I would expect when notification uses RemoteView for its content, that this RemoteView will launch activity that is attached to its layout definition. However it appears not.
Here is how I create a notification in main application Activity:
protected void startNoti() {
if( noti!=null ) return;
Context context = getApplicationContext();
RemoteViews contentView = new RemoteViews(context.getPackageName(),R.layout.activity_noti1);
Notification.Builder notibuilder = new Notification.Builder(context);
notibuilder.setContentTitle(" ");
notibuilder.setContentText(" ");
notibuilder.setSmallIcon(R.drawable.ic_launcher);
notibuilder.setOngoing(true);
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
noti = notibuilder.build();
noti.contentView = contentView;
manager.notify(NOTIFICATION_ID, noti);
}
LLMNotificationActivity activity class is defined as usual:
public class LLMNotificationActivity extends Activity {
.... etc.... constructor, some button on-click handlers, nothing spectacular...
}
Can anyone point to me what I am missing or if I have misunderstood what RemoteView can do? My understanding is that RemoteView should, once created, invoke activity associated with its layout. Or - is there some API I've missed that explicitly can set intent of the RemoteView?
What I have found so far are only setting content Intent which basically just launches an Activity once user touches notification. What I'm looking for is to handle touches to some of UI elements inside custom-layout notification, not to launch an Activity regardless where the user clicks on notification surface.
For example, if I have 3 icons (i.e. ImageView) in a RemoteView which notification uses, I'd like to be able to handle touch on each one of them. I can't imagine this wouldn't be possible as if it's not, what's the point of having RemoteView in notification?
You have to associate the activity thought setOnClickPendingIntent to launch the activity from remote view as below...You can set any of the layout id in the RemoteView to click.
Intent intent = new Intent(context, YourActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews removeWidget = new RemoteViews(context.getPackageName(), R.layout.your_layout);
removeWidget.setOnClickPendingIntent(R.id.layout_id, pendingIntent);
provide an +id/layout_id to the RelativeLayout your using.
If you have to launch the activity when user click on the notification, then you have to use PendingIntent as....
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("title")
.setContent(mRemoteControl);
Intent notificationIntent = new Intent(this, YourActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(contentIntent);
mNM.notify(1000,mBuilder.build());
For 3 buttons , You have to use create a custom RemoteView and use PendingIntent. some thing as below...
Here is the custom remote view i am using for one of my media player app. it has three button to handler click.
public class RemoveControlWidget extends RemoteViews
{
private final Context mContext;
public static final String ACTION_PLAY = "com.mediabook.app.ACTION_PLAY";
public static final String ACTION_PREVIOUS = "com.mediabook.app.ACTION_PREVIOUS";
public static final String ACTION_NEXT = "com.mediabook.app.ACTION_NEXT";
public RemoveControlWidget(Context context , String packageName, int layoutId)
{
super(packageName, layoutId);
mContext = context;
Intent intent = new Intent(ACTION_PLAY);
PendingIntent pendingIntent = PendingIntent.getService(mContext.getApplicationContext(),100,
intent,PendingIntent.FLAG_UPDATE_CURRENT);
setOnClickPendingIntent(R.id.play_control,pendingIntent);
setOnClickPendingIntent(R.id.pause_control,pendingIntent);
intent = new Intent(ACTION_PREVIOUS);
pendingIntent = PendingIntent.getService(mContext.getApplicationContext(),101,
intent,PendingIntent.FLAG_UPDATE_CURRENT);
setOnClickPendingIntent(R.id.previous_control,pendingIntent);
intent = new Intent(ACTION_NEXT);
pendingIntent = PendingIntent.getService(mContext.getApplicationContext(),102,
intent,PendingIntent.FLAG_UPDATE_CURRENT);
setOnClickPendingIntent(R.id.next_control,pendingIntent);
}
}
All you need to do is addsetContentIntent to your Notification.Builder like this:
Intent i = new Intent(context, YourLaunchedActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, 0);
Notification.Builder notibuilder = new Notification.Builder(context);
notibuilder.setContentIntent(pendingIntent);
Now, when you click on your notification, YourLanchedActivity will be launched.
*you can implement the pending intent on click of remote view by doing the following
also note that
if you are trying to get a activity from the remote view then getAcitvity is used in pending intent
like
*
//i will create a simple method//
//use return getActivity cause getting the bottom Activity
private static PendingIntent getActivityBottom(Context context) {
clearNotification(context);
Intent intentStartActivity = new Intent(context, BotomNavViewActivity.class);
intentStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intentStartActivity.addFlags(/*Intent.FLAG_ACTIVITY_CLEAR_TASK |*/ Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
return PendingIntent.getActivity(
context,
2,
intentStartActivity,
PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void clearNotification(Context context) {
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
Now if you want to get your service class the use getService in pending intent
private static PendingIntent stopPlayer(Context context){
Intent serviceIntent = new Intent(context, MusicService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.stopService(serviceIntent);
mContentView.setImageViewResource(R.id.notif_play, R.drawable.ic_play);
return PendingIntent.getService(
context,
2,
serviceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
use the above method like this
//perfoam action on notification to go to activity
mContentView.setOnClickPendingIntent(R.id.notif_small,getActivityBottom(context));
//for service
mContentView.setOnClickPendingIntent(R.id.notif_play,stopPlayer(context));

Get appwidget position on home screen?

I start an activity when a widget icon is clicked.What i want is to send the position of that widget to that activity.I have tried
Intent intent=new Intent(context, WidgetActivity.class);
Bundle bundle = new Bundle();
bundle.putString("rect", bound);
intent.putExtras(bundle);
//intent.putExtra("rect", bound.toString());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.pic1);
views.setOnClickPendingIntent(R.id.wbutton1, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
in my onUpdate procedure.But this crashes the activity.
I have heard that the position is returned using intent.getsourceBounds() .Thats in onReceive ryt?i have tried making bound a global variable.setting its value from onReceive as bound=intent.getsourceBounds(); That didn't work either.
So my question is
1.How do i get the widget position using intent.getsourceBounds() in onUpdate?
2.How can i send it to the activity?
Thank you for your time.
edit:i managed to send string from widget to activity like this:
Intent intent=new Intent(context, WidgetActivity.class);
Bundle bundle = new Bundle();
bundle.putString("pos", "hello");
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
edit 2: I found https://stackoverflow.com/a/5324918/1685829 which says it can be done using getSourceBounds().Can anyone explain how i can use it in onUpdate.
You don't need to send it; Android does it for you. getSourceBounds() can only be used from inside the activity. This information is not available inside onUpdate().

Categories