Android Widget works in debug but not in release - c#

I coded an Android widget which works perfectly fine during debugging, but after the release, it seems like the AppWidget.cs-Program doesn't get called because I can only see what I created in the Layout.
This program is made for activating or deactivating a lamp which reacts when the program calls the site, for example: "http://192.168.0.52/ein" activates the lamp, "http://192.168.0.52/aus" deactivates the lamp, and "http://192.168.0.52/state" gets the current status ("on" or "off") of the lamp. Thank you in advance!
AppWidget.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Android.App;
using Android.Appwidget;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace OrigWidget
{
[BroadcastReceiver(Label = "IoT-Lampe")]
[IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })]
[MetaData("android.appwidget.provider", Resource = "#xml/appwidgetprovider")]
public class AppWidget : AppWidgetProvider
{
WebClient client;
RemoteViews widgetView;
AppWidgetManager awm;
Context c;
int[] aWid;
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
awm = appWidgetManager;
c = context;
aWid = appWidgetIds;
System.Threading.Timer t = new System.Threading.Timer(upd, null, 0, 5000);
}
private void upd(Object o)
{
var me = new ComponentName(c, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
awm.UpdateAppWidget(me, BuildRemoteViews(c, aWid));
}
private RemoteViews BuildRemoteViews(Context context, int[] appWidgetIds)
{
widgetView = new RemoteViews(context.PackageName, Resource.Layout.Widget);
SetTextViewText(widgetView);
RegisterClicks(context, appWidgetIds, widgetView);
return widgetView;
}
private void SetTextViewText(RemoteViews widgetView)
{
Check();
}
public void Check()
{
client = new WebClient();
String htmlText = client.DownloadString("http://192.168.0.52/state");
client.Dispose();
if (htmlText == "on")
{
widgetView.SetInt(Resource.Id.an, "setBackgroundColor", Color.LimeGreen);
widgetView.SetInt(Resource.Id.aus, "setBackgroundColor", Color.Rgb(71, 66, 65));
}
else if (htmlText == "off")
{
widgetView.SetInt(Resource.Id.an, "setBackgroundColor", Color.Rgb(71, 66, 65));
widgetView.SetInt(Resource.Id.aus, "setBackgroundColor", Color.Red);
}
}
private static string AusClick = "AusClickTag";
private static string AnClick = "AnClickTag";
public override void OnReceive(Context context, Intent intent)
{
base.OnReceive(context, intent);
if (AnClick.Equals(intent.Action))
{
try
{
client = new WebClient();
String unnecessary = client.DownloadString("http://192.168.0.52/ein");
String nec = client.DownloadString("http://192.168.0.52/state");
client.Dispose();
}
catch (Exception) { }
}
if (AusClick.Equals(intent.Action))
{
try
{
client = new WebClient();
String unnecessary = client.DownloadString("http://192.168.0.52/aus");
client.Dispose();
}
catch (Exception) { }
}
}
private void RegisterClicks(Context context, int[] appWidgetIds, RemoteViews widgetView)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(AppWidgetManager.ActionAppwidgetUpdate);
intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, appWidgetIds);
widgetView.SetOnClickPendingIntent(Resource.Id.an, GetPendingSelfIntent(context, AnClick));
widgetView.SetOnClickPendingIntent(Resource.Id.aus, GetPendingSelfIntent(context, AusClick));
}
private PendingIntent GetPendingSelfIntent(Context context, string action)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(action);
return PendingIntent.GetBroadcast(context, 0, intent, 0);
}
}
}

Related

MAUI-Android: How to keep Google Speech Recognizer from timeout

