I have a plan and want to periodically check a URL every 5 minutes(NOTIFY CENTER SERVER(Listener)).
My problem: Once the program closes, the process closes
Is it possible that the project will not be shut down if the original program is closed ?
My Code After Changed Worked with : Matcha.BackgroundService
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Matcha.BackgroundService.Droid;
using Matcha.BackgroundService;
using System.Threading.Tasks;
using Android.Util;
using System.Threading;
using AndroidApp = Android.App.Application;
using Android.Content;
using Android.Support.V4.App;
using Android.Graphics;
namespace Solution.Droid
{
[Activity(Label = "Solution", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private NotificationManager _manager;
private bool _channelInitialized = false;
public const int _pendingIntentId = 0;
public int _channelID = 10001;
private long _mssageID=0;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
BackgroundAggregator.Init(this);
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
protected override void OnStart()
{
base.OnStart();
//Register Periodic Tasks
var _notifyTASK = new DevinuxTaskPeriodic(10);
_notifyTASK.DoTask += () =>
{
SendNotify("salam", DateTime.Now.ToString());
};
BackgroundAggregatorService.Add(() => _notifyTASK);
BackgroundAggregatorService.StartBackgroundService();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
public int SendNotify(string title, string message)
{
_mssageID++;
if (!_channelInitialized)
{
CreateNotificationChannel();
}
Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity));
PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, _pendingIntentId, intent, PendingIntentFlags.OneShot);
NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, _channelID.ToString())
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.notification_template_icon_bg))
.SetSmallIcon(Resource.Drawable.notification_template_icon_bg)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
Notification notification = builder.Build();
_manager.Notify((int)_mssageID, notification);
return (int)_mssageID;
}
void CreateNotificationChannel()
{
_manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String("Solution");
var channel = new NotificationChannel(_channelID.ToString(), channelNameJava, NotificationImportance.Default)
{
Description = "My Company Notify Camp."
};
_manager.CreateNotificationChannel(channel);
}
_channelInitialized = true;
}
public class DevinuxTaskPeriodic : IPeriodicTask
{
public bool use { set; get; } = false;
public delegate void DoArgs();
public event DoArgs DoTask;
public DevinuxTaskPeriodic(int seconds)
{
Interval = TimeSpan.FromSeconds(seconds);
}
public TimeSpan Interval { get; set; }
public Task<bool> StartJob()
{
if (!use)
{
Timer tmr = new Timer((o) => {
if (DoTask != null)
{
DoTask();
}
}, null, 0, (int)Interval.TotalSeconds*1000);
}
use = true;
return new Task<bool>(() => true);
}
}
}
}
Yes, it is possible to run processes even when the original program/app is not in the foreground.
You are entering the territory of "backgrounding" which is less simple to do. There isn't an inbuilt/official way of performing backgrounding using Xamarin.Forms, so you will have to either create a dependency service (shown here), or try using Shiny.
If you follow the dependency services route, you just need to follow the official iOS & Android tutorials and implement them in your Native project. Note that if you only need a periodic alarm, Android provides a simpler Alarm/PowerManager that you can use.
Related
I have a Xamarin Form application which has a language dropdown so user can select the application language. When user select a language I call:
CultureInfo culture = CultureInfo.CreateSpecificCulture(language);
System.Globalization.CultureInfo.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
AppResources.Culture = culture;
The application works fine and picks the strings from AppResources.{language}.resx
My problem is when localising an image. As per Microsoft's suggestion I have added my image to Resources/drawable folders inside the android project. In my case, I added thanks.jpg to Resources/drawable and Resources/drawable-fr. But it only shows the image on Resources/drawable folder even when I select fr-FR as language, however I found out if instead of changing the application language(culture), I change the device language, the device show the correct image(the image inside Resources/drawable-fr). I was wondering if there is any way to fix this issue.
You can create a dependence service to fix it.
First of all, create a interface.
public interface IChangeService
{
void ChangeIanguage(string lang);
}
We used it in the this format code in the xamarin forms.
<StackLayout>
<TimePicker></TimePicker>
<Image WidthRequest="100">
<Image.Source>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="flag.png" />
<On Platform="UWP" Value="Assets/Images/flag.png" />
</OnPlatform>
</Image.Source>
</Image>
<Button Text="Change" Clicked="Button_Clicked"></Button>
</StackLayout>
Here is background code.
public partial class LocalizedXamlPage : ContentPage
{
public LocalizedXamlPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, System.EventArgs e)
{
DependencyService.Get<IChangeService>().ChangeIanguage("en");
}
}
Then achieve the interface in the android platform. If we change the localization, we need it to work at the runtime, we should restart our application.
[assembly: Dependency(typeof(ChangeLanguageService))]
namespace UsingResxLocalization.Droid
{
public class ChangeLanguageService : IChangeService
{
public void ChangeIanguage(string lang = "in")
{
LanguageManager.ChangeLanguage(MainActivity.instance, lang);
//restart your application.
Intent intent = new Intent(MainActivity.instance, typeof(MainActivity));
intent.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
MainActivity.instance.StartActivity(intent);
}
}
}
Then we need to create a BaseActivity(because we change the Locale in android, we should use the same Context.) and LanguageManager(change the localization at the runtime)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
using Java.Util;
using Xamarin.Forms.Platform.Android;
namespace UsingResxLocalization.Droid
{
public class BaseActivity : FormsAppCompatActivity
{
protected override void AttachBaseContext(Context #base)
{
base.AttachBaseContext(LanguageManager.LoadLanguage(#base));
}
}
public class LanguageManager
{
private const string MYLANGUAGE = "myLanguage";
private const string MYPREF = "myPreference";
public static Context LoadLanguage(Context context)
{
var loadedLanguage = GetLanguage(context, Locale.Default.Language);
return ChangeLanguage(context, loadedLanguage);
}
public static Context ChangeLanguage(Context context, string language)
{
SaveLanguage(context, language);
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
return ChangeForAPI24(context, language);
}
return ChangeForLegacy(context, language);
}
private static string GetLanguage(Context context, string Language)
{
var privatePreference = context.GetSharedPreferences(MYPREF, FileCreationMode.Private);
return privatePreference.GetString(MYLANGUAGE, Language);
}
private static void SaveLanguage(Context context, string language)
{
var privatePreference = context.GetSharedPreferences(MYPREF, FileCreationMode.Private);
var editor = privatePreference.Edit();
editor.PutString(MYLANGUAGE, language);
editor.Apply();
}
private static Context ChangeForAPI24(Context context, string language)
{
// for api >= 24
var locale = new Locale(language);
Locale.Default = locale;
var configuration = context.Resources.Configuration;
configuration.SetLocale(locale);
configuration.SetLayoutDirection(locale);
return context.CreateConfigurationContext(configuration);
}
private static Context ChangeForLegacy(Context context, string language)
{
var locale = new Locale(language);
Locale.Default = locale;
var resources = context.Resources;
var configuration = resources.Configuration;
configuration.Locale = locale;
resources.UpdateConfiguration(configuration, resources.DisplayMetrics);
return context;
}
}
}
To make the mainAcitvity extend the BaseActivity.cs. And expose the public static MainActivity instance;,
[Activity(Label = "UsingResxLocalization", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : BaseActivity
{
public static MainActivity instance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
instance = this;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
Here is runinng GIF.
========Update=========
I make a test with France flag by changing language to fr when the device language is English.
I upload my demo to you, you can test it.
https://github.com/851265601/LocalzationDemo/blob/master/LocalzationDemoWithFlag.zip
If you want to change the text of Button or other label, when you click the Button, Please add CultureInfo.CurrentUICulture = new CultureInfo("fr", false); as well in the click event. You can see this GIF.
I'm trying to build my first xamarin app, which I'm building using forms. One of the features of the app is sending users locations and have to do that even if the app is in the background. So I came across James Montemagno's GeolocatorPlugin, which promised to do just that.
As the documentation was not that clear on how to implement his plugin in the background I looked through the projects closed issues and found a guy which gave an example of a simple case of using the plugin with a service. (https://github.com/jamesmontemagno/GeolocatorPlugin/issues/272)
I've adopted the code and created the service. The service are using an interface to start the service and now my problem is how to make use of the interface to make the service run.
In my shared project I put the interface and the viewmodel and in xamarin.android project I put the service.
The interface - IGeolocationBackgroundService:
public interface IGeolocationBackgroundService {
void StartService();
void StartTracking();
}
The viewmodel - GeolocatorPageViewModel:
public class GeolocatorPageViewModel
{
public Position _currentUserPosition { get; set; }
public string CoordinatesString { get; set; }
public List<string> userPositions { get; set; }
public ICommand StartTrackingCommand => new Command(async () =>
{
if (CrossGeolocator.Current.IsListening)
{
await CrossGeolocator.Current.StopListeningAsync();
}
CrossGeolocator.Current.DesiredAccuracy = 25;
CrossGeolocator.Current.PositionChanged += Geolocator_PositionChanged;
await CrossGeolocator.Current.StartListeningAsync(
TimeSpan.FromSeconds(3), 5);
});
private void Geolocator_PositionChanged(object sender, PositionEventArgs e)
{
var position = e.Position;
_currentUserPosition = position;
var positionString = $"Latitude: {position.Latitude}, Longitude: {position.Longitude}";
CoordinatesString = positionString;
Device.BeginInvokeOnMainThread(() => CoordinatesString = positionString);
userPositions.Add(positionString);
Debug.WriteLine($"Position changed event. User position: {CoordinatesString}");
}
}
The service - GeolocationService:
[assembly: Xamarin.Forms.Dependency(typeof(GeolocationService))]
namespace MyApp.Droid.Services
{
[Service]
public class GeolocationService : Service, IGeolocationBackgroundService
{
Context context;
private static readonly string CHANNEL_ID = "geolocationServiceChannel";
public GeolocatorPageViewModel ViewModel { get; private set; }
public override IBinder OnBind(Intent intent)
{
return null;
}
public GeolocationService(Context context)
{
this.context = context;
CreateNotificationChannel();
}
private void CreateNotificationChannel()
{
NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID,
"GeolocationService", Android.App.NotificationImportance.Default);
NotificationManager manager = context.GetSystemService(Context.NotificationService) as NotificationManager;
manager.CreateNotificationChannel(serviceChannel);
}
//[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
var newIntent = new Intent(this, typeof(MainActivity));
newIntent.AddFlags(ActivityFlags.ClearTop);
newIntent.AddFlags(ActivityFlags.SingleTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, newIntent, 0);
var builder = new Notification.Builder(this, CHANNEL_ID);
var notification = builder.SetContentIntent(pendingIntent)
.SetSmallIcon(Resource.Drawable.ic_media_play_light)
.SetAutoCancel(false)
.SetTicker("Locator is recording")
.SetContentTitle("GeolocationService")
.SetContentText("Geolocator is recording for position changes.")
.Build();
StartForeground(112, notification);
//ViewModel = new GeolocatorPageViewModel();
return StartCommandResult.Sticky;
}
public void StartService()
=> context.StartService(new Intent(context, typeof(GeolocationService)));
public void StartTracking()
{
ViewModel = new GeolocatorPageViewModel();
ViewModel.StartTrackingCommand.Execute(null);
}
}
}
So be clear, I need to start the service and I'm not used to interfaces, so how do I call the interface?
use DependencyService to get a reference to your service and then start it
var svc = DependencyService.Get<IGeolocationBackgroundService>();
svc.StartService();
svc.StartTracking();
I am creating an application in Xamarin using visual studio,where that app services always should be running in background even if the app is closed and that service should send notification in a interval.
If that app is closed by the system(in the condition when it is taking more memory space) then it should restart the services by showing the status as "0 process and 0 service Restarting.." under running services list in Settings.
Can anyone help me how to achieve that having some reference of sample project.
In BackgroundService.cs
[Service]
public class BackgroundService : Service
{
const int SERVICE_RUNNING_NOTIFICATION_ID = 123;
const string NOTIFICATION_CHANNEL_ID = "com.company.app.channel";
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug("service", "Service Started");
// Check if device is running Android 8.0 or higher and call StartForeground() if so
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.SetContentTitle(Resources.GetString(Resource.String.app_name))
.SetContentText(Resources.GetString(Resource.String.notification_text))
.SetSmallIcon(Resource.Drawable.notification_icon_background)
.SetOngoing(true)
.Build();
var notificationManager =
GetSystemService(NotificationService) as NotificationManager;
var chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "On-going Notification", NotificationImportance.Min);
notificationManager.CreateNotificationChannel(chan);
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
}
return StartCommandResult.NotSticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnTaskRemoved(Intent rootIntent)
{
Intent restartServiceIntent = new Intent(this, this.Class);
restartServiceIntent.SetPackage(this.PackageName);
Log.Debug("service", "Service Restarted");
PendingIntent restartServicePendingIntent = PendingIntent.GetService(this, 1, restartServiceIntent, PendingIntentFlags.OneShot);
AlarmManager alarmService = (AlarmManager)this.GetSystemService(Context.AlarmService);
alarmService.Set(
AlarmType.ElapsedRealtime,
SystemClock.ElapsedRealtime() + 1000,
restartServicePendingIntent);
base.OnTaskRemoved(rootIntent);
}
}
Updtaed MainActivity.cs
public class MainActivity : AppCompatActivity
{
String alarm = Android.Content.Context.AlarmService;
const string NOTIFICATION_CHANNEL_ID = "com.companyname.ServiceSample3";
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.abc_activity_chooser_view);
Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
//var alarmIntent = new Intent(this, typeof(AlarmReceiver));
//alarmIntent.PutExtra("title", "Hello");
//alarmIntent.PutExtra("message", "World!");
Intent intent = new Intent(NOTIFICATION_CHANNEL_ID);
intent.SetClass(this, typeof(AlarmReceiver));
var pending = PendingIntent.GetBroadcast(this, 0, intent, PendingIntentFlags.UpdateCurrent);
var alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
alarmManager.SetRepeating(AlarmType.ElapsedRealtime, DateTime.Now.Millisecond, 5 * 100, pending);
}
}
Thanks in advance.
Please refer the below sample.You can use alarm manager for restarting the service.
Please follow the steps.
Step 1 :
Create BroadcastReceiver
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace AlarmManagerApp
{
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
class AlarmReceiver : BroadcastReceiver
{
Context context;
public override void OnReceive(Context context, Intent intent)
{
this.context = context;
Toast.MakeText(context,"Recieved",ToastLength.Long).Show();
Intent background = new Intent(context, typeof(BackgroundService));
context.StartService(background);
}
}
}
Step 2: Add AlarmManager in the MainActivity where you want to call the service
namespace AlarmManagerApp
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme.NoActionBar", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
String alarm = Context.AlarmService;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
var alarmIntent = new Intent(this, typeof(AlarmReceiver));
alarmIntent.PutExtra("title", "Hello");
alarmIntent.PutExtra("message", "World!");
var pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
var alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();
alarmManager.SetRepeating(AlarmType.ElapsedRealtime,DateTime.Now.Millisecond, 5 * 100, pending);
}
}
Step 3: Add you Service
namespace AlarmManagerApp
{
[Service]
public class BackgroundService : Service
{
public override void OnCreate()
{
base.OnCreate();
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug("service","Service Started");
//init the handler in oncreate
System.Timers.Timer Timer1 = new System.Timers.Timer();
Timer1.Start();
Timer1.Interval = 3000;
int a = 0;
Timer1.Enabled = true;
//Timer1.Elapsed += OnTimedEvent;
Timer1.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) =>
{
Timer1.Stop();
Timer1.Start();
a++;
//Delete time since it will no longer be used.
Timer1.Dispose();
};
Timer1.Start();
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnTaskRemoved(Intent rootIntent)
{
Intent restartServiceIntent = new Intent(this, this.Class);
restartServiceIntent.SetPackage(this.PackageName);
Log.Debug("service", "Service Restarted");
PendingIntent restartServicePendingIntent = PendingIntent.GetService(this, 1, restartServiceIntent, PendingIntentFlags.OneShot);
AlarmManager alarmService = (AlarmManager)this.GetSystemService(Context.AlarmService);
alarmService.SetRepeating(AlarmType.RtcWakeup, SystemClock.CurrentThreadTimeMillis(), 30 * 1000, restartServicePendingIntent);
NotificationManager notificationManager =
(NotificationManager)GetSystemService(NotificationService);
Notification.Builder builder = new Notification.Builder(this);
Intent notificationIntent = new Intent(this, typeof(MainActivity));
PendingIntent contentIntent = PendingIntent.GetActivity(this, 0, notificationIntent, 0);
//set
builder.SetContentIntent(contentIntent);
builder.SetSmallIcon(Resource.Mipmap.ic_launcher);
builder.SetContentText("Contents");
builder.SetContentTitle("title");
builder.SetAutoCancel(true);
builder.SetDefaults(NotificationDefaults.All);
notificationManager.Notify(1, builder.Build());
base.OnTaskRemoved(rootIntent);
}
}
}
This works also if app is closed and device restarted.
I'm building a crossplatform application using Xamarin,my application will download videos from internet, I've done the download and save functions, but after saved videos to DCIM(in android) the videos do not appear in gallery.After hafl of a day searching for solutions on internet I comeup with two solutions:
1.after download finished: send broadcast with action "Intent.ActionMediaMounted".
2.after download finished Call "MediaScannerConnection.ScanFile".
With solution 1 I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.sendBroadcast(android.content.Intent)' on a null object reference}
With solution 2, I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.bindService(android.content.Intent, android.content.ServiceConnection, int)' on a null object reference}
This is my Interface which I used to handle downloadfinished placed in PLC project:
namespace VideoDownloader
{
public interface IDownloadState
{
void OnDownloadStarted();
void OnDownloadError();
void OnDownloadFinished(string path);
}
}
This is my MainPage.xaml.cs in PLC project:
namespace VideoDownloader
{
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
}
public void downloadVideo(VideoInfor video, bool isRetried)
{
//download code here...
DependencyService.Get<IDownloadState()
.OnDownloadFinished(video.path);
}
}
}
And This is my MainActivity in Android project which implement IDownloadState and send broadcast when OnDownloadFinished fired:
[assembly: Xamarin.Forms.Dependency(typeof(MainActivity))]
namespace VideoDownloader.Droid
{
[Activity(Label = "VideoDownloader", Icon = "#mipmap/icon", Theme =
"#style/MainTheme", MainLauncher = true, ConfigurationChanges =
ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,
IDownloadState
{
readonly string[] StoragePermissions =
{
Manifest.Permission.WriteExternalStorage,
Manifest.Permission.ReadExternalStorage
};
const int RequestStorageId = 0;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
int sdkBuildVersion = (int)Build.VERSION.SdkInt;
Console.WriteLine("SDK build version = " + sdkBuildVersion);
if (sdkBuildVersion >= 23)
{
RequestStoragePermission();
}
}
public override void OnRequestPermissionsResult(int requestCode,
string[] permissions, Permission[] grantResults)
{
switch (requestCode)
{
case RequestStorageId:
{
if (grantResults[0] == Permission.Granted)
{
}
else
{
}
}
break;
default:
break;
}
}
public void OnDownloadStarted()
{
throw new NotImplementedException();
}
public void OnDownloadError()
{
throw new NotImplementedException();
}
public void OnDownloadFinished(string path)
{
//Intent intent = new Intent(Intent.ActionMediaMounted);
//SendBroadcast(intent);
//throw new NotImplementedException();
MediaScannerConnection.ScanFile(this, new String[] {
Android.OS.Environment
.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim)
.AbsolutePath }, null, null);
}
}
}
I know there are many many similar questions for android on stackoverflow that have ansered but they seem to not like my situation at all. So is there anyone know what am I doing wrong? Why this is happening?
With solution 2, I got:
"{Java.Lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.bindService(android.content.Intent, android.content.ServiceConnection, int)' on a null object reference}
Please try to use Forms.Context instead of this in OnDownloadFinished().
For example:
public void OnDownloadFinished(string path)
{
//Intent intent = new Intent(Intent.ActionMediaMounted);
//SendBroadcast(intent);
//throw new NotImplementedException();
MediaScannerConnection.ScanFile(Forms.Context, new String[] {
Android.OS.Environment
.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim)
.AbsolutePath }, null, null);
}
I'm creating new app using xamarin. I have already completed some part using some sample codes. I'm able to disable back buttons, volume buttons and power button.
But when trying to disable home button I'm getting error on debugging.
I'm following this link,Kiosk mode in Andriod.
But when trying to disable home button I'm getting error on debugging.
Since you didn't post your code and your error message, we don't know what happened, I just tried to create such a sample followed the blog your posted and it works fine by my side.
Here is the service:
namespace KioskModeAndroid
{
[Service]
[IntentFilter(new[] { "KioskModeAndroid.KioskService" })]
public class KioskService : Service
{
private static long INTERVAL = Java.Util.Concurrent.TimeUnit.Seconds.ToMillis(2);
private static string TAG = typeof(KioskService).Name;
private static string PREF_KIOSK_MODE = "pref_kiosk_mode";
private Thread t = null;
private Context ctx = null;
private bool running = false;
public override void OnDestroy()
{
Log.Info(TAG, "Stopping service 'KioskService'");
running = false;
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Log.Info(TAG, "Starting service 'KioskService'");
running = true;
ctx = this;
t = new Thread(() =>
{
while (running)
{
handleKioskMode();
Thread.Sleep(INTERVAL);
}
StopSelf();
});
t.Start();
return StartCommandResult.NotSticky;
}
private void handleKioskMode()
{
if (isKioskModeActive(ctx))
{
}
if (isInBackground())
{
restoreApp();
}
}
private bool isKioskModeActive(Context context)
{
var sp = PreferenceManager.GetDefaultSharedPreferences(context);
return sp.GetBoolean(PREF_KIOSK_MODE, false);
}
private bool isInBackground()
{
var am = ctx.GetSystemService(Context.ActivityService) as ActivityManager;
var processes = am.RunningAppProcesses;
foreach (var process in processes)
{
if (process.Importance == ActivityManager.RunningAppProcessInfo.ImportanceForeground)
{
foreach (var activeprocess in process.PkgList)
{
if (activeprocess == ctx.PackageName)
return false;
}
}
}
return true;
}
private void restoreApp()
{
Intent i = new Intent(ctx, typeof(MainActivity));
i.AddFlags(ActivityFlags.NewTask);
ctx.StartActivity(i);
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
}
I started this service in the OnCreate of MainActivity:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
StartService(new Intent(this, typeof(KioskService)));
}