Android Wear Preview Stacked Notifications - android

Having trouble sending stacked notifications using setGroup. The moment I invoke setGroup no notifications are being sent on the device or the Android Wear emulator. Some sample code...
Intent intent1 = new Intent(this, AddActivity.class);
PendingIntent pIntent1 = PendingIntent.getActivity(this, 0, intent1, 0);
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this);
nBuilder.setContentTitle("Fence Monitor").setContentText("FENCE " + status).setSmallIcon(R.drawable.ic_launcher).setContentIntent(pIntent1);
NotificationCompat.Builder nBuilder1 = new NotificationCompat.Builder(this);
Notification secondNotification = nBuilder1.setContentTitle("Fence Monitor").setContentText("This is additional information related to this notification").setSmallIcon(R.drawable.ic_launcher).build();
WearableNotifications.Action.Builder aBuilder = new WearableNotifications.Action.Builder(android.R.drawable.ic_input_add,"Add Content",pIntent1);
WearableNotifications.Action action = aBuilder.build();
RemoteInput.Builder rBuilder = new RemoteInput.Builder(QUICK_REPLY);
RemoteInput rInput = rBuilder.setAllowFreeFormInput(true).setLabel("QUICK REPLY").build();
WearableNotifications.Builder wBuilder = new WearableNotifications.Builder(nBuilder);
Notification notification = wBuilder.setGroup(FENCE_NOTIFICATIONS_GROUP,order).addAction(action).addPage(secondNotification).addRemoteInputForContentIntent(rInput).build();
//Notification notification = wBuilder.setGroup(FENCE_NOTIFICATIONS_GROUP,order).build();
NotificationManagerCompat nManager = NotificationManagerCompat.from(this);
int notificationId = (new Random()).nextInt();
Log.d("Notification Id",""+notificationId);
nManager.notify(notificationId, notification);

I was playing around with stacked notifications and realized that having a summary notification is needed for your notification to show up (at-least in my case it was). The android documentation: https://developer.android.com/wear/notifications/stacks.html#AddSummary mentions that is important but doesn't say it is required.
Either ways, try this and see if it works. I was able to get your code to work by adding a summary notification.
/**
* Create a summary notification
*/
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.alert_dialog_icon);
WearableNotifications.Builder wearableBuilder = new WearableNotifications
.Builder(builder)
.setGroup(FENCE_NOTIFICATIONS_GROUP,
WearableNotifications.GROUP_ORDER_SUMMARY);
Notification summaryNotification = wearableBuilder.build();
/**
* Notify. First publish the summary notification and then send out the
* other multi-page notification.
*/
NotificationManagerCompat nManager = NotificationManagerCompat.from(this);
int notificationId = (new Random()).nextInt();
Log.d("Notification Id",""+notificationId);
nManager.notify(notificationId, summaryNotification);
notificationId = (new Random()).nextInt();
Log.d("Notification Id",""+notificationId);
nManager.notify(notificationId, notification);

The WearableNotificationsSample included in the Android Wear Developer Preview shows how you can build stacked notifications:
public Notification[] buildNotifications(Context context, BuildOptions options) {
NotificationCompat.Builder childBuilder1 = new NotificationCompat.Builder(context)
.setContentTitle(context.getString(R.string.first_child_content_title))
.setContentText(context.getString(R.string.first_child_content_text));
Notification child1 = new WearableNotifications.Builder(childBuilder1)
.setGroup(EXAMPLE_GROUP_KEY, 0)
.build();
NotificationCompat.Builder childBuilder2 = new NotificationCompat.Builder(context)
.setContentTitle(context.getString(R.string.second_child_content_title))
.setContentText(context.getString(R.string.second_child_content_text))
.addAction(R.mipmap.ic_app_notification_studio,
context.getString(R.string.second_child_action),
NotificationUtil.getExamplePendingIntent(
context, R.string.second_child_action_clicked));
Notification child2 = new WearableNotifications.Builder(childBuilder2)
.setGroup(EXAMPLE_GROUP_KEY, 1)
.build();
Notification summary = buildBasicNotification(context, options)
.setGroup(EXAMPLE_GROUP_KEY, WearableNotifications.GROUP_ORDER_SUMMARY)
.build();
return new Notification[] { summary, child1, child2 };
}