I am trying out Microsoft .NET MAUI that currently in Preview stage.
I try to make a small Android app that will use Google voice recognizer service as a way to let user navigate the app. Just a small demo to see what can I do with it. This is also my first time to actually write a Xamarin/MAUI project, so I am not really sure what I can actually do wit the platform.
The problem is that I would like to have this Google service to always on (without timeout) or auto-close then re-open when timeout. In short, I want user to never actually have to deal with this screen:
My intention is that the will be a background thread to keep asking user to say the command, only stop when user do, and the service will always ready to receive the speech.
However, I am unable to keep the above service always on or auto-close=>reopen when timeout.
I am search around and it seems that I cannot change the timeout of the service, so the only way is trying to auto-close=>reopen the service, but I don't know how to.
The below is my code, could you guy give me some direction with it?
1. The login page: only have username and password field, use will be asked to say the username. If it is exist, then asked to say password.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiDemo.LoginPage"
BackgroundColor="White">
<ContentPage.Content>
<StackLayout Margin="30" VerticalOptions="StartAndExpand">
<Label
x:Name="lblTitle"
HorizontalTextAlignment="Center"
FontSize="Large"
FontAttributes="Bold"
/>
<Label/>
<Button
x:Name="btnSpeak"
Text="Start"
Clicked="btnSpeak_Clicked"
FontAttributes="Bold"
BackgroundColor="DarkGreen"
/>
<Label/>
<Label
x:Name="lblUsername"
Text="Username"
FontAttributes="Bold"
/>
<Entry
x:Name="txtUsername"
TextColor="Black"
FontSize="18"
VerticalOptions="StartAndExpand"
HorizontalOptions="Fill"
IsReadOnly="True"
/>
<Label/>
<Label
x:Name="lblPassword"
Text="Password"
FontAttributes="Bold"
/>
<Entry
x:Name="txtPassword"
IsPassword="True"
TextColor="Black"
FontSize="18"
VerticalOptions="StartAndExpand"
HorizontalOptions="Fill"
IsReadOnly="True"
/>
<Label/>
<Label
x:Name="lblDisplayname"
Text="Name"
FontAttributes="Bold"
/>
<Label
x:Name="txtDisplayname"
/>
<Label/>
<Label
x:Name="lblMessage"
Text=""/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo
{
public partial class LoginPage : ContentPage
{
private string _field = string.Empty;
private int _waitTime = 2000;
public List<Language> Languages { get; }
private SpeechToTextImplementation _speechRecongnitionInstance;
private struct VoiceMode
{
int Username = 1;
int Password = 2;
}
public LoginPage()
{
InitializeComponent();
this.lblTitle.Text = "Login" + App.Status;
CheckMicrophone();
CommonData.CurrentField = string.Empty;
try
{
_speechRecongnitionInstance = new SpeechToTextImplementation();
_speechRecongnitionInstance.Language = DefaultData.SettingLanguage;
}
catch (Exception ex)
{
DisplayAlert("Error", ex.Message, "OK");
}
MessagingCenter.Subscribe<ISpeechToText, string>(this, "STT", (sender, args) =>
{
ReceivedUsernameAsync(args);
});
MessagingCenter.Subscribe<ISpeechToText>(this, "Final", (sender) =>
{
btnSpeak.IsEnabled = true;
});
MessagingCenter.Subscribe<IMessageSender, string>(this, "STT", (sender, args) =>
{
SpeechToTextRecievedAsync(args);
});
isReceiveUsername = false;
isReceivePassword = false;
RequestUsername();
}
protected override void OnDisappearing()
{
CommonData.CurrentField = string.Empty;
base.OnDisappearing();
}
private async void btnSpeak_Clicked(Object sender, EventArgs e)
{
isReceiveUsername = false;
isReceivePassword = false;
await RequestUsername();
}
private async void SpeechToTextRecievedAsync(string args)
{
switch (_field)
{
case "Username":
await this.ReceivedUsernameAsync(args);
break;
case "Password":
await this.ReceivedPasswordAsync(args);
break;
}
}
bool isReceiveUsername = false;
bool isReceivePassword = false;
private async Task ReceivedUsernameAsync(string args)
{
txtUsername.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtUsername.Text))
{
isReceiveUsername = false;
}
else
{
isReceiveUsername = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()));
if (checkUser.Any())
{
await RequestPassword();
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongUsername);
lblMessage.Text = message;
isReceiveUsername = false;
await RequestUsername(message);
}
}
}
private async Task ReceivedPasswordAsync(string args)
{
txtPassword.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtPassword.Text))
{
isReceivePassword = false;
}
else
{
isReceivePassword = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()) && x.Password.Equals(txtPassword.Text));
if (checkUser.Any())
{
_field = "";
lblDisplayname.Text = checkUser.FirstOrDefault().Displayname;
string msg = CommonData.GetMessage(MessageCode.LoginSuccess);
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
msg
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
await Navigation.PushAsync(new MainPage());
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongPassword);
lblMessage.Text = message;
isReceivePassword = false;
await RequestPassword(message);
}
}
}
private async Task RepeatVoiceUsername(string message)
{
do
{
//_speechRecongnitionInstance.StopSpeechToText();
//_speechRecongnitionInstance.StartSpeechToText();
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceiveUsername);
}
private async Task RepeatVoicePassword(string message)
{
do
{
//_speechRecongnitionInstance.StopSpeechToText();
//_speechRecongnitionInstance.StartSpeechToText();
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceivePassword);
}
private bool CheckMicrophone()
{
string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec != "android.hardware.microphone")
{
// no microphone, no recording. Disable the button and output an alert
DisplayAlert("Error", CommonData.GetMessage(MessageCode.SettingSaveSuccess), "OK");
btnSpeak.IsEnabled = false;
return false;
}
return true;
}
private async Task RequestUsername(string message = "")
{
_field = "Username";
isReceiveUsername = false;
txtUsername.Text = string.Empty;
lblDisplayname.Text = string.Empty;
txtUsername.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputUsername) : message);
Task.Run(() => RepeatVoiceUsername(message));
_speechRecongnitionInstance.StartSpeechToText(_field);
}
private async Task RequestPassword(string message = "")
{
_field = "Password";
isReceivePassword = false;
txtPassword.Text = string.Empty;
lblDisplayname.Text = string.Empty;
txtPassword.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputPassword) : message);
Task.Run(() => RepeatVoicePassword(message));
_speechRecongnitionInstance.StartSpeechToText(_field);
}
}
}
2. The Speech Recognizer class:
using Android.App;
using Android.Content;
using Android.Speech;
using Java.Util;
using Plugin.CurrentActivity;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo.Speech
{
public class SpeechToTextImplementation
{
public static AutoResetEvent autoEvent = new AutoResetEvent(false);
private readonly int VOICE = 10;
private Activity _activity;
private float _timeOut = 3;
private string _text;
public SpeechToTextImplementation()
{
_activity = CrossCurrentActivity.Current.Activity;
}
public SpeechToTextImplementation(string text)
{
_text = text;
_activity = CrossCurrentActivity.Current.Activity;
}
public string Language;
public void StartSpeechToText()
{
StartRecordingAndRecognizing();
}
public void StartSpeechToText(string text)
{
_text = text;
StartRecordingAndRecognizing();
}
private async void StartRecordingAndRecognizing()
{
string rec = global::Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec == "android.hardware.microphone")
{
try
{
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
Intent voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, _text);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
_activity.StartActivityForResult(voiceIntent, VOICE);
await Task.Run(() => { autoEvent.WaitOne(new TimeSpan(0, 2, 0)); });
}
catch (ActivityNotFoundException ex)
{
String appPackageName = "com.google.android.googlequicksearchbox";
try
{
Intent intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse("market://details?id=" + appPackageName));
_activity.StartActivityForResult(intent, VOICE);
}
catch (ActivityNotFoundException e)
{
Intent intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse("https://play.google.com/store/apps/details?id=" + appPackageName));
_activity.StartActivityForResult(intent, VOICE);
}
}
}
else
{
throw new Exception("No mic found");
}
}
public void StopSpeechToText()
{
// Do something here to close the service
}
}
}
3. MainActivity:
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Speech;
using MauiDemo.Common;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
namespace MauiDemo
{
[Activity(Label = "Maui Demo", Theme = "#style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity, IMessageSender
{
private readonly int VOICE = 10;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == VOICE)
{
if (resultCode == Result.Ok)
{
var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
if (matches.Count != 0)
{
string textInput = matches[0];
MessagingCenter.Send<IMessageSender, string>(this, "STT", textInput);
}
else
{
MessagingCenter.Send<IMessageSender, string>(this, "STT", "");
}
}
}
base.OnActivityResult(requestCode, resultCode, data);
}
}
}
4. MainApplication
using Android.App;
using Android.OS;
using Android.Runtime;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using Plugin.CurrentActivity;
using System;
namespace MauiDemo
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
public override void OnCreate()
{
base.OnCreate();
CrossCurrentActivity.Current.Init(this);
}
public override void OnTerminate()
{
base.OnTerminate();
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
}
After struggle for a few days without any success, I found a new way to do this thing by using SpeechRecognizer class, instead of using a Google service. With this, I am able to have a better control on the process.
To use SpeechRecognizer, I copied the code in "Create platform microphone services" for permission from this Microsoft page: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/azure-cognitive-services/speech-recognition
I have update my code as below:
Login page: currently is named Prototype2.
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo.View
{
public partial class Prototype2 : ContentPage
{
private string _field = string.Empty;
private int _waitTime = 2000;
public List<Language> Languages { get; }
private SpeechToTextImplementation2 _speechRecognizer;
//private BackgroundWorker worker = new BackgroundWorker();
private struct VoiceMode
{
int Username = 1;
int Password = 2;
}
public Prototype2()
{
InitializeComponent();
this.lblTitle.Text = "Prototype2" + App.Status;
CheckMicrophone();
CommonData.CurrentField = string.Empty;
try
{
_speechRecognizer = new SpeechToTextImplementation2();
_speechRecognizer.Language = DefaultData.SettingLanguage;
}
catch (Exception ex)
{
DisplayAlert("Error", ex.Message, "OK");
}
MessagingCenter.Subscribe<ISpeechToText, string>(this, "STT", (sender, args) =>
{
ReceivedUsernameAsync(args);
});
MessagingCenter.Subscribe<ISpeechToText>(this, "Final", (sender) =>
{
btnSpeak.IsEnabled = true;
});
MessagingCenter.Subscribe<IMessageSender, string>(this, "STT", (sender, args) =>
{
SpeechToTextRecievedAsync(args);
});
isReceiveUsername = false;
isReceivePassword = false;
RequestUsername(true);
}
protected override void OnDisappearing()
{
CommonData.CurrentField = string.Empty;
base.OnDisappearing();
}
private async void btnSpeak_Clicked(Object sender, EventArgs e)
{
isReceiveUsername = false;
isReceivePassword = false;
await RequestUsername(true);
}
private async void SpeechToTextRecievedAsync(string args)
{
switch (_field)
{
case "Username":
await this.ReceivedUsernameAsync(args);
break;
case "Password":
await this.ReceivedPasswordAsync(args);
break;
}
}
bool isReceiveUsername = false;
bool isReceivePassword = false;
private async Task ReceivedUsernameAsync(string args)
{
txtUsername.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtUsername.Text))
{
isReceiveUsername = false;
}
else
{
isReceiveUsername = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()));
if (checkUser.Any())
{
await RequestPassword(true);
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongUsername);
lblMessage.Text = message;
isReceiveUsername = false;
await RequestUsername(false, message);
}
}
}
private async Task ReceivedPasswordAsync(string args)
{
txtPassword.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtPassword.Text))
{
isReceivePassword = false;
}
else
{
isReceivePassword = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()) && x.Password.Equals(txtPassword.Text));
if (checkUser.Any())
{
_field = "";
lblDisplayname.Text = checkUser.FirstOrDefault().Displayname;
string msg = CommonData.GetMessage(MessageCode.LoginSuccess);
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
msg
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
await Navigation.PushAsync(new MainPage());
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongPassword);
lblMessage.Text = message;
isReceivePassword = false;
await RequestPassword(false, message);
}
}
}
private async Task RepeatVoiceUsername(string message)
{
do
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceiveUsername);
}
private async Task RepeatVoicePassword(string message)
{
do
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceivePassword);
}
private bool CheckMicrophone()
{
string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec != "android.hardware.microphone")
{
// no microphone, no recording. Disable the button and output an alert
DisplayAlert("Error", CommonData.GetMessage(MessageCode.SettingSaveSuccess), "OK");
btnSpeak.IsEnabled = false;
return false;
}
return true;
}
private async Task RequestUsername(bool isRepeat, string message = "")
{
_field = "Username";
isReceiveUsername = false;
//txtUsername.Text = string.Empty;
//lblDisplayname.Text = string.Empty;
txtUsername.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputUsername) : message);
if (isRepeat)
{
Task.Run(() => RepeatVoiceUsername(message));
}
else
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
}
_speechRecognizer.StartListening();
}
private async Task RequestPassword(bool isRepeat, string message = "")
{
_field = "Password";
isReceivePassword = false;
//txtPassword.Text = string.Empty;
//lblDisplayname.Text = string.Empty;
txtPassword.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputPassword) : message);
if (isRepeat)
{
Task.Run(() => RepeatVoicePassword(message));
}
else
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
}
_speechRecognizer.StartListening();
}
}
}
New Microphone Service to handle the permission
using Android.App;
using Android.Content.PM;
using Android.OS;
using AndroidX.Core.App;
using Google.Android.Material.Snackbar;
using System.Threading.Tasks;
namespace MauiDemo.Speech
{
public class MicrophoneService
{
public const int RecordAudioPermissionCode = 1;
private TaskCompletionSource<bool> tcsPermissions;
string[] permissions = new string[] { Manifest.Permission.RecordAudio };
public MicrophoneService()
{
tcsPermissions = new TaskCompletionSource<bool>();
}
public Task<bool> GetPermissionAsync()
{
if ((int)Build.VERSION.SdkInt < 23)
{
tcsPermissions.TrySetResult(true);
}
else
{
var currentActivity = MainActivity.Instance;
if (ActivityCompat.CheckSelfPermission(currentActivity, Manifest.Permission.RecordAudio) != (int)Permission.Granted)
{
RequestMicPermissions();
}
else
{
tcsPermissions.TrySetResult(true);
}
}
return tcsPermissions.Task;
}
public void OnRequestPermissionResult(bool isGranted)
{
tcsPermissions.TrySetResult(isGranted);
}
void RequestMicPermissions()
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(MainActivity.Instance, Manifest.Permission.RecordAudio))
{
Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content),
"Microphone permissions are required for speech transcription!",
Snackbar.LengthIndefinite)
.SetAction("Ok", v =>
{
((Activity)MainActivity.Instance).RequestPermissions(permissions, RecordAudioPermissionCode);
})
.Show();
}
else
{
ActivityCompat.RequestPermissions((Activity)MainActivity.Instance, permissions, RecordAudioPermissionCode);
}
}
}
}
New Speech=>Text class to use SpeechRecognizer: Mostly take frrm this How to increase the voice listen time in Google Recognizer Intent(Speech Recognition) Android
using Android;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Speech;
using AndroidX.Core.App;
using Java.Util;
using MauiDemo.Common;
using Microsoft.Maui.Controls;
using Plugin.CurrentActivity;
using System.Threading;
namespace MauiDemo.Speech
{
public class SpeechToTextImplementation2 : Java.Lang.Object, IRecognitionListener, IMessageSender
{
public static AutoResetEvent autoEvent = new AutoResetEvent(false);
private readonly int VOICE = 10;
private Activity _activity;
private float _timeOut = 3;
private SpeechRecognizer _speech;
private Intent _speechIntent;
public string Words;
public string Language;
private MicrophoneService micService;
public SpeechToTextImplementation2()
{
micService = new MicrophoneService();
_activity = CrossCurrentActivity.Current.Activity;
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._activity);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
}
void RestartListening()
{
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
_speech.Destroy();
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._activity);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
StartListening();
}
public async void StartListening()
{
bool isMicEnabled = await micService.GetPermissionAsync();
if (!isMicEnabled)
{
Words = "Please grant access to the microphone!";
return;
}
_speech.StartListening(_speechIntent);
}
public void StopListening()
{
_speech.StopListening();
}
public void OnBeginningOfSpeech()
{
}
public void OnBufferReceived(byte[] buffer)
{
}
public void OnEndOfSpeech()
{
}
public void OnError([GeneratedEnum] SpeechRecognizerError error)
{
Words = error.ToString();
MessagingCenter.Send<IMessageSender, string>(this, "Error", Words);
RestartListening();
}
public void OnEvent(int eventType, Bundle #params)
{
}
public void OnPartialResults(Bundle partialResults)
{
}
public void OnReadyForSpeech(Bundle #params)
{
}
public void OnResults(Bundle results)
{
var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
if (matches == null)
Words = "Null";
else
if (matches.Count != 0)
Words = matches[0];
else
Words = "";
MessagingCenter.Send<IMessageSender, string>(this, "STT", Words);
RestartListening();
}
public void OnRmsChanged(float rmsdB)
{
}
}
}
Update MainActivities for permission
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Speech;
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
namespace MauiDemo
{
[Activity(Label = "Maui Demo", Theme = "#style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity, IMessageSender
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Instance = this;
micService = new MicrophoneService();
}
private readonly int VOICE = 10;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == VOICE)
{
if (resultCode == Result.Ok)
{
var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
if (matches.Count != 0)
{
string textInput = matches[0];
MessagingCenter.Send<IMessageSender, string>(this, "STT", textInput);
}
else
{
MessagingCenter.Send<IMessageSender, string>(this, "STT", "");
}
//SpeechToTextImplementation.autoEvent.Set();
}
}
base.OnActivityResult(requestCode, resultCode, data);
}
MicrophoneService micService;
internal static MainActivity Instance { get; private set; }
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
// ...
switch (requestCode)
{
case MicrophoneService.RecordAudioPermissionCode:
if (grantResults[0] == Permission.Granted)
{
micService.OnRequestPermissionResult(true);
}
else
{
micService.OnRequestPermissionResult(false);
}
break;
}
}
}
}
Feel free to check out the code, but I will not use this for anything serious because it does not runs properly yet.
Any opinion to improve for the code will be really appreciated, as I really want to get good with this MAUI platform.

