Chang Phone to Silent Mode on BroadCast Recieving in Xamarin Android - c#

MainActivity.cs
private void StartAlarm()
{
Intent myIntent;
PendingIntent pendingIntent; myIntent = new Intent(this, typeof(AlarmToastReceiver));
pendingIntent = PendingIntent.GetBroadcast(this, 0, myIntent, 0);
alarm_manager.Set(AlarmType.RtcWakeup, calndr.TimeInMillis, pendingIntent);
}
AlarmToastReceiver.cs
[BroadcastReceiver(Enabled =true)]
public class AlarmToastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "BroadCast Received.", ToastLength.Long).Show();
}
}
I want to Change my Phone mode to Silent at Specific Time automatically on Broadcast receiving, So here i pick the Time from Time-picker, and then set the Ala ram Manager Instance. When the Pending Intent completed , then Broadcast Receiver is active, and a Message is Shown to me,i.e "Broadcast Received.", but here i want to change my Mobile Mode to silent Mode,So how can i do it,can any one help me ? thanks in advance.

You can use the AudioManager to set Silent/Vibrate/Normal.
var audioMgr = (AudioManager)GetSystemService(AudioService);
audioMgr.RingerMode = RingerMode.Silent; // In Oreo(+) this will enable DnD mode
From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed unless the app has been granted Do Not Disturb Access.
Re: AudioManager

Related

Xamarin - BroadcastReceiver Unable to receive after Distribution APK

Hi I am new to xamarin and I hit a weird issue.
I currently developing an app for Zebra MC93, and I use broadcast receiver to received the barcode information. I hardcorded the intent to be "com.symbol.ccn.RECVR". when I zebra developer mode to install the app via visual studio to zebra with usb debugging, the app can run smoothly with all the broadcast receiver working. But when I archive and distribute the file, and install the app with the apk, the broadcast receiver doesnt work at all. I didnt declare the intent filter in AndroidManifest, i only declared it in a class below. Anyone had any idea?
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { "com.symbol.ccn.RECVR" })]
public class Receiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action.Equals(GeneralString.IntentPASSTOAPP))
{
string x = intent.GetStringExtra(GeneralString.BcReaderData);
// Toast.MakeText(context, "Received !" + x, ToastLength.Short).Show();
MessagingCenter.Send<ProductIdentificationScanPage, string>(new ProductIdentificationScanPage(), "BarcodeInfo", x);
}
else if (intent.Action.Equals("com.symbol.ccn.RECVR"))
{
string x = intent.GetStringExtra("com.symbol.datawedge.data_string");
MessagingCenter.Send<ProductIdentificationScanPage, string>(new ProductIdentificationScanPage(), "BarcodeInfo", x);
}
}
}
Anyone had any idea or meet this type of issues before?

Android Foreground Location Service stops after some time

Im using this code to get location updates for my Xamarin Android app. I have 2 questions.
How to make this foreground service to run forever? I've tried to change return StartCommandResult.NotSticky; to return StartCommandResult.Sticky; and remove anything from OnDestroy() method, but OS seems to be unable to recreate service after it was killed or crashed. So, it runs about a half day only, even i've added app to my battery optimization exclude list. How to make it run forever?
How to properly start service from boot?
Here is what i've tried. Added following to MainActivity.cs
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
public Context Context { get; set; }
public override void OnReceive(Context context, Intent intent)
{
var stepServiceIntent = new Intent(context, typeof(LocationUpdatesService));
stepServiceIntent.PutExtra("StartedFromBoot", true);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
context.StartForegroundService(stepServiceIntent);
}
else
{
context.StartService(stepServiceIntent);
}
}
}
Edited LocationUpdatesService.cs
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Log.Info(Tag, "Service started");
var startedFromNotification = intent.GetBooleanExtra(ExtraStartedFromNotification, false);
var startedFromBoot = intent.GetBooleanExtra("StartedFromBoot", false);
if (startedFromBoot)
{
//Preferences.Set("LocationUpdates", true);
StartForeground(NotificationId, StartNotification("",""));
Preferences.Set("foreground", true);
try
{
FusedLocationClient.RequestLocationUpdates(LocationRequest, LocationCallback, Looper.MyLooper());
}
catch (SecurityException unlikely)
{
Preferences.Set("LocationUpdates", false);
Log.Error(Tag, "Lost location permission. Could not request updates. " + unlikely);
}
}
if (startedFromNotification)
{
RemoveLocationUpdates();
StopSelf();
}
return StartCommandResult.Sticky;
}
I got only single location update that way right from boot. After that single update Im geting "Unknown Location" so service doesnt run continuously. So, how to properly start that service from boot to make it run continuously?
Maybe there will be a single solution for both questions, so if there is a way to start fully functional service from boot, then system could recreate it with Sticky flag and run forever.
Actually, the foreground service will keep running when the phone is on. But you can also use the PowerManager.WakeLock to make sure your app always keep alive even the device is sleep.
You can check this case:Xamarin wakelock
In addition, it seems that you want to get the user's location cyclically. So you can run a timed task in the foreground service. There are many ways to do that. Such as:
JobScheduler
AlarmManager
WorkManager
ScheduledThreadPoolExecutor
You can check this case:Xamarin Android - Periodic task execution