Just recently I did a blog post which had a complete example that you might want to try out: http://android-developers.blogspot.com/2014/05/stacking-notifications-for-android-wear.html
Bitmap bitmapMila = BitmapFactory.decodeResource(getResources(), R.drawable.mila128);
// Nuke all previous notifications and generate unique ids
NotificationManagerCompat.from(this).cancelAll();
int notificationId = 0;
// String to represent the group all the notifications will be a part of
final String GROUP_KEY_MESSAGES = "group_key_messages";
// Group notification that will be visible on the phone
NotificationCompat.Builder builderG = new NotificationCompat.Builder(this)
.setContentTitle("2 Pet Notifications")
.setContentText("Mila and Dylan both sent messages")
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(bitmapMila);
Notification summaryNotification = new WearableNotifications.Builder(builderG)
.setGroup(GROUP_KEY_MESSAGES, WearableNotifications.GROUP_ORDER_SUMMARY)
.build();
// Separate notifications that will be visible on the watch
Intent viewIntent1 = new Intent(this, MainActivity.class);
PendingIntent viewPendingIntent1 =
PendingIntent.getActivity(this, notificationId+1, viewIntent1, 0);
NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this)
.addAction(R.drawable.ic_action_done, "Treat Fed", viewPendingIntent1)
.setContentTitle("Message from Mila")
.setContentText("What's for dinner? "
+ "Can we have steak?")
.setSmallIcon(R.drawable.ic_launcher);
Notification notification1 = new WearableNotifications.Builder(builder1)
.setGroup(GROUP_KEY_MESSAGES)
.build();
Intent viewIntent2 = new Intent(this, MainActivity.class);
PendingIntent viewPendingIntent2 =
PendingIntent.getActivity(this, notificationId+2, viewIntent2, 0);
NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this)
.addAction(R.drawable.ic_action_done, "Water Filled", viewPendingIntent2)
.setContentTitle("Message from Dylan")
.setContentText("Can you refill our water bowl?")
.setSmallIcon(R.drawable.ic_launcher);
Notification notification2 = new WearableNotifications.Builder(builder2)
.setGroup(GROUP_KEY_MESSAGES)
.build();
// Issue the group notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId+0, summaryNotification);
// Issue the separate wear notifications
notificationManager.notify(notificationId+2, notification2);
notificationManager.notify(notificationId+1, notification1);

Related

Notification Bubble not showing

for some reason whenever I send a notification the notification bubble does not show up. Ive allowed notification bubbles from the developer options and compileSdkVersion is 29. Bubble activity just has a button in it for testing purposes. Any help will be greatly appreciated.
My code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
NotificationManager notificationManager = mContext.getSystemService(NotificationManager.class);
// set up notification channel
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(CHANNEL_DESCRIPTION);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
// create person
Person person = new Person.Builder()
.setName("Notification")
.setIcon(Icon.createWithResource(mContext, R.drawable.ic_notification))
.setBot(true)
.setImportant(true)
.build();
// create bubble meta data
Intent target = new Intent(mContext, BubbleActivity.class);
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder()
.setDesiredHeight(300)
.setIcon(Icon.createWithResource(mContext, R.drawable.ic_notification))
.setSuppressNotification(true)
.setAutoExpandBubble(false)
.setIntent(bubbleIntent)
.build();
// create message style
Notification.MessagingStyle style = new Notification.MessagingStyle(person)
.setGroupConversation(false)
.addMessage("notification", currentTimeMillis(), person);
// create notification intent
Intent target2 = new Intent(mContext.getApplicationContext(), LaunchActivity.class);
PendingIntent notificationIntent = PendingIntent.getActivity(mContext.getApplicationContext(), 1, target2, PendingIntent.FLAG_UPDATE_CURRENT);
// create notification
Notification notification = new Notification.Builder(mContext, CHANNEL_ID)
.setContentTitle("Notification")
.setSmallIcon(Icon.createWithResource(mContext, R.drawable.ic_notification))
.setLargeIcon(Icon.createWithResource(mContext, R.drawable.ic_notification))
.setCategory(Notification.CATEGORY_MESSAGE)
.setStyle(style)
.setBubbleMetadata(bubbleMetadata)
.addPerson(person)
.setShowWhen(true)
.setContentIntent(notificationIntent)
.build();
if (notificationManager != null) {
notificationManager.notify(0, notification);
}
}
You need to set a shortcut ID on the notification. Once that is done, your notifications will appear in the conversation space and will be allowed to bubble. Note though that bubbles will not initially bubble automatically. It is up to the user to invoke/trigger this.
Please the following resources:
https://developer.android.com/guide/topics/ui/conversations#api-shortcuts
https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder#setShortcutId(java.lang.String)