c# TLS client without client certificate

I'm trying to create a TLS client without the need for TLS client certificate.
This works with client certificate:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
private static readonly string ServerCertificateName = "MyServer";
private static readonly string ClientCertificateFile = "client.pfx";
private static readonly string ClientCertificatePassword = null;
static void Main(string[] args) {
try {
var clientCertificate = new X509Certificate2(ClientCertificateFile, ClientCertificatePassword);
var clientCertificateCollection = new X509CertificateCollection(new X509Certificate[] { clientCertificate });
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false, App_CertificateValidation)) {
Console.WriteLine("Device connected.");
sslStream.AuthenticateAsClient(ServerCertificateName, clientCertificateCollection, SslProtocols.Tls12, false);
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
sslStream.Write(outputBuffer);
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
private static bool App_CertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; } //we don't have a proper certificate tree
Console.WriteLine("*** SSL Error: " + sslPolicyErrors.ToString());
return false;
}
}
}
Trying to remove the need for TLS client certificate is as follows:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
static void Main(string[] args) {
try {
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false)) {
Console.WriteLine("Device connected.");
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
try {
sslStream.Write(outputBuffer);
} catch (Exception x) {
var baseException = x.GetBaseException();
Console.WriteLine(baseException);
}
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
}
}
But this outputs:
Device connected.
System.InvalidOperationException: This operation is only allowed using a successfully authenticated context.
at Mono.Net.Security.MobileAuthenticatedStream.CheckThrow (System.Boolean authSuccessCheck, System.Boolean shutdownCheck) [0x0001e] in <cbad0c8bbe7b432eb83038c06be00093>:0
at Mono.Net.Security.MobileAuthenticatedStream+<StartOperation>d__58.MoveNext () [0x00011] in <cbad0c8bbe7b432eb83038c06be00093>:0
***** AggregateException
***** One or more errors occurred.!
you need to change your code if use tls you need to authenticate first.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
static void Main(string[] args) {
try {
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(App_CertificateValidation)) {
sslStream.AuthenticateAsClient(ServerIpAddress);
Console.WriteLine("Device connected.");
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
try {
sslStream.Write(outputBuffer);
} catch (Exception x) {
var baseException = x.GetBaseException();
Console.WriteLine(baseException);
}
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
private static bool App_CertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; } //we don't have a proper certificate tree
Console.WriteLine("*** SSL Error: " + sslPolicyErrors.ToString());
return false;
}
}
}

