Just wondering if there is an event In Xamarin for the activity class like OnStart, OnResume, OnPause etc. that gets fired when the user locks or unlocks their screen while the app is open, I've been looking for such an event in documentation etc, but I haven't been able to find it.
If there is no such event, then how can we create it?
Xamarin C# activity on screen (un)lock event
you could create a listener class to listen for android lock screen and unlock events,use broadcast to receive the state of screen.
first create a ScreenListener.cs :
public class ScreenListener
{
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private static ScreenStateListener mScreenStateListener;
public ScreenListener(Context context)
{
mContext = context;
mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
* screen BroadcastReceiver
*/
private class ScreenBroadcastReceiver : BroadcastReceiver
{
private String action = null;
public override void OnReceive(Context context, Intent intent)
{
action = intent.Action;
if (Intent.ActionScreenOn == action)
{ // screen on
mScreenStateListener.onScreenOn();
}
else if (Intent.ActionScreenOff == action)
{ // screen off
mScreenStateListener.onScreenOff();
}
else if (Intent.ActionUserPresent == action)
{ // unlock
mScreenStateListener.onUserPresent();
}
}
}
/**
* begin to listen screen state
*
* #param listener
*/
public void begin(ScreenStateListener listener)
{
mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
* get screen state
*/
private void getScreenState()
{
PowerManager manager = (PowerManager)mContext
.GetSystemService(Context.PowerService);
if (manager.IsScreenOn)
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOn();
}
}
else
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOff();
}
}
}
/**
* stop listen screen state
*/
public void unregisterListener()
{
mContext.UnregisterReceiver(mScreenReceiver);
}
/**
* regist screen state broadcast
*/
private void registerListener()
{
IntentFilter filter = new IntentFilter();
filter.AddAction(Intent.ActionScreenOn);
filter.AddAction(Intent.ActionScreenOff);
filter.AddAction(Intent.ActionUserPresent);
mContext.RegisterReceiver(mScreenReceiver, filter);
}
public interface ScreenStateListener
{// Returns screen status information to the caller
void onScreenOn();
void onScreenOff();
void onUserPresent();
}
}
then in the MainActivity.cs:
public class MainActivity : AppCompatActivity,ScreenStateListener
{
ScreenListener mScreenListener;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
mScreenListener = new ScreenListener(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
mScreenListener.unregisterListener();
}
protected override void OnResume()
{
base.OnResume();
mScreenListener.begin(this);
}
public void onScreenOn()
{
Console.WriteLine("onScreenOn");
}
public void onScreenOff()
{
Console.WriteLine("onScreenOff");
}
public void onUserPresent()
{
Console.WriteLine("onUserPresent");
}
}
Here's a sample of Xamarin.Android activities lifecycle.
You can override any of the lifecycle methods like this:
protected override void OnResume() {
base.OnResume();
}
Like in native Android OnPause is fired when the system is about to put the activity into the background. OnResume is called when the activity is ready to start interacting with the user.
OnPause and OnResume can be used for your (un)lock events.
Related
I'm programming a small widget that needs to be updated whenever the user changes the ringer volume or the vibrate settings.
Capturing android.media.VIBRATE_SETTING_CHANGED works just fine for the vibrate settings, but I haven't found any way of getting notified when the ringer volume changes and although I could try to capture when the user presses the volume up/volume down physical keys, there are many other options for changing the volume without using these keys.
Do you know if there's any broadcast action defined for this or any way to create one or to solve the problem without it?
There is no broadcast action, but I did find you can hook up a content observer to get notified when the settings change, volume of streams being some of those settings. Register for the android.provider.Settings.System.CONTENT_URI to be notified of all settings changes:
mSettingsContentObserver = new SettingsContentObserver( new Handler() );
this.getApplicationContext().getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true,
mSettingsContentObserver );
The content observer might look something like this:
public class SettingsContentObserver extends ContentObserver {
public SettingsContentObserver(Handler handler) {
super(handler);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.v(LOG_TAG, "Settings change detected");
updateStuff();
}
}
And be sure to unregister the content observer at some point.
Nathan's code works but gives two notifications for each change system settings. To avoid that, use the following
public class SettingsContentObserver extends ContentObserver {
int previousVolume;
Context context;
public SettingsContentObserver(Context c, Handler handler) {
super(handler);
context=c;
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta=previousVolume-currentVolume;
if(delta>0)
{
Logger.d("Decreased");
previousVolume=currentVolume;
}
else if(delta<0)
{
Logger.d("Increased");
previousVolume=currentVolume;
}
}
}
Then in your service onCreate register it with:
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
Then unregister in onDestroy:
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
Yes, you can register a receiver for a volume change(this is kind of a hack, but works), I managed to do it this way (does not involve a ContentObserver):
In manifest xml file:
<receiver android:name="com.example.myproject.receivers.MyReceiver" >
<intent-filter>
<action android:name="android.media.VOLUME_CHANGED_ACTION" />
</intent-filter>
</receiver>
BroadcastReceiver:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) {
Log.d("Music Stream", "has changed");
}
}
}
hope it helps!
Based into Nathan's, adi's and swooby's code I created a full working example with some minor improvements.
Looking to the AudioFragment class we can see how easy is to listen for volume changes with our custom ContentObserver.
public class AudioFragment extends Fragment implements OnAudioVolumeChangedListener {
private AudioVolumeObserver mAudioVolumeObserver;
#Override
public void onResume() {
super.onResume();
// initialize audio observer
if (mAudioVolumeObserver == null) {
mAudioVolumeObserver = new AudioVolumeObserver(getActivity());
}
/*
* register audio observer to identify the volume changes
* of audio streams for music playback.
*
* It is also possible to listen for changes in other audio stream types:
* STREAM_RING: phone ring, STREAM_ALARM: alarms, STREAM_SYSTEM: system sounds, etc.
*/
mAudioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
}
#Override
public void onPause() {
super.onPause();
// release audio observer
if (mAudioVolumeObserver != null) {
mAudioVolumeObserver.unregister();
}
}
#Override
public void onAudioVolumeChanged(int currentVolume, int maxVolume) {
Log.d("Audio", "Volume: " + currentVolume + "/" + maxVolume);
Log.d("Audio", "Volume: " + (int) ((float) currentVolume / maxVolume) * 100 + "%");
}
}
public class AudioVolumeContentObserver extends ContentObserver {
private final OnAudioVolumeChangedListener mListener;
private final AudioManager mAudioManager;
private final int mAudioStreamType;
private int mLastVolume;
public AudioVolumeContentObserver(
#NonNull Handler handler,
#NonNull AudioManager audioManager,
int audioStreamType,
#NonNull OnAudioVolumeChangedListener listener) {
super(handler);
mAudioManager = audioManager;
mAudioStreamType = audioStreamType;
mListener = listener;
mLastVolume = audioManager.getStreamVolume(mAudioStreamType);
}
/**
* Depending on the handler this method may be executed on the UI thread
*/
#Override
public void onChange(boolean selfChange, Uri uri) {
if (mAudioManager != null && mListener != null) {
int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType);
int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
if (currentVolume != mLastVolume) {
mLastVolume = currentVolume;
mListener.onAudioVolumeChanged(currentVolume, maxVolume);
}
}
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
}
public class AudioVolumeObserver {
private final Context mContext;
private final AudioManager mAudioManager;
private AudioVolumeContentObserver mAudioVolumeContentObserver;
public AudioVolumeObserver(#NonNull Context context) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
public void register(int audioStreamType,
#NonNull OnAudioVolumeChangedListener listener) {
Handler handler = new Handler();
// with this handler AudioVolumeContentObserver#onChange()
// will be executed in the main thread
// To execute in another thread you can use a Looper
// +info: https://stackoverflow.com/a/35261443/904907
mAudioVolumeContentObserver = new AudioVolumeContentObserver(
handler,
mAudioManager,
audioStreamType,
listener);
mContext.getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI,
true,
mAudioVolumeContentObserver);
}
public void unregister() {
if (mAudioVolumeContentObserver != null) {
mContext.getContentResolver().unregisterContentObserver(mAudioVolumeContentObserver);
mAudioVolumeContentObserver = null;
}
}
}
public interface OnAudioVolumeChangedListener {
void onAudioVolumeChanged(int currentVolume, int maxVolume);
}
Hope it's still useful for someone! :)
Nathan's and adi's code works, but can be cleaned up and self-contained to:
public class AudioStreamVolumeObserver
{
public interface OnAudioStreamVolumeChangedListener
{
void onAudioStreamVolumeChanged(int audioStreamType, int volume);
}
private static class AudioStreamVolumeContentObserver
extends ContentObserver
{
private final AudioManager mAudioManager;
private final int mAudioStreamType;
private final OnAudioStreamVolumeChangedListener mListener;
private int mLastVolume;
public AudioStreamVolumeContentObserver(
#NonNull
Handler handler,
#NonNull
AudioManager audioManager, int audioStreamType,
#NonNull
OnAudioStreamVolumeChangedListener listener)
{
super(handler);
mAudioManager = audioManager;
mAudioStreamType = audioStreamType;
mListener = listener;
mLastVolume = mAudioManager.getStreamVolume(mAudioStreamType);
}
#Override
public void onChange(boolean selfChange)
{
int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
if (currentVolume != mLastVolume)
{
mLastVolume = currentVolume;
mListener.onAudioStreamVolumeChanged(mAudioStreamType, currentVolume);
}
}
}
private final Context mContext;
private AudioStreamVolumeContentObserver mAudioStreamVolumeContentObserver;
public AudioStreamVolumeObserver(
#NonNull
Context context)
{
mContext = context;
}
public void start(int audioStreamType,
#NonNull
OnAudioStreamVolumeChangedListener listener)
{
stop();
Handler handler = new Handler();
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioStreamVolumeContentObserver = new AudioStreamVolumeContentObserver(handler, audioManager, audioStreamType, listener);
mContext.getContentResolver()
.registerContentObserver(System.CONTENT_URI, true, mAudioStreamVolumeContentObserver);
}
public void stop()
{
if (mAudioStreamVolumeContentObserver == null)
{
return;
}
mContext.getContentResolver()
.unregisterContentObserver(mAudioStreamVolumeContentObserver);
mAudioStreamVolumeContentObserver = null;
}
}
If its only ringer mode change you can use Brodcast receiver with "android.media.RINGER_MODE_CHANGED" as the action. It will easy to implement
Hi i tried the code above and it did not work for me. But when i tried to add this line
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
and put
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
It works now. My concern is how to hide the volume dialog onchange. See this image.
private const val EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"
private const val VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"
val filter = IntentFilter(VOLUME_CHANGED_ACTION)
filter.addAction(RINGER_MODE_CHANGED_ACTION)
val receiver = object : BroadcastReceiver() {
override fun onReceive(context1: Context, intent: Intent) {
val stream = intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, UNKNOWN)
val mode = intent.getIntExtra(EXTRA_RINGER_MODE, UNKNOWN)
val volumeLevel = audioManager.getStreamVolume(stream)
}
}
100% working way in all cases
public class SettingsContentObserver extends ContentObserver {
SettingsContentObserver(Handler handler) {
super(handler);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
volumeDialogContract.updateMediaVolume(getMediaVolume());
}
int getMediaVolume() {
return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
void unRegisterVolumeChangeListener() {
volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().
unregisterContentObserver(settingsContentObserver);
}
void registerVolumeChangeListener() {
settingsContentObserver = new VolumeDialogPresenter.SettingsContentObserver(new Handler());
volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true,
settingsContentObserver);
}
I am using Xamarin Android to build an app which should allow the app to keep sending a driver's location every 15 minutes so that I can keep track of his movement. I used JobScheduler to get this done. My project is very simple now and only contains the following 3 files:
MainActivity.cs
AttendancePage.cs (Content page, interact with UI button to start the service)
ServiceClass.cs
Methods in Main Activity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
scheduler = (JobScheduler)GetSystemService(JobSchedulerService);
LoadApplication(new App()); //This line will then jump to AttendancePage.cs
}
public void ScheduleJob()
{
ComponentName componentName = new ComponentName(this, Java.Lang.Class.FromType(typeof(ServiceClass)));
JobInfo info = new JobInfo.Builder(123, componentName)
.SetPersisted(true)
.SetPeriodic(60000)
.Build();
int resultCode = scheduler.Schedule(info); //The error show when hit this line.
if (resultCode == JobScheduler.ResultSuccess)
{
Log.Info("Message", "Job Schedule!");
}
else
{
Log.Info("Message", "Job shceduling failed");
}
}
public void CancelJob()
{
scheduler.Cancel(123);
}
AttendancePage.cs
public partial class AttendancePage : ContentPage
{
MainActivity main = new MainActivity();
public AttendancePage()
{
InitializeComponent();
Title = "Attendance App";
}
//Button OnClickEvent
async void ScheduleJob(object s, EventArgs e)
{
main.ScheduleJob();
}
//Button OnClickEvent
async void CancelJob(object s, EventArgs e)
{
main.CancelJob();
}
}
ServiceClass.cs
[Service(Name = "com.SampleApp.AttendanceApp.ServiceClass", Permission = "android.permission.BIND_JOB_SERVICE")]
public class ServiceClass : JobService
{
public ServiceClass()
{
}
public override bool OnStartJob(JobParameters jobParamsOnStart)
{
doBackgroundWork(jobParamsOnStart);
return true;
}
private void doBackgroundWork(JobParameters jobParam)
{
//My code to send driver's location
TestingPage.GetGPS();
JobFinished(jobParam, false);
}
public override bool OnStopJob(JobParameters jobParamsOnStop)
{
return false;
}
}
I have added the service tag inside AndroidManifest.xml as well.
<service android:name=".ServiceClass"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true" />
I have no idea why the error is still there. The error is from the line scheduler.Schedule(JobInfo). Anyone has another possible solution? I am frustrated on solving this. Will the reason be I can't debug on the service but only can straight away run in release mode? Please help.
Froms shared code it works in Xamarin.Android project , however here is a Xamarin.Forms project . It can not work.
In AttendancePage.cs , you create a new MainActivity to invoke the native method ScheduleJob and CancelJob . This will not find the JobScheduler in native ,then it will return null .
No such service ComponentInfo{/com.SampleApp.AttendanceApp.ServiceClass}
If you want to invoke native method , you can have a try with DependencyService in Xamarin Forms .
At least need to create a Interface in Forms to invoke :
public interface IJobSchedulerService
{
//Start JobSchedule
void StartJobSchedule();
//Cancel JobSchedule
void CancelJobSchedule();
}
Then can invoke in Xamarin Forms as follow :
async void ScheduleJob(object s, EventArgs e)
{
DependencyService.Get<IJobSchedulerService>().StartJobSchedule();
}
//Button OnClickEvent
async void CancelJob(object s, EventArgs e)
{
DependencyService.Get<IJobSchedulerService>().CancelJobSchedule();
}
Now you need to implement the IJobSchedulerService in native android .Create the JobSchedulerDependcenyService:
public class JobSchedulerDependcenyService : IJobSchedulerService
{
JobScheduler jobScheduler;
public JobSchedulerDependcenyService()
{
jobScheduler = (JobScheduler)MainActivity.Instance.GetSystemService(Android.Content.Context.JobSchedulerService);
}
public void StartJobSchedule()
{
ComponentName componentName = new ComponentName(MainActivity.Instance, Java.Lang.Class.FromType(typeof(DownloadJob)));
JobInfo jobInfo = new JobInfo.Builder(1, componentName)
.SetOverrideDeadline(0)
.Build();
//var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var scheduleResult = jobScheduler.Schedule(jobInfo);
if (JobScheduler.ResultSuccess == scheduleResult)
{
var snackBar = Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content), "jobscheduled_success", Snackbar.LengthShort);
snackBar.Show();
}
else
{
var snackBar = Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content), "jobscheduled_failure", Snackbar.LengthShort);
snackBar.Show();
}
}
public void CancelJobSchedule()
{
jobScheduler.CancelAll();
}
}
Here you will find the MainActivity.Instance inside it , that's a static instance defined by self in MainActivity.
public static MainActivity Instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Instance = this;
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
I am currently developing an android xamarin app (android 6 and above) and I have got a problem.
Our customer wants to secure the app by a pinpad. Whenever the app is started the user has to enter a four digit pin.
We have created an activity for the pinpad. This works pretty fine, but the problem is the following:
The pinpad just opens if the app was completely killed (e.g. by the task manager ) -> cold started.
How can I achive that the pinpad opens if the app was in the background and reopend by the task manager for example (user pressed home button and then wants to start app again) -> warm started.
I've tried to do this by OnResume(), OnStart(),. But unfortunately they trigger every time an another activity (e.g. open detail view of list item) is opened.
use IActivityLifecycleCallbacks to listen the status.
Application registration ActivityLifecycleCallbacks, such, when each activity in the app lifecycle occurs, the Application can be listening to. The number of public void onActivityStarted(activity activity) and public void onActivityStopped(activity activity) of an activity can be used to determine whether the app is in the foreground. Because when the app is in the foreground, an activity must have started onActivityStarted but not onActivityStopped, so the statistics of the number of activities opened in the app must be 1. When the app switches to the background, activityStartCount will be 0.
so write a Helper classes :
public class AppFrontBackHelper
{
public static OnAppStatusListener mOnAppStatusListener;
private LifecycleCallBack lifecycleCallBack;
public AppFrontBackHelper()
{
}
/**
* Register status listener, only used in Application
* #param application
* #param listener
*/
public void register(Application application, OnAppStatusListener listener)
{
mOnAppStatusListener = listener;
lifecycleCallBack = new LifecycleCallBack();
application.RegisterActivityLifecycleCallbacks(lifecycleCallBack);
}
public void unRegister(Application application) => application.UnregisterActivityLifecycleCallbacks(lifecycleCallBack);
public interface OnAppStatusListener
{
void onFront();
void onBack();
}
public class LifecycleCallBack : Java.Lang.Object, Application.IActivityLifecycleCallbacks
{
public int activityStartCount { get; private set; }
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
activityStartCount++;
//A value from 1 to 0 indicates cutting from the background to the foreground
if (activityStartCount == 1)
{
if (mOnAppStatusListener != null)
{
mOnAppStatusListener.onFront();
}
}
}
public void OnActivityStopped(Activity activity)
{
activityStartCount--;
//A value from 1 to 0 indicates cutting from the foreground to the background
if (activityStartCount == 0)
{
//从前台切到后台
if (mOnAppStatusListener != null)
{
mOnAppStatusListener.onBack();
}
}
}
}
}
then custom an Application and regist the listener :
[Application]
public class MyApplication : Application,AppFrontBackHelper.OnAppStatusListener
{
protected MyApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate()
{
base.OnCreate();
AppFrontBackHelper appFrontBackHelper = new AppFrontBackHelper();
appFrontBackHelper.register(this, this);
}
public void onBack()
{
Toast.MakeText(this, "from front to back", ToastLength.Short).Show();
}
public void onFront()
{
Toast.MakeText(this, "from back to front", ToastLength.Short).Show();
}
}
you could do something in the onFront() callback.
I'm creating an Android App in C# Xamarin.
Is there a way to "listen" for volume up/down key presses when an App goes into "background" mode, i.e. when a user "locks" their phone?
I've created several Service objects and made them "resident" by issuing the command 'StartCommandResult.Sticky'.
Any sample C# Xamarin code would be much appreciated.
You do not need to create a background service, just start a another task to listen the volume control. If the application do not be killed the task will run on the background.
public class MainActivity : Activity
{
private int currentVolume;
public AudioManager mAudioManager;
private int maxVolume;
private bool isDestory;
Android.Media.MediaPlayer player;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
player = Android.Media.MediaPlayer.Create(this, Resource.Raw.SampleAudio);
SetContentView (Resource.Layout.Main);
mAudioManager = (AudioManager)GetSystemService(Context.AudioService);
maxVolume = mAudioManager.GetStreamMaxVolume(Stream.Music);
onVolumeChangeListener();
player.Start();
}
protected override void OnDestroy()
{
base.OnDestroy();
isDestory = true;
}
private Task voluemChangeTask;
public void onVolumeChangeListener()
{
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
voluemChangeTask = new Task(ChangeVolume);
voluemChangeTask.Start();
}
public void ChangeVolume()
{
while (!isDestory)
{
int count = 0;
try
{
Thread.Sleep(20);
}
catch (Exception e)
{
}
if (currentVolume < mAudioManager.GetStreamVolume(Stream.Music))
{
System.Console.WriteLine("volunm+");
count++;
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
mAudioManager.SetStreamVolume(Stream.Music, currentVolume, VolumeNotificationFlags.RemoveSoundAndVibrate);
}
if (currentVolume > mAudioManager.GetStreamVolume(Stream.Music))
{
System.Console.WriteLine("volunm-");
count++;
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
mAudioManager.SetStreamVolume(Stream.Music, currentVolume, VolumeNotificationFlags.RemoveSoundAndVibrate);
}
}
}
}
I have tested it in the real device with screen lock and got the log:
Hello, I want to build an app, in which you can start a service, which runs intependenly and creates a notification, and this service should constantly proof, if the DateTime.Now.Date is bigger than a spezific Date.
When I execute the code below, the notification gets displayed, but when I am closing the app, a few secondes later I get two times an information that the app crashed and I dont know why.
I cant even debug the code because this anly happens when the application is closed....
I hope you can help me thanks!
Here is my code:
namespace App
{
[Activity(Label = "App", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate {
button.Text = string.Format("{0} clicks!", count++);
StartService(new Intent(this, typeof(backgroudservice)));
};
}
}
public class backgroudservice : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
newnotification("Title", "Text: ", 0);
new Task(() => {
DoWork();
Thread.Sleep(1000);
}).Start();
return StartCommandResult.Sticky;
}
public void DoWork()
{
if (DateTime.Now.Date > Convert.ToDateTime("2016-03-29").Date)
{
cancelnotification(0);
StopSelf();
}
}
public override void OnDestroy()
{
base.OnDestroy();
cancelnotification(0);
}
private void newnotification(string titel, string text, int id)
{
Notification.Builder builder = new Notification.Builder(this)
.SetContentTitle(titel)
.SetContentText(text)
.SetSmallIcon(Resource.Drawable.droidlogo_small)
.SetAutoCancel(false)
.SetVisibility(NotificationVisibility.Public)
.SetContentIntent(PendingIntent.GetActivity(this, 0, new Intent(this, typeof(MainActivity)), PendingIntentFlags.OneShot));
// Build the notification:
Notification notification = builder.Build();
notification.Flags = NotificationFlags.NoClear;
//notification.ContentIntent = new Intent(this,typeof(login));
// Get the notification manager:
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
// Publish the notification:
notificationManager.Notify(id, notification);
}
private void cancelnotification(int id)
{
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Cancel(id);
}
}
}
I solved it, I forgot the [Service] above my class, now it works!
[Service]
public class backgroudservice : Service
{
...
}
You might try moving the call to cancelnotification in your service's OnDestroy to before the call to the base method, i.e.:
public override void OnDestroy()
{
cancelnotification(0);
base.OnDestroy();
}