How to group android notifications like whatsapp? as setGroup not work for me

I am currently test on Oreo and lollipop devices. What I am done so far:
final static String GROUP_KEY_NOTIFY = "group_key_notify";
int notificationId0 = 100;
int notificationId1 = 101;
int notificationId2 = 102;
int notificationId3 = 103;
NotificationCompat.Builder builderSummary =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("A Bundle Example")
.setContentText("You have 3 new messages")
.setGroup(GROUP_KEY_NOTIFY)
.setGroupSummary(true);
NotificationCompat.Builder builder1 =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("New Message")
.setContentText("You have a new message from Kassidy")
.setGroup(GROUP_KEY_NOTIFY);
NotificationCompat.Builder builder2 =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("New Message")
.setContentText("You have a new message from Caitlyn")
.setGroup(GROUP_KEY_NOTIFY);
NotificationCompat.Builder builder3 =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("New Message")
.setContentText("You have a new message from Jason")
.setGroup(GROUP_KEY_NOTIFY);
NotificationManager notifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notifyMgr.notify(notificationId1, builder1.build());
notifyMgr.notify(notificationId2, builder2.build());
notifyMgr.notify(notificationId3, builder3.build());
notifyMgr.notify(notificationId0, builderSummary.build());
What I am noticing, if there is 4 or more notifications occurs then they are bundled together but when there are less than 4 notification they are not bundled in android device above N. I read the documentations and doing what they are saying like using setGroup method and make separate notification object for summaryNotification. But nothing gets work for me.
You can use this link for reference for creating bundled notification.
Example:
String GROUP_KEY_WORK_EMAIL = "com.android.example.WORK_EMAIL";
Notification newMessageNotification = new
NotificationCompat.Builder(MainActivity.this, CHANNEL_ID)
.setSmallIcon(R.drawable.new_mail)
.setContentTitle(emailObject.getSenderName())
.setContentText(emailObject.getSubject())
.setLargeIcon(emailObject.getSenderAvatar())
.setGroup(GROUP_KEY_WORK_EMAIL)
.build();
Notification summaryNotification =
new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID)
.setContentTitle(emailObject.getSummary())
//set content text to support devices running API level < 24
.setContentText("Two new messages")
.setSmallIcon(R.drawable.ic_notify_summary_status)
//build summary info into InboxStyle template
.setStyle(new NotificationCompat.InboxStyle()
.addLine("Alex Faarborg Check this out")
.addLine("Jeff Chang Launch Party")
.setBigContentTitle("2 new messages")
.setSummaryText("janedoe#example.com"))
//specify which group this notification belongs to
.setGroup(GROUP_KEY_WORK_EMAIL)
//set this notification as the summary for the group
.setGroupSummary(true)
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(emailNotificationId1, newMessageNotification);
notificationManager.notify(SUMMARY_ID, summaryNotification);
You have to bundle the notifications into a group using Summary Notification Builder to ensure proper grouping. Below is my working code:
NotificationManager notificationManager;
NotificationCompat.Builder summaryNotificationBuilder;
int bundleNotificationId = 100;
int singleNotificationId = 100;
private void notificationGroup(Map<String, String> message) {
// Create Notification
String contentTitle = message.get("contentTitle");
String contentText = message.get("contentText");
Bitmap bm = BitmapFactory.decodeResource(getApplication().getResources(),
R.drawable.user3);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Notification Group Key
String groupKey = "bundle_notification_" + bundleNotificationId;
// Notification Group click intent
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("notification", "Summary Notification");
resultIntent.putExtra("notification_id", bundleNotificationId);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, bundleNotificationId, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// We need to update the bundle notification every time a new notification comes up
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
if (notificationManager.getNotificationChannels().size() < 2) {
NotificationChannel groupChannel = new NotificationChannel("bundle_channel_id", "bundle_channel_name", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(groupChannel);
NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
}
summaryNotificationBuilder = new NotificationCompat.Builder(this, "bundle_channel_id")
.setGroup(groupKey)
.setGroupSummary(true)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setSmallIcon(R.drawable.app_logo)
.setLargeIcon(bm)
.setAutoCancel(true)
.setContentIntent(resultPendingIntent);
if (singleNotificationId == bundleNotificationId)
singleNotificationId = bundleNotificationId + 1;
else
singleNotificationId++;
// Individual notification click intent
resultIntent = new Intent(this, NotificationActivity.class);
resultIntent.putExtra("notification", "Single Notification");
resultIntent.putExtra("notification_id", singleNotificationId);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
resultPendingIntent = PendingIntent.getActivity(this, singleNotificationId, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notification = new NotificationCompat.Builder(this, "channel_id")
.setGroup(groupKey)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setSmallIcon(R.drawable.app_logo)
.setLargeIcon(bm)
.setSound(defaultSoundUri)
.setAutoCancel(true)
.setGroupSummary(false)
.setContentIntent(resultPendingIntent);
notificationManager.notify(singleNotificationId, notification.build());
notificationManager.notify(bundleNotificationId, summaryNotificationBuilder.build());
}
Happy Coding!

Firebase Push Notification?

I am implementing firebase push notification in my app, the app is showing the push notification also. But my problem is - I may send different types of push notifications based on different topics.
Ex -
1. If I am sending a push notification on App Update, then on clicking that notification by the user, he should be redirected to PlayStore
If I am sending a push notification on New Contents, then on clicking that notification by the user, he should be redirected to App's MainActivity
If I am sending a push notification on New Contest, then on clicking that notification by the user, he should be redirected to App's ContestActivity
I implemented it using the below code in "MessageReceiver" class as --
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String title = remoteMessage.getNotification().getTitle();
String message = remoteMessage.getNotification().getBody();
showNotifications(title, message);
}
private void showNotifications(String title, String msg) {
Intent i = null;
if(title.equals("DoUp Now - Update")){
Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=com.s2s.doupnow"); // missing 'http://' will cause crashed
i = new Intent(Intent.ACTION_VIEW, uri);
}
else if(title.equals("DoUp Now - New Content")){
i = new Intent(this, MainActivity.class);
}
else if(title.equals("DoUp Now - New Notification")){
i = new Intent(this, NotificationActivity.class);
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, REQUEST_CODE,
i, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder, mBuilderOld;
final int NOTIFICATION_ID = 1;
final String NOTIFICATION_CHANNEL_ID = "my_notification_channel";
mNotifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
mBuilder.setContentTitle(title)
.setContentText(msg)
.setSmallIcon(R.drawable.doupnowlogo)
.setOnlyAlertOnce(true)
.setContentIntent(pendingIntent);
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
}
else
{
mBuilderOld = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
mBuilderOld.setContentTitle(title)
.setContentText(msg)
.setSmallIcon(R.drawable.doupnowlogo)
.setOnlyAlertOnce(true)
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationManager.IMPORTANCE_MAX);
mNotifyManager.notify(NOTIFICATION_ID, mBuilderOld.build());
}
}
But on clicking any notification by the user, he is always redirected to App's MainActivity only.
Can anyone guide me where i am missing.
If you are comparing title using api the you have to check the title using JSON object like this.
JSONObject data = json.getJSONObject("data");
String title = data.getString("title");
String message = data.getString("message");
Make sure the title you get is equal as title you are comparing and add flags in intent.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