Android - Get value from Service and using it in Widget

I am developing a simple C# Android app, which runs in Background and does a specific calculation, I have a also a widget with a TexTview in which I want to display the Calculation result.
Service.cs
Intent intent = new Intent("TEST");
intent.PutExtra("alltotale", total.ToString());
this.SendBroadcast(intent);
Then in BroadcastReceiver class, I have:
Receiver.cs
public override void OnReceive(Context context, Intent intent)
{
string nh = intent.GetStringExtra("alltotale");
Toast.MakeText(context, nh, ToastLength.Short).Show();
}
Now I want to re-use this value and display it in the widget TextView but it is not working, I am getting nothing in my Widget.
AppWidget.cs
[BroadcastReceiver(Label = "Widget1")]
[IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })]
[MetaData("android.appwidget.provider", Resource = "#xml/appwidgetprovider")]
public class AppWidget : AppWidgetProvider
{
Intent intent;
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
var me = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
appWidgetManager.UpdateAppWidget(me, BuildRemoteViews(context, appWidgetIds));
}
private RemoteViews BuildRemoteViews(Context context, int[] appWidgetIds)
{
var widgetView = new RemoteViews(context.PackageName, Resource.Layout.Widget);
SetTextViewText(widgetView);
RegisterClicks(context, appWidgetIds, widgetView);
return widgetView;
}
private void SetTextViewText(RemoteViews widgetView)
{
string oo = intent.GetStringExtra("alltotale");
widgetView.SetTextViewText(Resource.Id.widgetMedium, "Dabboussi");
widgetView.SetTextViewText(Resource.Id.widgetSmall, oo);
}
private static string AnnouncementClick = "AnnouncementClickTag";
private void RegisterClicks(Context context, int[] appWidgetIds, RemoteViews widgetView)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(AppWidgetManager.ActionAppwidgetUpdate);
intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, appWidgetIds);
// Register click event for the Background
var piBackground = PendingIntent.GetBroadcast(context, 0, intent, PendingIntentFlags.UpdateCurrent);
widgetView.SetOnClickPendingIntent(Resource.Id.widgetAnnouncementIcon, GetPendingSelfIntent(context, AnnouncementClick));
}
private PendingIntent GetPendingSelfIntent(Context context, string action)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(action);
return PendingIntent.GetBroadcast(context, 0, intent, 0);
}
public override void OnReceive(Context context, Intent intent)
{
base.OnReceive(context, intent);
var data = intent.GetStringExtra("alltotale");
if (data != null)
{
var updateViews = new RemoteViews(context.PackageName, Resource.Layout.Widget);
SetTextViewText(updateViews);
ComponentName thisWidget = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
AppWidgetManager manager = AppWidgetManager.GetInstance(context);
manager.UpdateAppWidget(thisWidget, updateViews);
}
if (AnnouncementClick.Equals(intent.Action))
{
Toast.MakeText(context, "OPEN", ToastLength.Short).Show();
// Open another app
}
}
}
So, the value is being displayed in the Toast message in background but nothing in the widget textview. Why is that and how can I solve it ?
Edit
I have thought that maybe ISharedPreferences would do the trick, so I did the following:
Service.cs
Intent priceIntent = new Intent("com.xamarin.example.TEST");
priceIntent.PutExtra("alltotale", total.ToString());
this.SendBroadcast(priceIntent);
ISharedPreferences prSer = PreferenceManager.GetDefaultSharedPreferences(this);
ISharedPreferencesEditor prEd = prSer.Edit();
prEd.PutInt("PriceTot", Convert.ToInt32(total));
then in the AppWidget.cs file I did the following:
[BroadcastReceiver(Label = "Widget1")]
[IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE", "com.xamarin.example.TEST" })]
[MetaData("android.appwidget.provider", Resource = "#xml/appwidgetprovider")]
public class AppWidget : AppWidgetProvider
{
Intent intent;
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
var me = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
appWidgetManager.UpdateAppWidget(me, BuildRemoteViews(context, appWidgetIds));
}
private RemoteViews BuildRemoteViews(Context context, int[] appWidgetIds)
{
var widgetView = new RemoteViews(context.PackageName, Resource.Layout.Widget);
//SetTextViewText(widgetView);
RegisterClicks(context, appWidgetIds, widgetView);
return widgetView;
}
private void SetTextViewText(RemoteViews widgetView)
{
widgetView.SetTextViewText(Resource.Id.widgetMedium, "Don Dabboussi");
widgetView.SetTextViewText(Resource.Id.widgetSmall, "KK");
}
private static string AnnouncementClick = "AnnouncementClickTag";
private void RegisterClicks(Context context, int[] appWidgetIds, RemoteViews widgetView)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(AppWidgetManager.ActionAppwidgetUpdate);
intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, appWidgetIds);
// Register click event for the Background
var piBackground = PendingIntent.GetBroadcast(context, 0, intent, PendingIntentFlags.UpdateCurrent);
//widgetView.SetOnClickPendingIntent(Resource.Id.widgetAnnouncementIcon, GetPendingSelfIntent(context, AnnouncementClick));
}
private PendingIntent GetPendingSelfIntent(Context context, string action)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(action);
return PendingIntent.GetBroadcast(context, 0, intent, 0);
}
public override void OnReceive(Context context, Intent intent)
{
base.OnReceive(context, intent);
ISharedPreferences prSer = PreferenceManager.GetDefaultSharedPreferences(context);
var data = prSer.GetInt("PriceTot", 0);
if (data != 0)
{
var updateViews = new RemoteViews(context.PackageName, Resource.Layout.Widget);
SetTextViewText(updateViews);
ComponentName thisWidget = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
AppWidgetManager manager = AppWidgetManager.GetInstance(context);
manager.UpdateAppWidget(thisWidget, updateViews);
}
if (AnnouncementClick.Equals(intent.Action))
{
Toast.MakeText(context, "OPEN", ToastLength.Short).Show();
// Open another app
}
}
But that didn't worked, there are no text in the textviews in my widget (no dabboussi and no kk). Why is that ?
You put a string named alltotale and you ask for a string named widgetTotale, so it is normal if it is not working. You have to change widgetTotale by alltotale
You need to get AppWidgetManager and call UpdateAppWidget() method to update the widget.
For example:
public override void OnReceive(Context context, Intent intent)
{
base.OnReceive(context, intent);
var data = intent.GetStringExtra("alltotale");
if(data != null)
{
var updateViews = new RemoteViews(context.PackageName, Resource.Layout.widget);
SetTextViewText(updateViews, intent);
// Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(context, Java.Lang.Class.FromType(typeof(MyWidget)).Name);
AppWidgetManager manager = AppWidgetManager.GetInstance(context);
manager.UpdateAppWidget(thisWidget, updateViews);
}
}
private void SetTextViewText(RemoteViews widgetView, Intent intent)
{
string oo = intent.GetStringExtra("alltotale");
widgetView.SetTextViewText(Resource.Id.widgetMedium, "Dabboussi");
widgetView.SetTextViewText(Resource.Id.widgetSmall, oo);
}
And you could refer to this official demo for more information.