Creating a notification at a specific time

I have a calendar app that I'm working on, and I need to alert the user to an Upcoming event.
so I want to know what's the best practice to do this, and how should I do it, since the current solution I have isn't even working very well.
the way I do it now is by using an AlarmManager to trigger the a BroadcasReciever that creates and shows the notification.
do I need to use a service? and if so, how should I do it?
CODE:
private void StartDBUpdateAlarm() // Start the alarm manager for event reminder
{
// Get the eventos orded by date (Later than DateTime.Now),
// so that we can get the earliest events
var eventos = eventDao.Select(FromEventos.OrderByDate, DateTime.Now);
if ((eventos.Count > 0)) // Only create notification if there is an event
{
// Create the Intent to pass some info through it to the notification
Intent alarmIntent = new Intent(this, typeof(ReminderReciever));
// Putting the information that will be passed with constant Id's
alarmIntent.PutExtra(GerirUtils.INTENT_TITLE, GetString(Resource.String.main_notification_title));
alarmIntent.PutExtra(GerirUtils.INTENT_INFO, "Info");
alarmIntent.PutExtra(GerirUtils.INTENT_CONTENT, eventos[0].Descricao);
// Creating/Recreating the Pending Intent that will pass the actual information to the notification
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, GerirUtils.NOTIFICATION_REMINDER_ID, alarmIntent, 0);
// Getting the date and time of the next event, then calculate the diference between DateTime.Now,
// to know how much time it'll be until next event, so that we know when to trigger the notification
DateTime eventDateTime = CalendarHelper.EventDateTime(eventos[0]);
TimeSpan eventMillis = (eventDateTime - GerirUtils.BaseUTCDate); // BaseDate is just the Utc date = 1970/01/01, because the alarm counts millis since then
// Creating and setting the alarm manager
alarm = (AlarmManager)GetSystemService(Context.AlarmService);
alarm.SetExact(AlarmType.RtcWakeup, (long)eventMillis.TotalMilliseconds, pendingIntent);
}
}
BROADCAST RECIEVER CLASS
[BroadcastReceiver(Enabled = true)]
public class ReminderReciever : BroadcastReceiver
{
private string type, title, info, content;
private IList<string> events;
private int notificationId;
private Context context;
public override void OnReceive(Context context, Intent intent)
{
this.context = context;
notificationId = intent.GetIntExtra(GerirUtils.INTENT_ID, -1);
type = intent.GetStringExtra(GerirUtils.INTENT_TYPE);
events = intent.GetStringArrayListExtra(GerirUtils.INTENT_EVENTS);
title = intent.GetStringExtra(GerirUtils.INTENT_TITLE);
info = intent.GetStringExtra(GerirUtils.INTENT_INFO);
content = intent.GetStringExtra(GerirUtils.INTENT_CONTENT);
if(notificationId > -1)
if(type == GerirUtils.NOTIFICATION_TYPE_EVENT_REMINDER)
ShowNotification();
else if(type == GerirUtils.NOTIFICATION_TYPE_ADDED_EVENTS)
ShowNotificationList();
}
private void ShowNotification()
{
Android.Net.Uri sound = RingtoneManager.GetDefaultUri(RingtoneType.Alarm);
NotificationManager mNotificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
NotificationChannel channel = new NotificationChannel("default", title, NotificationImportance.Default) { Description = content };
mNotificationManager.CreateNotificationChannel(channel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "default")
.SetSmallIcon(Resource.Mipmap.ic_calendario_gerir) // notification icon
.SetContentTitle(title) // title for notification
.SetContentText(content) // message for notification
.SetContentInfo(info) // Info message next to content
.SetSound(sound) // set alarm sound for notification
.SetAutoCancel(true); // clear notification after click
Intent intent = new Intent(context, typeof(MainActivity));
PendingIntent pi = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.UpdateCurrent);
mBuilder.SetContentIntent(pi);
mNotificationManager.Notify(0, mBuilder.Build());
}
}
Well,I managed to find the problem after carefully inspecting the code, it looked like I wasn't sending an notificationId, through the intent. the the intent on the BroadcastReviever was always the default -1, so the if statement was always false and, dumb ol' me, didn't put a message warning when the Id was -1, so I had a harder time to find the error then what I would've if I had the message.
and so, the solution was adding this line of code to the program:
private void StartDBUpdateAlarm() // Start the alarm manager for event reminder
{
...
...
if ((eventos.Count > 0)) // Only create notification if there is an event
{
// Create the Intent to pass some info through it to the notification
Intent alarmIntent = new Intent(this, typeof(ReminderReciever));
// MISSING LINE OF CODE
alarmIntent.PutExtra(GerirUtils.INTENT_ID, GerirUtils.NOTIFICATION_REMINDER_ID);
...
...
...
}
}

