How can i add a .AddOnCompleteListener(this) to SignOut() method in Xamarin.Android.
I want to navigate back to the login page after signing out. I'm using Xamarin.Firebase.Auth to login and I'm logging in like this:
private void InitFirebaseAuth()
{
app = FirebaseApp.Instance;
auth = FirebaseAuth.GetInstance(app);
var user = auth.CurrentUser;
if (user != null)
{
StartActivity(new Intent(this, typeof(HomeActivity)));
Finish();
}
}
Then after logging in, I want to log out and navigate to the logging page again, and I want to be sure that I have successfully logged out, but SignOut() has not a .AddOnCompleteListener(this).
example:
public class HomeActivity : AppCompatActivity, IOnCompleteListener
{
#region Public Properties
private FirebaseAuth auth;
#endregion
FirebaseUser user;
private DatabaseReference RealTimeDatabase;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.home);
auth = FirebaseAuth.GetInstance(MainActivity.app);
user = auth.CurrentUser;
//Init Firebase
RealTimeDatabase = FirebaseDatabase.Instance.GetReference("Users");
var welcomeMessage = FindViewById<TextView>(Resource.Id.welcomeMessage);
var LogOutBtn = FindViewById<Button>(Resource.Id.logOutBtn);
welcomeMessage.Text = $"Welcome {user.DisplayName}!";
LogOutBtn.Click += delegate
{
auth.SignOut().AddOnCompleteListener(this);
};
}
public void OnComplete(Task task)
{
if (task.IsSuccessful)
{
StartActivity(new Intent(this, typeof(MainActivity)));
Finish();
}
else
{
Snackbar snackbar = Snackbar.Make(activity_main, "Failed", Snackbar.LengthShort);
snackbar.Show();
}
}
}
Any help, please?
The SignOut operation is synchronous, so the sign out is completed as soon as the method is done. That's why it doesn't have/need a completion handler. You can just put any code that needs to happen after signing out, right after the method call:
auth.SignOut();
// whatever needs to happen after signing out
Related
I need to make a simple callback in Xamarin, to check if the network status is connected or disconnected.
I have so far been doing it with this code:
class NetworkControl : INetworkControl
{
private readonly INetworkControl.ICallback _callback;
private readonly Context _context;
private readonly NetworkBroadcastReceiver _receiver = new NetworkBroadcastReceiver();
public NetworkControl(INetworkControl.ICallback callback, Context context)
{
_callback = callback;
_context = context;
IntentFilter filter = new IntentFilter(ConnectivityManager.ConnectivityAction);
context.RegisterReceiver(_receiver, filter);
}
public INetworkControl.ICallback Callback => _callback;
public INetworkControl.NetworkStatus Status
{
get
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
return INetworkControl.NetworkStatus.Connected;
}
return INetworkControl.NetworkStatus.Disconnected;
}
}
}
class NetworkBroadcastReceiver : BroadcastReceiver
{
private static String TAG = "NetworkBroadcastReceiver";
public override void OnReceive(Context context, Intent intent)
{
if (ShellBridge.Instance != null)
{
if (intent.Action.Equals(ConnectivityManager.ConnectivityAction))
{
NetworkInfo ni = (NetworkInfo)intent.Extras.Get(ConnectivityManager.ExtraNetworkInfo);
if (ni.isConnected)
{
// do something if connected
ShellBridge.Instance.NetworkBridge.Callback.NetworkStatusChanged(INetworkControl.NetworkStatus.Connected);
} else
{
ShellBridge.Instance.NetworkBridge.Callback.NetworkStatusChanged(INetworkControl.NetworkStatus.Connected);
}
}
}
}
The problem is, the function ConnectivityManager.ConnectivityAction in the Intent creating is depricated, and will soon be obsolete. After searching, I found that the pendingIntent should be used for that, but I could not find any valid example of how to use it.
The closest to what I need is this:
https://stackoverflow.com/questions/58588132/how-to-use-registernetworkcallback-with-pendingintent
But, it has not all the information I need.
I need it to be all programmatically, without changing the manifest, for, my app should be a fore- and background app.
Please help, and thank you for your time.
You can take a look at NetworkCallback .
public class ConnectionStateMonitor : NetworkCallback
{
NetworkRequest networkRequest;
public ConnectionStateMonitor()
{
networkRequest = new NetworkRequest.Builder().
AddTransportType(TransportType.Cellular).
AddTransportType(TransportType.Wifi).Build();
}
public void enable(Context context) {
ConnectivityManager connectivityManager = context.GetSystemService(Context.ConnectivityService) as ConnectivityManager;
connectivityManager.RegisterNetworkCallback(networkRequest, this);
}
public override void OnAvailable(Network network)
{
//network available
}
public override void OnLost(Network network)
{
//network lost
}
}
Usage
You just need to instantiate the class ConnectionStateMonitor and enable it , you could detect the network status with the method OnAvailable and OnLost .
ConnectionStateMonitor m = new ConnectionStateMonitor ();
m.enable(context);
Refer
https://github.com/xamarin/Essentials/issues/512
ConnectivityManager.CONNECTIVITY_ACTION deprecated
You don't need to reinvent the wheel. You can achieve all that with Xamarin Essentials' Connectivity.
Besides checking if there is a connectivity like this:
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
// Connection to internet is available
}
you can also track when the connectivity type changes:
public class ConnectivityTest
{
public ConnectivityTest()
{
// Register for connectivity changes, be sure to unsubscribe when finished
Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
}
void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
var access = e.NetworkAccess;
var profiles = e.ConnectionProfiles;
}
}
I want to make a container-app for my web application, and I decided to do so in Xamarin because the rest of the project is also .NET.
Initially I downloaded and setup the project from Xamarin Sample Pages:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/webview?tabs=windows
I simply changed a few variables in WebPage.cs: https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/WebPage.cs
using Xamarin.Forms;
namespace WorkingWithWebview
{
public class WebPage : ContentPage
{
public WebPage()
{
var browser = new WebView();
browser.Source = "https://xamarin.swappsdev.net";
Content = browser;
}
}
}
Secondly I updated App.cs to suit my needs: https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/App.
using Xamarin.Forms;
namespace WorkingWithWebview
{
public class App : Application
{
public App ()
{
MainPage = new WebPage();
}
}
}
And boom! I had an app.
Then came the real struggle. In the web application I can – when opening the site (https://xamarin.swappsdev.net) in the browser – click on a button which requests permissions from the device and then display the camera feed in the same window.
When doing the same action in the app nothing happens.
I then started googling for an answer and really didn’t find a lot. And the answers I found seems to be of an older version of Xamarin (?), since I wasn’t able to compare the files and structure in the answer compared to the one of the Xamarin Sample Page.
https://stackoverflow.com/a/50560855
I tried implementing the answer from Robbit here. After a long struggle I managed to compile it and install it on my device but it doesn't actually ask for permissions.
I am at a loss and could need some help/guidance.
Updated:
In my previous answer, it shows how to add camera permission on webview.
The link you provided, it works now. https://xamarin.swappsdev.net/ It seems to provide a camera preview function. It need to check permissions on API 23+.
On Xamarin.Forms, you could use Permissions Plugin. https://github.com/jamesmontemagno/PermissionsPlugin
First, add the camera permission in Android Manifest.
Your Project.Android> Properties> Android Manifest> Required permissions> Camera. After that, it would generate the user permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.CAMERA" />
Create a Utils.cs.
public static class Utils
{
public static async Task<PermissionStatus> CheckPermissions(Permission permission)
{
var permissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
bool request = false;
if (permissionStatus == PermissionStatus.Denied)
{
if (Device.RuntimePlatform == Device.iOS)
{
var title = $"{permission} Permission";
var question = $"To use this plugin the {permission} permission is required. Please go into Settings and turn on {permission} for the app.";
var positive = "Settings";
var negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return permissionStatus;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return permissionStatus;
}
request = true;
}
if (request || permissionStatus != PermissionStatus.Granted)
{
var newStatus = await CrossPermissions.Current.RequestPermissionsAsync(permission);
if (!newStatus.ContainsKey(permission))
{
return permissionStatus;
}
permissionStatus = newStatus[permission];
if (newStatus[permission] != PermissionStatus.Granted)
{
permissionStatus = newStatus[permission];
var title = $"{permission} Permission";
var question = $"To use the plugin the {permission} permission is required.";
var positive = "Settings";
var negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return permissionStatus;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return permissionStatus;
}
}
return permissionStatus;
}
}
In MainActivity.cs, add the code in OnCreate method.
Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, savedInstanceState);
OnRequestPermissionsResult is needed in MainActivity.cs.
public override void OnRequestPermissionsResult(int requestCode, string[] permissions,
[GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
And then impletement it.
private async void _button_Clicked(object sender, EventArgs e)
{
webView.Source = "https://xamarin.swappsdev.net/";//"https://test.webrtc.org/";
var status = PermissionStatus.Unknown;
status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(Permission.Camera);
}
}
I have upload on my GitHub. Check the folder. Test/CameraRuntimePermission_WebView/RuntimePermission
https://github.com/WendyZang/Test.git
Edit:
If you do not want to call this in button click event, you could delete the button in MainPage.xaml.
MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
webView.Source = "https://xamarin.swappsdev.net/";
}
protected override void OnAppearing()
{
base.OnAppearing();
RunTimePermission();
}
public async void RunTimePermission()
{
var status = PermissionStatus.Unknown;
status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(Permission.Camera);
}
}
After following several guides to enable the WebView's camera, I have finally succeeded.
I followed all of the above steps, and despite getting prompts for allowing the camera I could never get rid of the permissions error (even when debug showed the permissions were granted). I then replaced the MyWebViewRenderer code (as given above by Wendy) with the following (as given on https://forums.xamarin.com/discussion/183988/how-to-give-camera-and-microphone-permission-to-webview-with-xamarin-forms-on-android):
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace App19F_8.Droid
{
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.SetWebChromeClient(new MyWebChromeClient(MainActivity.Instance));
Control.Settings.JavaScriptEnabled = true;
}
}
}
public class MyWebChromeClient : WebChromeClient
{
Activity mActivity = null;
public MyWebChromeClient(Activity activity)
{
mActivity = activity;
}
public override void OnPermissionRequest(PermissionRequest request)
{
mActivity.RunOnUiThread(() => {
request.Grant(request.GetResources());
});
}
}
}
In case the link above becomes invalid, I should mention that in Android's MainActivity you should insert the following:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
...
base.OnCreate(savedInstanceState);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
Now finally the camera is working :-) I'm not exactly sure what the culprit was in the previous code. Thanks a lot to Wendy, Yelinzh and all for the thorough responses.
I tried implementing the answer from Robbit here. After a long struggle I managed to compile it and install it on my device but it doesn't actually ask for permissions.
I try the code provided by Robbit from the link.
Camera on Xamarin WebView
Actually, it works well. For better understanding, you could use the link below to check. https://test.webrtc.org/
If I use the webview to load the url directly, it would throw the error like below.
If I use the custom renderer from Robbit, it would ask for permission with the code in MyWebViewRenderer.
public override void OnPermissionRequest(PermissionRequest request)
{
mContext.RunOnUiThread(() =>
{
request.Grant(request.GetResources());
});
}
I have also check the link you used, nothing happened. The link would not open the camera in Android device.
Usage of the code from Robbit.
Create the MyWebView in your project.
public class MyWebView : WebView
{
}
Create the MyWebViewRenderer.cs in Android part of your project.
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace WebViewDemo.Droid
{
public class MyWebViewRenderer : WebViewRenderer
{
Activity mContext;
public MyWebViewRenderer(Context context) : base(context)
{
this.mContext = context as Activity;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.Settings.JavaScriptEnabled = true;
Control.ClearCache(true);
Control.SetWebChromeClient(new MyWebClient(mContext));
}
public class MyWebClient : WebChromeClient
{
Activity mContext;
public MyWebClient(Activity context)
{
this.mContext = context;
}
[TargetApi(Value = 21)]
public override void OnPermissionRequest(PermissionRequest request)
{
mContext.RunOnUiThread(() =>
{
request.Grant(request.GetResources());
});
}
}
}
}
Usage:
MainPage.xaml
<StackLayout>
<Button x:Name="_button" Clicked="_button_Clicked" />
<local:MyWebView
x:Name="webView"
HeightRequest="500"
WidthRequest="500" />
</StackLayout>
MainPage.xaml.cs
private void _button_Clicked(object sender, EventArgs e)
{
webView.Source = "https://test.webrtc.org/";//"https://xamarin.swappsdev.net/";
}
You could download the whole project from GitHub folder CameraRuntimePermission_WebView. The Page1 is used to test the link with webview. The MainPage is used to test with custom renderer.
https://github.com/WendyZang/Test.git
Hi I am facing a very simple problem but I am not exactly sure why?
I am trying to call directly from xamarin forms app, without showing dailer screen, user will see list of its contacts in a screen click a button to call, and it will make a direct call without showing dialer screen.
to achieve this I have used DependencyServic and I have used this as my base https://www.c-sharpcorner.com/UploadFile/e4bad6/code-to-start-call-in-xamarin-forms/
the only difference is this is PCL and I am using shared library
Where I am getting Problem?
My Interface
public interface IPhoneCall
{
void MakeQuickCall(string PhoneNumber);
}
My call to Dependency Service
private void makeCall_Clicked(object sender, EventArgs e)
{
try
{
DependencyService.Get<IPhoneCall>().MakeQuickCall("+xxxxxxxxx");
} catch(Exception ex)
{
DisplayAlert("Alert!!!", ex.Message, "ok");
}
}
My Dependency service call for Android:
[assembly: Dependency(typeof(PhoneCall_Droid))]
namespace MakeCall.Droid
{
public class PhoneCall_Droid : IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}
}
This alert is returning an exception Unable to add window - token null is not valid; is your activity running?
I have looked different solutions like this
Intent ActionCall is not making phone call in xamarin forms
and this
https://forums.xamarin.com/discussion/129166/unable-to-add-window-token-null-is-not-for-an-application-alertbuilder
but I am still not able to sort this, out,
also I tried this in my Main activity
internal static MainActivity Instance { get; private set; }
and then added this line in OnCreate method
Instance = this;
and changed my Android dependency service class method to this
public void MakeQuickCall(string PhoneNumber)
{
var context = MainActivity.Instance;
try
{
new AlertDialog.Builder(context ).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber)).ToString())
.SetTitle("Android Exception")
.Show();
Intent intent = new Intent(Intent.ActionCall, Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber)));
context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
and by doing this alert is showing the dailed phone number, but it is not calling and for call part is still showing same of unable to add window ..,
I can reproduce your issue at my side, if you request the runtime permissions after Android 6.0, you will solved your issue.
Firstly, you could defined a static variable in MainActiviy:
public static MainActivity macvivity;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
macvivity = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
Then requesting permissions before call:
public void MakeQuickCall(string PhoneNumber)
{
try
{
if (ActivityCompat.CheckSelfPermission(MainActivity.macvivity, Android.Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted)
{
ActivityCompat.RequestPermissions(MainActivity.macvivity, new string[] { Android.Manifest.Permission.CallPhone }, 1);
return;
}
else
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
//MainActivity.macvivity.StartActivity(intent);
}
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
Assume that i'm in the Page_1 while click the button have to navigate to Page_2.In Page_2 Api call has to done.
MyIssue is when i'm clicking the Button it doesn't navigate to Page_2 immediately it waits for the API response.
How to Navigate Immediately to Page_2 without waiting for the APi response.
Code:
Page_1.cs
public partial class Page_1 : ContentPage
{
public Page_1()
{
InitializeComponent();
}
private void Btn_click(object sender, EventArgs e)
{
Navigation.PushAsync(new Page_2());
}
}
Page_2:
public Page_2()
{
InitializeComponent();
}
protected override void OnAppearing()
{
HttpClient httpClient = new HttpClient();
var obj = httpClient.GetAsync("//Api//").Result;
if (obj.IsSuccessStatusCode)
{
}
}
Same code works good in iOS as expected
You could load your data in an other Task to prevent blocking the UI.
protected override void OnAppearing()
{
Task.Run( () => LoadData());
base.OnAppearing();
}
private async void LoadData()
{
HttpClient httpClient = new HttpClient();
var obj = await httpClient.GetAsync("//Api//");
if (obj.IsSuccessStatusCode)
{
// If you need to set properties on the view be sure to use MainThread
// otherwise you won't see it on the view.
Device.BeginInvokeOnMainThread(() => Name = "your text";);
}
}
As per your question you are calling the API on Page constructor that's why it's taking time to load web API then navigating on page2. If you want to navigate on page2 before a load the api. Check below code
public partial class Page2 : ContentPage
{
bool IsLoading{ get; set; }
public Page2()
{
InitializeComponent();
IsLoading = false;
}
protected async override void OnAppearing()
{
base.OnAppearing();
if (!IsLoading)
{
IsLoading=true
**Call the Web API Method Here**
}
IsLoading=false
}
}
Im building an android app using Xamarin and C#.
The app use restsharp to connect to my server and pull the information I need.
Im trying to build a register page, and I want to check if the user exist.
I want to do this in the background while the user see a ProgressDialog.
This is my code:
if (!string.IsNullOrEmpty(PhoneNumber) && !string.IsNullOrEmpty(Password)
&& !string.IsNullOrEmpty(LicenceId) && LicenceImage.Length > 1)
{
ProgressDialog mDialog = new ProgressDialog(this);
mDialog.SetMessage("Loading data...");
mDialog.SetCancelable(false);
mDialog.Show();
bool checkExistance = await api.CheckIfExist(PhoneNumber);
if (checkExistance)
{
Android.Support.V7.App.AlertDialog.Builder alert = new Android.Support.V7.App.AlertDialog.Builder(this);
alert.SetTitle("");
}
else
{
Intent intent = new Intent(this, typeof(RegisterDone));
StartActivity(intent);
}
}
The ProgressDialog shows but than nothing happedns.
I tried to do it in other ways but still dosent work.
What is the propper way to do it? Thx in advance
I want to check if the user exist. I want to do this in the background while the user see a ProgressDialog
In Android, you could use Handler to implement this feature. When you display a ProgressDialog, you could use Handler open a new thread to execute the verification. When you get the result, send a message to Handler, in Handler class, you could get the result and do your logic. Here is an example :
Display the ProgressDialog and use Handler open a new thread to execute the verification :
mDialog = new ProgressDialog(this);
mDialog.SetMessage("Loading data...");
mDialog.SetCancelable(false);
mDialog.Show();
Action action = () =>
{
checkExistance();
};
handler = new MyHandler(this);
handler.Post(action);
Check if the user exist and return a value, send message to MyHandler :
private async void checkExistance()
{
bool checkExistance = api.CheckIfExist(PhoneNumber);
Message msg = new Message();
msg = handler.ObtainMessage();
if (checkExistance)
{
msg.Arg1 = 0;//tell MyHandler exist
}
else
{
msg.Arg1 = 1;//tell MyHandler didnt exist
}
handler.SendMessage(msg);
}
Handle message in MyHandler :
public class MyHandler : Handler
{
private MainActivity mainActivity;
public MyHandler(MainActivity mainActivity)
{
this.mainActivity = mainActivity;
}
public override void HandleMessage(Message msg)
{
switch (msg.Arg1)
{
case 0:
//true
mainActivity.Exist();
mainActivity.mDialog.Dismiss();
break;
case 1:
//false
mainActivity.Regist();
mainActivity.mDialog.Dismiss();
break;
default:
break;
}
base.HandleMessage(msg);
}
}
Exist() method and Regist() in MainActivity :
public void Exist()
{
Android.Support.V7.App.AlertDialog.Builder alert = new Android.Support.V7.App.AlertDialog.Builder(this);
alert.SetTitle("");
}
public void Regist()
{
Intent intent = new Intent(this, typeof(RegisterDone));
StartActivity(intent);
}
Effect :