Xamarin Forms pedometer application foreground service problem on android oreo 8.1 and android pie 9.0 - xamarin.forms

I am using foreground service if OS version >= 8.0. On android 8.1 and 9.0 when my pedometer app is open or on the background it is counting steps, but not when the app is closed. Also after closing the app notification icon disappearing from the phone screen. Tested on Oreo 8.0 using foreground service, it is working fine and counting steps when the app is closed. Tested also on android Nougat 7.0 with background service and working with no problems.
BootReceiver.cs
[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new string[] { Intent.ActionBootCompleted, Intent.ActionLockedBootCompleted, "android.intent.action.QUICKBOOT_POWERON", "com.htc.intent.action.QUICKBOOT_POWERON" })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var stepServiceIntent = new Intent(context, typeof(StepService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
context.StartForegroundService(stepServiceIntent);
}
else
{
context.StartService(stepServiceIntent);
}
}
}
StepServiceBinder.cs
public class StepServiceBinder : Binder
{
StepService stepService;
public StepServiceBinder(StepService service)
{
this.stepService = service;
}
public StepService StepService
{
get { return stepService; }
}
}
StepServiceConnection.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
*Manifest.xml *
<manifest android:versionName="1.1" package="com.PedometerApp" android:installLocation="internalOnly" android:versionCode="11">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27" />
<application android:label="My Pedometer" android:icon="#drawable/logo"> </application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
StepService.cs
[Service(Enabled = true)]
[IntentFilter(new String[] { "com.PedometerApp.StepService" })]
public class StepService : Service, ISensorEventListener, INotifyPropertyChanged
{
private SensorManager sManager;
private bool isRunning;
private long stepsToday = 0;
public bool WarningState
{
get;
set;
}
public long StepsToday
{
get { return stepsToday; }
set
{
if (stepsToday == value)
return;
stepsToday = value;
OnPropertyChanged("StepsToday");
Settings.CurrentDaySteps = value;
MessagingCenter.Send<object, long>(this, "Steps", Settings.CurrentDaySteps);
}
}
public const string PRIMARY_NOTIF_CHANNEL = "exampleChannel";
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
RegisterForService();
var warning = false;
if (intent != null)
warning = intent.GetBooleanExtra("warning", false);
Startup();
return StartCommandResult.Sticky;
}
private void RegisterForService()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channel = new NotificationChannel(PRIMARY_NOTIF_CHANNEL, "Pedometer Service Channel", NotificationImportance.Low)
{
Description = "Foreground Service Channel"
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
var notification = new Notification.Builder(this, PRIMARY_NOTIF_CHANNEL)
.SetContentTitle("Service")
.SetContentText("Running")
.SetSmallIcon(Resource.Drawable.ic_stat_name)
.SetContentIntent(BuildIntentToShowMainActivity())
.SetOngoing(true)
.Build();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
}
else
{
BuildIntentToShowMainActivity();
}
}
PendingIntent BuildIntentToShowMainActivity()
{
var alarmManager = ((AlarmManager)ApplicationContext.GetSystemService(AlarmService));
var intent2 = new Intent(this, typeof(StepService));
intent2.PutExtra("warning", WarningState);
var stepIntent = PendingIntent.GetService(ApplicationContext, 200, intent2, PendingIntentFlags.UpdateCurrent);
alarmManager.Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 1000 * 60 * 60, stepIntent);
return stepIntent;
}
public override void OnTaskRemoved(Intent rootIntent)
{
base.OnTaskRemoved(rootIntent);
UnregisterListeners();
var intent = new Intent(this, typeof(StepService));
intent.PutExtra("warning", WarningState);
((AlarmManager)GetSystemService(AlarmService)).Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 500,
PendingIntent.GetService(this, 201, intent, 0));
}
private void Startup(bool warning = false)
{
CrunchDates(true);
if (!isRunning)
{
RegisterListeners();
WarningState = warning;
}
isRunning = true;
}
public override void OnDestroy()
{
base.OnDestroy();
UnregisterListeners();
isRunning = false;
CrunchDates();
}
void RegisterListeners()
{
sManager = GetSystemService(SensorService) as SensorManager;
sManager.RegisterListener(this, sManager.GetDefaultSensor(SensorType.StepCounter), SensorDelay.Ui);
}
void UnregisterListeners()
{
if (!isRunning)
return;
try
{
var sensorManager = (SensorManager)GetSystemService(Context.SensorService);
sensorManager.UnregisterListener(this);
isRunning = false;
}
catch (Exception ex)
{
}
}
StepServiceBinder binder;
public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
binder = new StepServiceBinder(this);
return binder;
}
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
//do nothing here
}
public void AddSteps(long count)
{
if (lastSteps == 0)
{
lastSteps = count;
}
newSteps = count - lastSteps;
if (newSteps < 0)
newSteps = 1;
else if (newSteps > 100)
newSteps = 1;
lastSteps = count;
CrunchDates();
Settings.TotalSteps += newSteps;
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
long newSteps = 0;
long lastSteps = 0;
public void OnSensorChanged(SensorEvent e)
{
if (lastSteps < 0)
lastSteps = 0;
var count = (long)e.Values[0];
WarningState = false;
AddSteps(count);
}
private void CrunchDates(bool startup = false)
{
if (!Utils.IsSameDay)
{
var yesterday = Settings.CurrentDay;
var dayEntry = StepEntryManager.GetStepEntry(yesterday);
if (dayEntry == null || dayEntry.Date.DayOfYear != yesterday.DayOfYear)
{
dayEntry = new StepEntry();
}
dayEntry.Date = yesterday;
dayEntry.Steps = Settings.CurrentDaySteps;
Settings.CurrentDay = DateTime.Today;
Settings.CurrentDaySteps = 0;
Settings.StepsBeforeToday = Settings.TotalSteps;
StepsToday = 0;
try
{
StepEntryManager.SaveStepEntry(dayEntry);
}
catch (Exception ex)
{
Console.WriteLine("Error {0}", ex.Message);
}
}
else if (startup)
{
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
MainActivity.cs
[Activity(Label = "My Pedometer", Icon = "#mipmap/icon", Theme = "#style/MainTheme", LaunchMode = LaunchMode.SingleTask, MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public bool IsBound { get; set; }
private StepServiceBinder binder;
private bool registered;
private Handler handler;
private bool firstRun = true;
private StepServiceConnection serviceConnection;
public StepServiceBinder Binder
{
get { return binder; }
set
{
binder = value;
if (binder == null)
return;
HandlePropertyChanged(null, new System.ComponentModel.PropertyChangedEventArgs("StepsToday"));
if (registered)
binder.StepService.PropertyChanged -= HandlePropertyChanged;
binder.StepService.PropertyChanged += HandlePropertyChanged;
registered = true;
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
StartStepService();
handler = new Handler();
handler.PostDelayed(() => UpdateUI(), 500);
LoadApplication(new App());
}
private void StartStepService()
{
try
{
var service = new Intent(this, typeof(StepService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
StartForegroundService(service);
}
else
{
StartService(service);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception {0}.", ex.Message);
}
}
protected override void OnStop()
{
base.OnStop();
if (IsBound)
{
UnbindService(serviceConnection);
IsBound = false;
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if (IsBound)
{
UnbindService(serviceConnection);
IsBound = false;
}
}
protected override void OnStart()
{
base.OnStart();
if (!firstRun)
StartStepService();
if (IsBound)
return;
var serviceIntent = new Intent(this, typeof(StepService));
serviceConnection = new StepServiceConnection(this);
BindService(serviceIntent, serviceConnection, Bind.AutoCreate);
}
protected override void OnPause()
{
base.OnPause();
if (registered && binder != null)
{
binder.StepService.PropertyChanged -= HandlePropertyChanged;
registered = false;
}
}
protected override void OnResume()
{
base.OnResume();
if (!firstRun)
{
if (handler == null)
handler = new Handler();
handler.PostDelayed(() => UpdateUI(), 500);
}
firstRun = false;
if (!registered && binder != null)
{
binder.StepService.PropertyChanged += HandlePropertyChanged;
registered = true;
}
}
void HandlePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != "StepsToday")
return;
UpdateUI();
}
private void UpdateUI()
{
RunOnUiThread(() =>
{
long steps = 0;
var showWaring = false;
if (Binder == null)
{
if (Utils.IsSameDay)
steps = Settings.CurrentDaySteps;
}
else
{
steps = Binder.StepService.StepsToday;
showWaring = binder.StepService.WarningState;
}
Settings.CurrentDaySteps = steps;
});
}
}

Related

iOS web view renderer doesn't update its value

I have implemented WebViewRenderer it works well on Android but it doesn't work on iOS. It displays the value, but then user clicks next button and the value doesn't update. I have tried the the example on ms website, but that displayed no text, I don't have the values from URL. I have also tried several post here.
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace MyApp.iOS.Renderers
{
public class ExtendedWebViewRenderer : ViewRenderer<ExtendedWebView, WKWebView>
{
WKWebView _wkWebView;
static ExtendedWebView _xwebView = null;
protected override void OnElementChanged(ElementChangedEventArgs<ExtendedWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
WKWebViewConfiguration config = new WKWebViewConfiguration();
_wkWebView = new WKWebView(Frame, config);
_wkWebView.NavigationDelegate = new CustomWKNavigationDelegate(this);
SetNativeControl(_wkWebView);
}
if (e.NewElement != null)
{
HtmlWebViewSource source = (Xamarin.Forms.HtmlWebViewSource)Element.Source;
string html = source.Html;
_wkWebView.LoadHtmlString(html, baseUrl: null);
_wkWebView.ScrollView.ScrollEnabled = false;
_wkWebView.SizeToFit();
}
}
}
public class CustomWKNavigationDelegate : WKNavigationDelegate
{
ExtendedWebViewRenderer _webViewRenderer;
public CustomWKNavigationDelegate(ExtendedWebViewRenderer webViewRenderer)
{
_webViewRenderer = webViewRenderer;
}
public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
var wv = _webViewRenderer.Element as ExtendedWebView;
if (wv != null)
{
await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
}
}
}
}
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace MyApp.Droid.Renderers
{
public class ExtendedWebViewRenderer : WebViewRenderer
{
public static int _webViewHeight;
static ExtendedWebView _xwebView = null;
public WebView _webView;
bool isScroll;
[Obsolete]
public ExtendedWebViewRenderer(Context context) : base(context)
{
}
class ExtendedWebViewClient : WebViewClient
{
WebView _webView;
public async override void OnPageFinished(WebView view, string url)
{
try
{
_webView = view;
if (_xwebView != null)
{
view.Settings.JavaScriptEnabled = true;
await Task.Delay(100);
string result = await _xwebView.EvaluateJavaScriptAsync("(function(){return document.body.scrollHeight;})()");
_xwebView.HeightRequest = Convert.ToDouble(result);
}
base.OnPageFinished(view, url);
}
catch (Exception ex)
{
Console.WriteLine($"{ex.Message}");
}
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
return true;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
_xwebView = e.NewElement as ExtendedWebView;
_webView = Control;
if (e.OldElement == null)
{
_webView.SetWebViewClient(new ExtendedWebViewClient());
}
}
}
}
public class ExtendedWebView : WebView
{
public ExtendedWebView()
{
}
}
XAML
<controls:ExtendedWebView
VerticalOptions="FillAndExpand" Grid.RowSpan="2"
x:Name="enView"
Opacity="1"
Source="{Binding CZ, Mode=TwoWay}"/>
private static HtmlWebViewSource htmlSourceExplanation = new HtmlWebViewSource();
public HtmlWebViewSource Cz
{
get { return _cz; }
set
{
_cz = value;
NotifyPropertyChanged(nameof(Cz));
}
}
private void SetExplanationDetail(string text, string text2)
{
htmlSourceExplanation.Html = _style + "<div class=\"text\"><div>" + text + "</div><div>" + text2 + "</div></div>";
_cz = htmlSourceExplanation;
NotifyPropertyChanged("Cz");
}
I expect the value to change once to user cliks the button. `

How to uncheck a checkbox after returning to a page

i have a checkboxes that i am setting in View Model and i am collecting user decision on a list, however once i filter my items and then go bakc on the page the checkbox is still checked even thought the list is empty so if i press again button to show filtered items i get nothing. I am clearing my list but i am not sure how to get the checkboxes unchecked once i come back. I have Mode = two way
private bool _filterBeginnerItems = false;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
public bool FilterBeginnerItems
{
set
{
NotifyPropertyChanged();
_filterBeginnerItems = value;
if (_filterBeginnerItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 1);
}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
NotifyPropertyChanged();
_filterIntermediateItems = value;
if (_filterIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 2);
}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
NotifyPropertyChanged();
_filterUpperIntermediateItems = value;
if (_filterUpperIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 3);
}
}
get => _filterUpperIntermediateItems;
}
public FilterArticlesForPurchaseViewModel(INavigation navigation)
: base()
{
Task.Run(async () => await LoadAllDataForArticlesAndCategories()).Wait();
FilterItemsCommand = new Command(async () => navigation.PushAsync(new ArticlesForPurchaseFiltered()));
UserDecision.Clear();
//FilterAdvancedItems = false;
// FilterBeginnerItems = false;
}
Have tried to set their value to false but it doesnt help.
I write a demo about clear the CheckBox
Here is running gif.
Here is FilterArticlesForPurchaseViewModel.cs to achieve the INotifyPropertyChanged interface. I used a Command to clear these checkbox.
public class FilterArticlesForPurchaseViewModel: INotifyPropertyChanged
{
private bool _filterBeginnerItems = true;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
public bool FilterBeginnerItems
{
set
{
// NotifyPropertyChanged();
_filterBeginnerItems = value;
OnPropertyChanged("FilterBeginnerItems");
//if (_filterBeginnerItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 1);
//}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
// NotifyPropertyChanged();
_filterIntermediateItems = value;
OnPropertyChanged("FilterIntermediateItems");
//if (_filterIntermediateItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 2);
//}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
// NotifyPropertyChanged();
_filterUpperIntermediateItems = value;
OnPropertyChanged("FilterUpperIntermediateItems");
//if (_filterUpperIntermediateItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 3);
//}
}
get => _filterUpperIntermediateItems;
}
public ICommand ClearCommand { protected set; get; }
public FilterArticlesForPurchaseViewModel(INavigation navigation)
{
ClearCommand = new Command(async () =>
{
FilterBeginnerItems = false;
FilterIntermediateItems = false;
FilterUpperIntermediateItems = false;
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here is layout.xaml
<StackLayout>
<!-- Place new controls here -->
<CheckBox IsChecked="{Binding FilterBeginnerItems,Mode=TwoWay}"></CheckBox>
<CheckBox IsChecked="{Binding FilterIntermediateItems,Mode=TwoWay}"></CheckBox>
<CheckBox IsChecked="{Binding FilterUpperIntermediateItems,Mode=TwoWay}"></CheckBox>
<Button Text="clear" Command="{Binding ClearCommand}"></Button>
</StackLayout>
Here is background code.
public MainPage()
{
InitializeComponent();
this.BindingContext = new FilterArticlesForPurchaseViewModel(Navigation);
}
=================update===================
I make edit your viewmodel. Here is code, I achieve the remove data from the List<int> UserDecision
public class FilterViewModel : BaseViewModel
{
private bool _filterAllItems = true;
private bool _filterBeginnerItems = false;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
private static List<Article> _allArticlesForPurchase;
private static List<Category> _allCategories;
private static List<CategoryGroup> _allUserCategoryGroups;
public static List<int> UserDecisionResult { get; set; }
private static int _parentCategoryId;
public ICommand FilterItemsCommand { get; private set; }
public static List<int> UserDecision { get; set; } = new List<int>();
public bool FilterAllItems
{
set
{
_filterAllItems = value;
OnPropertyChanged();
if (FilterAllItems == false)
{
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
if (FilterAllItems == true)
{
FilterBeginnerItems = false;
FilterIntermediateItems = false;
FilterUpperIntermediateItems = false;
FilterAdvancedItems = false;
if (!UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Add(_parentCategoryId = -1);
}
if (UserDecision.Contains(_parentCategoryId=1))
{
UserDecision.Remove(_parentCategoryId = 1);
}
if (UserDecision.Contains(_parentCategoryId = 2))
{
UserDecision.Remove(_parentCategoryId = 2);
}
if (UserDecision.Contains(_parentCategoryId = 3))
{
UserDecision.Remove(_parentCategoryId = 3);
}
if (UserDecision.Contains(_parentCategoryId = 4))
{
UserDecision.Remove(_parentCategoryId = 4);
}
}
}
get => _filterAllItems;
}
public bool FilterBeginnerItems
{
set
{
_filterBeginnerItems = value;
OnPropertyChanged();
if (_filterBeginnerItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 1);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
_filterIntermediateItems = value;
OnPropertyChanged();
if (_filterIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 2);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
_filterUpperIntermediateItems = value;
OnPropertyChanged();
if (_filterUpperIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 3);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterUpperIntermediateItems;
}
public bool FilterAdvancedItems
{
set
{
_filterAdvancedItems = value;
OnPropertyChanged();
if (_filterAdvancedItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 4);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterAdvancedItems;
}
public FilterViewModel()
{
FilterItemsCommand = new Command(async () => await FilterItems());
FindAllArticlesForPurchase();
}
public ObservableCollection<Article> FilterArticlesForPurchase { get; } = new ObservableCollection<Article>();
private static void FindAllArticlesForPurchase()
{
foreach (var userDecision in UserDecision)
{
if (userDecision != -1)
{
if (UserDecision.Count > 1)
{
Console.WriteLine("more than one item");
}
else
{
Console.WriteLine("one item");
}
}
else
{
Console.WriteLine("not minus one");
}
}
}
private async Task FilterItems()
{
await Application.Current.MainPage.Navigation.PushAsync(new Filter());
}
}
If you want to binding same FilterViewModel in MainPage and Filter page.
You should use static FilterViewModel in the MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public static FilterViewModel filterViewModel ;
public MainPage()
{
InitializeComponent();
filterViewModel= new FilterViewModel();
BindingContext = filterViewModel;
}
}
In Filter page.You can binding same FilterViewModel in MainPage.xaml.cs
public partial class Filter: ContentPage
{
public Filter()
{
InitializeComponent();
BindingContext = MainPage.filterViewModel;
//If this FilterAllItems is empty, you want AllItems the checkbox to unselect, just set the value to false, the checkbox will update in the MainPage
MainPage.filterViewModel.FilterAllItems = false;
}
}

Xamarin Firebase and Syncfusion DataGrid. How do I listen for Firebase changes?

I'm having trouble with the coding to properly listen for Firebase add or update events. My attempt below has the data loading into the Syncfusion Datagrid, but there is a weird glitch where when I click the mouse on the Datagrid and pull-down, the first record in my 4 record set gets added to the bottom of the Datagrid, showing a 5th record... if I update an element in the Datagrid, the change is not reflected in Firebase. If I add or change a value in firebase, it does not update in Datagrid. Any help to steer me in the right direction to get this to work would be appreciated. Here's the code:
the VisualStudio 2019
CookPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Chart_sample"
xmlns:gauge="clr-namespace:Syncfusion.SfGauge.XForms;assembly=Syncfusion.SfGauge.XForms"
xmlns:Syncfusion="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms"
mc:Ignorable="d"
x:Class="Chart_sample.Views.CookPage">
<StackLayout>
<Syncfusion:SfDataGrid x:Name="sfGrid">
</Syncfusion:SfDataGrid>
</StackLayout>
</ContentPage>
CookPage.xaml.cs
using Chart_sample.Services;
using Syncfusion.SfDataGrid.XForms;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Chart_sample.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CookPage : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public CookPage()
{
InitializeComponent();
// for Syncfusion DataGrid
firebaseHelper.listenForEvents();
sfGrid.ItemsSource = ViewProgramModel._returnedEvents;
sfGrid.ColumnSizer = ColumnSizer.Star;
sfGrid.AllowEditing = true;
sfGrid.NavigationMode = NavigationMode.Cell;
sfGrid.SelectionMode = Syncfusion.SfDataGrid.XForms.SelectionMode.Single;
}
}
}
FirebaseHelper.cs
using Firebase.Database;
using Firebase.Database.Query;
using System;
using System.Linq;
namespace Chart_sample.Services
{
public class FirebaseHelper
{
internal ViewProgramModel ViewProgramModel { get; set; }
FirebaseClient firebase = new FirebaseClient("https://pelletpirate.firebaseio.com/");
private readonly string ChildProgram = "ControllerData/Pellet_Pirate_1/Program";
public static IDisposable returnedEvents;
public async void listenForEvents()
{
ViewProgramModel._returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
ViewProgramModel._returnedEvents.Add(programs.ElementAt(i).Object);
}
returnedEvents = firebase.Child(ChildProgram).OrderByKey().AsObservable<ViewProgramModel>()
.Subscribe(eventReceived =>
{
if (eventReceived.EventType == Firebase.Database.Streaming.FirebaseEventType.InsertOrUpdate)
{
var found = ViewProgramModel._returnedEvents.FirstOrDefault(i => i._KEY == eventReceived.Key);
if (found == null)
{
// not in observable collection, add it
ViewProgramModel._returnedEvents.Add(eventReceived.Object);
}
else
{
// event was updated
int tempIndex = ViewProgramModel._returnedEvents.IndexOf(found);
ViewProgramModel._returnedEvents[tempIndex] = eventReceived.Object;
}
}
});
}
}
}
ViewProgrammodel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Chart_sample
{
public class ViewProgramModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _KEy;
private string MOde;
private int TArget;
private string TRigger;
private int TRiggerVAlue;
public string _KEY
{
get { return _KEy; }
set
{
this._KEy = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("_KEY"));
}
}
public string MODE
{
get { return MOde; }
set
{
this.MOde = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MODE"));
}
}
public int TARGET
{
get { return TArget; }
set
{
this.TArget = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TARGET"));
}
}
public string TRIGGER
{
get { return TRigger; }
set
{
this.TRigger = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGER"));
}
}
public int TRIGGERVALUE
{
get { return TRiggerVAlue; }
set
{
this.TRiggerVAlue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGERVALUE"));
}
}
public static ObservableCollection<ViewProgramModel> _returnedEvents = new ObservableCollection<ViewProgramModel>();
}
}
I edit your demo, I achieve the update, Add, delete function.
Here is running GIF.
I change your ViewProgramModel like following code. Just move the _returnedEvents to the FirebaseHelper.cs
namespace Chart_sample
{
public class ViewProgramModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _KEy;
private string MOde;
private int TArget;
private string TRigger;
private int TRiggerVAlue;
public string _KEY
{
get { return _KEy; }
set
{
this._KEy = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("_KEY"));
}
}
public string MODE
{
get { return MOde; }
set
{
this.MOde = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MODE"));
}
}
public int TARGET
{
get { return TArget; }
set
{
this.TArget = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TARGET"));
}
}
public string TRIGGER
{
get { return TRigger; }
set
{
this.TRigger = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGER"));
}
}
public int TRIGGERVALUE
{
get { return TRiggerVAlue; }
set
{
this.TRiggerVAlue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGERVALUE"));
}
}
}
Here is FirebaseHelper.cs, Note: I achieve the update function just for the TARGET Column, I suggest your to add a Primary-key(Auto-increase) for every record in your database to achieve your search function.
public class FirebaseHelper
{
public ObservableCollection<ViewProgramModel> _returnedEvents { get; set; }
public FirebaseHelper()
{
_returnedEvents = new ObservableCollection<ViewProgramModel>();
}
// internal ViewProgramModel MyViewProgramModel { get; set; }
FirebaseClient firebase = new FirebaseClient("https://xxxxxxxxxx.firebaseio.com/");
private readonly string ChildProgram = "ControllerData/xxxxxx_Pirate_1/Program";
public static IDisposable returnedEvents;
public async Task AddViewProgramModel()
{
//new ViewProgramModel() { MODE="test", TARGET=122, TRIGGER="122", TRIGGERVALUE=333, }
await firebase
.Child(ChildProgram)
.PostAsync( new ViewProgramModel() { MODE = "test", TARGET = 122, TRIGGER = "122", TRIGGERVALUE = 333, });
GetAllData();
}
public async Task UpdateViewProgramModel(ViewProgramModel viewProgramModel , string oldValue)
{
var toUpdatePerson = (await firebase
.Child(ChildProgram)
.OnceAsync<ViewProgramModel>()).FirstOrDefault(a => a.Object.TARGET == Convert.ToInt32( oldValue));
await firebase
.Child(ChildProgram)
.Child(toUpdatePerson.Key)
.PutAsync(viewProgramModel);
GetAllData();
}
public async Task DeleteViewProgramModel(string mode)
{
var toDeletePerson = (await firebase
.Child(ChildProgram)
.OnceAsync<ViewProgramModel>()).FirstOrDefault(a => a.Object.MODE == mode);
await firebase.Child(ChildProgram).Child(toDeletePerson.Key).DeleteAsync();
GetAllData();
}
public async void GetAllData()
{
_returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
_returnedEvents.Add(programs.ElementAt(i).Object);
}
}
public async void listenForEvents()
{
_returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
_returnedEvents.Add(programs.ElementAt(i).Object);
}
//returnedEvents = firebase.Child(ChildProgram).OrderByKey().AsObservable<ViewProgramModel>()
// .Subscribe(eventReceived =>
// {
// if (eventReceived.EventType == Firebase.Database.Streaming.FirebaseEventType.InsertOrUpdate)
// {
// var found = _returnedEvents.FirstOrDefault(i => i._KEY == eventReceived.Key);
// if (found == null)
// {
// // not in observable collection, add it
// _returnedEvents.Add(eventReceived.Object);
// }
// else
// {
// // event was updated
// int tempIndex = _returnedEvents.IndexOf(found);
// _returnedEvents[tempIndex] = eventReceived.Object;
// }
// }
//});
}
}
}
Here is CookPage.xaml
<StackLayout>
<Button Text="add" Clicked="Button_Clicked"></Button>
<Button Text="delete" Clicked="Button_Clicked_1"></Button>
<Syncfusion:SfDataGrid x:Name="sfGrid" ItemsSource="{Binding _returnedEvents, Mode=TwoWay} " >
</Syncfusion:SfDataGrid>
</StackLayout>
Here is code about CookPage.cs.
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CookPage : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public CookPage()
{
InitializeComponent();
// for Syncfusion DataGrid
firebaseHelper.listenForEvents();
//sfGrid.ItemsSource = ViewProgramModel._returnedEvents;
BindingContext= firebaseHelper;
sfGrid.ColumnSizer = ColumnSizer.Star;
sfGrid.AllowEditing = true;
sfGrid.NavigationMode = NavigationMode.Cell;
sfGrid.AllowLoadMore = true;
sfGrid.AutoGenerateColumns = true;
//sfGrid.AutoGenerateColumnsMode= AutoGenerateColumnsMode.
sfGrid.SelectionMode = Syncfusion.SfDataGrid.XForms.SelectionMode.Single;
sfGrid.AllowPullToRefresh = true;
sfGrid.CurrentCellEndEdit += SfGrid_CurrentCellEndEdit; ;
}
private async void SfGrid_CurrentCellEndEdit(object sender, GridCurrentCellEndEditEventArgs e)
{
//throw new System.NotImplementedException();
var selectObj = sender as SfDataGrid;
RowColumnIndex index = e.RowColumnIndex;
int selectColumnIndex = index.ColumnIndex; //2
int selectRowIndex = index.RowIndex; //3
var ob=firebaseHelper._returnedEvents;
ViewProgramModel selectObject =ob[selectRowIndex-1];
var newVale = e.NewValue.ToString();
var oldeValue = e.OldValue.ToString();
//Here just judge TARGET Column, you should judge all Columns
if (selectColumnIndex == 2)
{
selectObject.TARGET = Convert.ToInt32(newVale);
}
//If you want to achieve the all Grid change function, you should judge the selectRowIndex for every change
//if (selectRowIndex==1)
//{
// selectObject.MODE = newVale;
//}else if (selectRowIndex==2)
//{
// selectObject.TARGET = Convert.ToInt32( newVale);
//}else if (selectRowIndex == 3)
//{
// selectObject.TRIGGER = newVale;
//}else if (selectRowIndex == 4)
//{
// selectObject.TRIGGERVALUE = Convert.ToInt32(newVale);
//}
await firebaseHelper.UpdateViewProgramModel(selectObject, oldeValue);
}
private async void Button_Clicked(object sender, System.EventArgs e)
{
await firebaseHelper.AddViewProgramModel();
}
private async void Button_Clicked_1(object sender, System.EventArgs e)
{
await firebaseHelper.DeleteViewProgramModel("test");
}
}

After phone restart 'unfortunately app has stopped' error

I get "unfortunately app has stopped" error after phone restart. My Phone is Oreo 8 but another phone with Nougat 7.1.1 also having the same error after phone restart. I use James Montemagnos' MyStepCounter bound services codes from GitHub with some changes in VS 2017 (Xamarin Cross-Platform App). The app is working fine if once started after phone restart with this error, else it is not counting steps and not working on the background. If I check the app in Phone Settings-General-Battery-Power saving exclusions then it works with no problems after phone restart and it is counting steps on the background without starting the app on Oreo phone. But there are no settings for battery power saving exclusions on the other phone
BootReceiver.cs
[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new string[] { Intent.ActionBootCompleted, Intent.ActionLockedBootCompleted, "android.intent.action.QUICKBOOT_POWERON", "com.htc.intent.action.QUICKBOOT_POWERON" })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var stepServiceIntent = new Intent(context, typeof(StepService));
context.StartService(stepServiceIntent);
}
}
StepServiceBinder.cs
public class StepServiceBinder : Binder
{
StepService stepService;
public StepServiceBinder(StepService service)
{
this.stepService = service;
}
public StepService StepService
{
get { return stepService; }
}
}
StepServiceConnection.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
StepService.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
StepService.cs
[Service(Enabled = true)]
[IntentFilter(new String[] { "com.PedometerApp.StepService" })]
public class StepService : Service, ISensorEventListener, INotifyPropertyChanged
{
private SensorManager sManager;
private bool isRunning;
private long stepsToday = 0;
public bool WarningState
{
get;
set;
}
public long StepsToday
{
get { return stepsToday; }
set
{
if (stepsToday == value)
return;
stepsToday = value;
OnPropertyChanged("StepsToday");
Settings.CurrentDaySteps = value;
MessagingCenter.Send<object, long>(this, "Steps", Settings.CurrentDaySteps);
}
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
var alarmManager = ((AlarmManager)ApplicationContext.GetSystemService(AlarmService));
var intent2 = new Intent(this, typeof(StepService));
intent2.PutExtra("warning", WarningState);
var stepIntent = PendingIntent.GetService(ApplicationContext, 200, intent2, PendingIntentFlags.UpdateCurrent);
alarmManager.Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 1000 * 60 * 60, stepIntent);
var warning = false;
if (intent != null)
warning = intent.GetBooleanExtra("warning", false);
Startup();
return StartCommandResult.Sticky;
}
public override void OnTaskRemoved(Intent rootIntent)
{
base.OnTaskRemoved(rootIntent);
UnregisterListeners();
var intent = new Intent(this, typeof(StepService));
intent.PutExtra("warning", WarningState);
((AlarmManager)GetSystemService(AlarmService)).Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 500,
PendingIntent.GetService(this, 201, intent, 0));
}
private void Startup(bool warning = false)
{
CrunchDates(true);
if (!isRunning)
{
RegisterListeners();
WarningState = warning;
}
isRunning = true;
}
public override void OnDestroy()
{
base.OnDestroy();
UnregisterListeners();
isRunning = false;
CrunchDates();
}
void RegisterListeners()
{
sManager = GetSystemService(SensorService) as SensorManager;
sManager.RegisterListener(this, sManager.GetDefaultSensor(SensorType.StepCounter), SensorDelay.Ui);
}
void UnregisterListeners()
{
if (!isRunning)
return;
try
{
var sensorManager = (SensorManager)GetSystemService(Context.SensorService);
sensorManager.UnregisterListener(this);
isRunning = false;
}
catch (Exception ex)
{
}
}
StepServiceBinder binder;
public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
binder = new StepServiceBinder(this);
return binder;
}
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
//do nothing here
}
public void AddSteps(long count)
{
if (lastSteps == 0)
{
lastSteps = count;
}
newSteps = count - lastSteps;
if (newSteps < 0)
newSteps = 1;
else if (newSteps > 100)
newSteps = 1;
lastSteps = count;
CrunchDates();
Settings.TotalSteps += newSteps;
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
long newSteps = 0;
long lastSteps = 0;
public void OnSensorChanged(SensorEvent e)
{
if (lastSteps < 0)
lastSteps = 0;
var count = (long)e.Values[0];
WarningState = false;
AddSteps(count);
}
private void CrunchDates(bool startup = false)
{
if (!Utils.IsSameDay)
{
var yesterday = Settings.CurrentDay;
var dayEntry = StepEntryManager.GetStepEntry(yesterday);
if (dayEntry == null || dayEntry.Date.DayOfYear != yesterday.DayOfYear)
{
dayEntry = new StepEntry();
}
dayEntry.Date = yesterday;
dayEntry.Steps = Settings.CurrentDaySteps;
Settings.CurrentDay = DateTime.Today;
Settings.CurrentDaySteps = 0;
Settings.StepsBeforeToday = Settings.TotalSteps;
StepsToday = 0;
try
{
StepEntryManager.SaveStepEntry(dayEntry);
}
catch (Exception ex)
{
Console.WriteLine("Error {0}", ex.Message);
}
}
else if (startup)
{
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}

How can i integrate QR-reader in Weex App?

React.Native has plugins like react-native-qrcode-scanner.
How can I do that on Weex?
Here comes a solution named EMAS. like weex-market, there are a lot of components and modules. One of these is the scan component which meets your requirement.
But the portal website is only in the Chinese language now.
Here is an android demo using ZXing to do qrcode. Copy this and register as a scan component. Have a look at this Demo.
public class WXQRCodeScannerComponent extends WXComponent<ZXingScannerView> implements ZXingScannerView.ResultHandler{
private static final String VF_WIDTH = "vfWidth";
private static final String VF_HEIGHT = "vfHeight";
private static final String VF_TOP_MARGIN = "vfTopMargin";
private static final String AUTO_STOP = "autoStop";
private static final String ON_SCAN = "scan";
private static final String TAG = "scan";
private boolean isAutoStop = false;
private boolean hasScanned = false;
private Handler mHandler = new Handler(Looper.getMainLooper());
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0x1001;
private OnRequestPermissionCallback mPermissionCallback = new OnRequestPermissionCallback() {
#Override
public void onPermissionGranted() {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#Override
public void onPermissionDenied() {
// nope
}
};
public WXQRCodeScannerComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
super(instance, dom, parent);
}
public WXQRCodeScannerComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, int type) {
super(instance, dom, parent, type);
}
#Override
protected ZXingScannerView initComponentHostView(#NonNull Context context) {
requestPermissionIfNeeded();
ZXingScannerView qrCodeView = new ZXingScannerView(context);
qrCodeView.setSquareViewFinder(true);
qrCodeView.setResultHandler(this); // Register ourselves as a handler for scan results.
return qrCodeView;
}
private void requestPermissionIfNeeded() {
Context c = getContext();
if(c != null && c instanceof Activity) {
if(ContextCompat.checkSelfPermission(c, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) c, Manifest.permission.CAMERA)) {
Toast.makeText(c, "请授予相机权限以用于扫码", Toast.LENGTH_LONG).show();
}
LocalBroadcastManager.getInstance(c)
.registerReceiver(new InnerReceiver(mPermissionCallback), new IntentFilter(WXModule.ACTION_REQUEST_PERMISSIONS_RESULT));
ActivityCompat.requestPermissions((Activity) c,
new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
} else {
//Nope
}
}
}
static class InnerReceiver extends BroadcastReceiver{
private OnRequestPermissionCallback mCallback;
InnerReceiver(OnRequestPermissionCallback callback) {
this.mCallback = callback;
}
#Override
public void onReceive(Context context, Intent intent) {
int code = intent.getIntExtra(WXModule.REQUEST_CODE, 0);
int[] grantResults = intent.getIntArrayExtra(WXModule.GRANT_RESULTS);
String[] permissions = intent.getStringArrayExtra(WXModule.PERMISSIONS);
if(code == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限申请成功
if(mCallback != null) {
mCallback.onPermissionGranted();
}
} else {
Toast.makeText(context, "相机权限申请失败!将无法使用扫码功能!", Toast.LENGTH_SHORT).show();
if(mCallback != null) {
mCallback.onPermissionDenied();
}
}
}
LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
}
}
interface OnRequestPermissionCallback {
void onPermissionGranted();
void onPermissionDenied();
}
#Override
protected boolean setProperty(String key, Object param) {
switch (key) {
case VF_WIDTH:
Float width = WXUtils.getFloat(param,null);
if(width != null) {
setVfWidth(width);
}
return true;
case VF_HEIGHT:
Float height = WXUtils.getFloat(param,null);
if(height != null) {
setVfHeight(height);
}
return true;
case VF_TOP_MARGIN:
Float topMargin = WXUtils.getFloat(param,null);
if(topMargin != null) {
setVfTopMargin(topMargin);
}
return true;
case AUTO_STOP:
Boolean autoStop = WXUtils.getBoolean(param, false);
if(autoStop != null) {
setAutoStop(autoStop);
}
return true;
}
return super.setProperty(key, param);
}
#Override
protected void onHostViewInitialized(ZXingScannerView host) {
super.onHostViewInitialized(host);
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#WXComponentProp(name = VF_WIDTH)
public void setVfWidth(float width) {
float finalWidth = WXViewUtils.getRealSubPxByWidth(width,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setRectWidth((int) finalWidth);
// }
}
}
#WXComponentProp(name = VF_HEIGHT)
public void setVfHeight(float height) {
float finalHeight = WXViewUtils.getRealSubPxByWidth(height,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setRectHeight((int) finalHeight);
// }
}
}
#WXComponentProp(name = VF_TOP_MARGIN)
public void setVfTopMargin(float topMargin) {
float finalTopMargin = WXViewUtils.getRealSubPxByWidth(topMargin,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setTopOffset((int) finalTopMargin);
// }
}
}
#WXComponentProp(name = AUTO_STOP)
public void setAutoStop(boolean autoStop) {
this.isAutoStop = autoStop;
}
#Override
public void onActivityResume() {
super.onActivityResume();
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#Override
public void onActivityPause() {
super.onActivityPause();
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.stopCamera(); // Stop camera on pause
}
}
#Override
public void onActivityDestroy() {
if(mHandler != null) {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.stopCamera();
}
mHandler.removeCallbacksAndMessages(null);
}
}
#Override
public void handleResult(Result result) {
if(isAutoStop && hasScanned) {
resumeCameraPreviewDelayed();
return;
}
fireEventByResult(result);
resumeCameraPreviewDelayed();
hasScanned = true;
}
private void fireEventByResult(Result result) {
if(result == null || TextUtils.isEmpty(result.getText())) {
Map<String,Object> callback = new HashMap<>(4);
callback.put("result","failed");
fireEvent(ON_SCAN,callback);
if(WXEnvironment.isApkDebugable()) {
WXLogUtils.d(TAG, "scan failed");
}
} else {
Map<String,String> data = new HashMap<>(4);
data.put("timestamp", System.currentTimeMillis()+"");
data.put("code", result.getText());
Map<String,Object> callback = new HashMap<>(4);
callback.put("result","success");
callback.put("data", data);
fireEvent(ON_SCAN,callback);
if(WXEnvironment.isApkDebugable()) {
WXLogUtils.d(TAG, "scan success: " + result.getText());
}
}
}
private void resumeCameraPreviewDelayed() {
if(mHandler == null) {
return;
}
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.resumeCameraPreview(WXQRCodeScannerComponent.this);
}
}
}, 1000);
}
}

Resources