Start Sound on BroadCast Recieving in Xamarin Android

MainActivity.cs
private void StartAlarm()
{
Intent myIntent;
PendingIntent pendingIntent; myIntent = new Intent(this, typeof(AlarmToastReceiver));
pendingIntent = PendingIntent.GetBroadcast(this, 0, myIntent, 0);
alarm_manager.Set(AlarmType.RtcWakeup, calndr.TimeInMillis, pendingIntent);
}
AlarmToastReceiver.cs
[BroadcastReceiver(Enabled =true)]
public class AlarmToastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "THIS IS MY ALARM", ToastLength.Long).Show();
}
}
I am going to create an Alaram App in Xamarin. So here i pick the Time from TimePicker, and then and set the Alaram Manager Instance. When the Pending Intent completed , then BroadCastReceiver is active, and a Message is Shown to me,i.e "THIS IS MY ALARM", but here i want to Start Some Kind of Sound, i.e Animal Sound,Bird Sound etc.So how i can do it,can any one help me?thanks in advance.
You can use MediaPlugin documented here.
Here is nice blog post, which I reccomend to read.

Pending Intent Extras are not set for Launcher Application

I have created a Launcher application named HomeActivity which has a LaunchMode = SingleTask and CATEGORY_HOME and CATEGORY_LAUNCHER. This activity in turn starts new activities and some other applications as well.
The activity is connected with a Firebase Messaging service to get Push notifications. The Firebase service adds some extras (gathered from the push notification and sends them in Extras in HomeActivity
public override void OnMessageReceived(RemoteMessage message)
{
Notification.Builder builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.Icon);
Intent intent = new Intent(this, typeof(HomeActivity));
intent.AddFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
intent.PutExtra(General.UPDATE_NOTIFIED, true);
if(message.Data != null)
{
if (message.Data.Any())
{
foreach(KeyValuePair<string,string> kv in message.Data)
{
intent.PutExtra(kv.Key, kv.Value);
}
}
}
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
builder.SetContentIntent(pendingIntent);
builder.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.app_logo));
builder.SetContentTitle(message.GetNotification().Title);
builder.SetContentText(message.GetNotification().Body);
builder.SetDefaults(NotificationDefaults.Sound);
builder.SetAutoCancel(true);
NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(1, builder.Build());
}
Whenever the HomeActivity is on top and a push notification is received and clicked, I can access the Extras in HomeActivity's OnResume function (I have overriden OnNewIntent(Intent intent)).
protected override void OnNewIntent(Intent intent)
{
bool updateNotification = intent.GetBooleanExtra(General.UPDATE_NOTIFIED, false); //Check if Extra is set
this.Intent = intent;
base.OnNewIntent(intent);
}
But when I am in another activity which is launched by the HomeActivity and a Push notification is clicked; the app does return to the HomeActivity but there are no Extras in the Intent.
I have tried all sorts of Flags, including but not limited to NewTask, ClearTask as well.
I am still unable to get why the Extras aren't being set when the notification is clicked at the time another activity is in place. What am I missing here.
Ok so I figured out what the issue is.
The Firebase system WILL NOT fire the OnMessageReceived method if you post a Notification with data (That is a display message).
What is needed to be done is that only data payload in the push notification will fire the OnMessageRecieved function which is responsible for setting the data.
So the notification should be like
{
to: "topic | Registered device",
data:{
data1: "data_value1",
data2: "data_value2",
data3: "data_value3",
}
}

Categories