Create custom notification android

How to create custom default notification? I am using Remote view to create the notification. but its not what was expect. Below is the image attched. I want to create the notification as that, with two button at bottom(like The Big Meeting is defined.
Any tutorial will be really helpful.
Below is code snippet what I have written.
Intent snoozeIntent = new Intent(LockableActivity.INTENT_SNOOZE);
PendingIntent pendingSnoozeIntent = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0);
Intent gotItIntent = new Intent(LockableActivity.INTENT_GOT_IT);
PendingIntent pendingGotItIntent = PendingIntent.getBroadcast(context, 0, gotItIntent, 0);
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.view_notification);
remoteView.setTextViewText(R.id.tv_title, entity.getClientName() + " appointment is late");
remoteView.setTextColor(R.id.tv_title, context.getResources().getColor(android.R.color.black));
remoteView.setOnClickPendingIntent(R.id.btn_snooze, pendingSnoozeIntent);
remoteView.setOnClickPendingIntent(R.id.btn_got_it, pendingGotItIntent);
NotificationManager mNotificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(entity.getClientName() + " appointment is late")
.setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_content)))
.setContent(remoteView);
But here I have my xml. Is there other way by which I could DD THE BUTTONs at bottom.
You need to set your remote view to the bigContentView field in the notification
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(entity.getClientName() + " appointment is late")
.setAutoCancel(true).build();
notification.bigContentView = remoteView;
mNotificationManager .notify(0,notification);