Async/Await deadlock

I can't seem to get my code work, although I tried several different approaches. Here is my preferred code snippet:
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var championsData = freeToPlayChampions.Select(x =>
client.GetStaticChampionByIdAsync(
(int)x.Id,
platformId: Region));
ConsoleTable.From(await Task.WhenAll(championsData)).Write();
When debugging I see that the code hangs on await Task.WhenAll(championsData). So i tried to make the code more easy:
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var table = new ConsoleTable();
foreach(var freeToPlayChampion in freeToPlayChampions)
{
var championsData = client.GetStaticChampionByIdAsync(
(int)freeToPlayChampion.Id,
platformId: Region);
table.AddRow(await championsData);
}
table.Write();
Unfortunately this hangs, as well. Again on the same code part, e.g. await championsData.
How can this 'easy' usage of async/await lead to an deadlock? Thanks in advance for help!
EDIT:
Here is the whole class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsoleTables;
using Mono.Options;
using RiotNet.Models;
using RiotShell.Properties;
namespace RiotShell
{
public class FreeToPlay : IShellCommand
{
public IEnumerable<string> Names { get; }
public OptionSet Options { get; }
public bool ShowHelp { get; private set; }
public string Region { get; private set; }
public FreeToPlay()
{
Names = new List<string>
{
"freetoplay",
"ftp"
};
Options = new OptionSet
{
{ "r|region=" , "The region to execute against", x => Region = x},
{ "h|help|?" , "Show help", x => ShowHelp = true }
};
}
public async Task Execute(IEnumerable<string> args)
{
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return;
}
if (args.Any())
{
throw new Exception(Resources.TooManyArgumentsProvided);
}
if (Region == null)
{
throw new Exception(string.Format(Resources.RequiredOptionNotFound, "region"));
}
if (!PlatformId.All.Contains(Region))
{
throw new Exception(string.Format(Resources.InvalidRegion, Region));
}
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var championsData = freeToPlayChampions.Select(x =>
client.GetStaticChampionByIdAsync(
(int)x.Id,
platformId: Region));
ConsoleTable.From(await Task.WhenAll(championsData)).Write();
}
}
}
And here is the caller code, my main method:
using System;
using System.Threading.Tasks;
using RiotShell.Properties;
namespace RiotShell
{
public class Program
{
public static async Task Main()
{
while (true)
{
Console.Write(Resources.RiotShellLineString);
var input = Console.ReadLine();
try
{
var parsedArgs = InputParser.Parse(input);
(var command, var commandArgs) = ArgsToIShellCommandCaster.GetCommand(parsedArgs);
await command.Execute(commandArgs);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
Since it was wished, here the code for the ApiProvider:
using RiotNet;
using System.Threading.Tasks;
namespace RiotShell
{
public class ApiClientProvider
{
private static IRiotClient _client;
public static async Task<IRiotClient> GetApiClient()
{
if (_client != null)
{
_client.Settings.ApiKey = await KeyService.GetKey();
return _client;
}
_client = new RiotClient(new RiotClientSettings
{
ApiKey = await KeyService.GetKey()
});
return _client;
}
}
}

Memory increase gradually after every HTTPClient Call in Xamarin iOS. GC collection is not effective

I have monitor the Application Allocation using Instrument. I have noticed that Memory is gradually increase. I just need release the memory which is used by HTTPClient.
I have tried using Dispose(),used using statement,used GC.collect; but those are not reducing the memory. It looks like not effective.
Below is code used in the program.
namespace MemoryManagementStudy
{
public partial class ViewController : UIViewController
{
protected ViewController(IntPtr handle) : base(handle)
{
}
NetworkStaticCall networkStaticCall;
public override void ViewDidLoad()
{
//lblStatusUpdate.Text = "Success Count: 0, Fail Count: 0 -- Last Update: " + DateTime.Now;
base.ViewDidLoad();
//string status = "";
networkStaticCall = new NetworkStaticCall();
networkStaticCall.init();
Timer timer = new Timer(1000 * 30);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) => {
Console.WriteLine("Memory " + GC.GetTotalMemory(true));
await networkStaticCall.MakeSMWebService();
Console.WriteLine("Memory " + GC.GetTotalMemory(true));
};
timer.Start();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
}
class NetworkStaticCall
{
//int successCount = 0;
//int failCount = 0;
private static HttpClient httpClient;
private static HttpResponseMessage httpResponseMessage;
private StringContent dataContent;
private string xmlString;
private static HttpClientHandler httpClientHandler;
private NSUrlSessionHandler nsUrlSessionHandler;
public void init()
{
httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new NetworkCredential("userName", "Password"); ;
httpClient = new HttpClient(httpClientHandler);
httpClient.DefaultRequestHeaders.Accept.Clear();
dataContent = new StringContent("Xml String Content",
Encoding.UTF8, "text/xml");
}
public async Task<string> MakeSMWebService()
{
Console.WriteLine("Call Processing");
try
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpResponseMessage = await httpClient.PostAsync("url", dataContent);
Console.WriteLine("Call success");
xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
//successCount++;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}
}
}
We have tried https://stackoverflow.com/a/27830926 but it is not working.
I have tried WebRequest but it still increasing
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using UIKit;
namespace MemoryManagementStudy
{
public partial class ViewController : UIViewController
{
protected ViewController(IntPtr handle) : base(handle)
{
}
CustomWebRequest customWebRequest;
public override void ViewDidLoad()
{
customWebRequest = new CustomWebRequest();
lblStatusUpdate.Text = "Success Count: 0, Fail Count: 0 -- Last Update: " + DateTime.Now;
base.ViewDidLoad();
string status = "";
//networkStaticCall = new NetworkStaticCall();
//networkStaticCall.init();
//
Timer timer = new Timer(1000 * 60);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) => {
status = await customWebRequest.Post();
InvokeOnMainThread(()=>{
lblStatusUpdate.Text =status + " -- Last Update: " + DateTime.Now;
});
GC.Collect();
};
timer.Start();
}
}
class CustomWebRequest{
string finalUrl = "URL";
//StreamReader reader;
int successCount = 0;
int failCount = 0;
async public Task<string> Post()
{
var request = WebRequest.Create(finalUrl);
request.Method = "GET";
request.Timeout = 10000;
try
{
using (var response = await request.GetResponseAsync())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine(reader.ReadToEnd());
}
}
successCount++;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
failCount++;
}
finally
{
if(request != null){
request.Abort();
request = null;
}
}
return string.Format("Success Count: {0}, Fail Count: {1}", successCount, failCount);
}
}
}

Categories