How to group pushnotifications in android?

I have implemeted push notification in android,and it comes perfectly as per needed,But only one problem is it displaying as individualy ,I want it in grouping,means if 5 notifications are there,it should display "5 messages" not a list of notification(which is currentl[y coming),My code is as belo,I have found solution that style can do this,and have tried but no change,
code
#SuppressWarnings("null")
public void sendNotification(String title, String description) {
Random random = new Random();
int id = random.nextInt(50);
NotificationCompat.Builder myNotification = null;
NotificationManager notificationManager = null;
notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent myIntent = new Intent(context, ActivityHome.class);
myIntent.putExtra("push", "push");
TaskStackBuilder taskbuiler = TaskStackBuilder.create(this);
taskbuiler.addParentStack(ActivityHome.class);
taskbuiler.addNextIntent(myIntent);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, myIntent, Intent.FLAG_ACTIVITY_NEW_TASK);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
myNotification = new NotificationCompat.Builder(context);
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
String[] events = new String[6];
// Sets a title for the Inbox in expanded layout
inboxStyle.setBigContentTitle("Event tracker details:");
// Moves events into the expanded layout
for (int i = 0; i < events.length; i++) {
inboxStyle.addLine(events[i]);
}
// Moves the expanded layout object into the notification object.
myNotification.setStyle(inboxStyle);
myNotification.setStyle(new NotificationCompat.InboxStyle());
myNotification.setContentTitle(title);
myNotification.setContentText(description);
myNotification.setContentIntent(pendingIntent);
myNotification.setDefaults(Notification.DEFAULT_SOUND);
myNotification.setAutoCancel(true);
myNotification.setSmallIcon(R.drawable.app_icon);
myNotification.build();
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, myNotification.build());
}
Check this out:
https://developer.android.com/training/wearables/notifications/stacks.html
Maybe this helps.

Categories

Resources