I’d like to connect to the device from an Android app. I already managed to authorize successfully. Now I would like to start the automatic polling as described in the reference (Request command: E0 00 00 40 01, Page 30, https://www.acs.com.hk/download-manual/7664/REF-ACR1255U-J1-1.12.pdf) but I don’t get it.
I think, I have to encrypt the request to the reader. Is this correct? If yes, which key do I have to use? Comes the key (session key?) from the final response within the authorization flow?
For testing I used the demo app (https://www.acs.com.hk/download-driver-unified/9644/ACS-BT-EVK-Android-1.01r2.zip) and Wireshark to record the requests.
I was very surprised to find that the request would change every time once I clicked the "start polling" button. I would expect it to be the same, no matter how often I click.
I would appreciate a more helpful explanation of the start polling command than the one I can find in the reference.
I just created an auto polling command :
private static final byte[] AUTO_POLLING_START = {(byte) 0xE0, 0x00, 0x00, 0x40, 0x01};
then a function that I am executing in onAuthenticationComplete listener, after successful authentication
private void startPolling() {
if (bluetoothReader == null) {
authStatus.setText("Card reader not ready");
return;
}
if (!bluetoothReader.transmitEscapeCommand(AUTO_POLLING_START)) {
authStatus.setText("Card reader not ready");
}
}
bluetoothReader.setOnAuthenticationCompleteListener(new BluetoothReader.OnAuthenticationCompleteListener() {
#Override
public void onAuthenticationComplete(BluetoothReader bluetoothReader, final int errorCode) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (errorCode == BluetoothReader.ERROR_SUCCESS) {
authStatus.setText("Authentication Success!");
startPolling();
} else {
authStatus.setText("Authentication Failed!");
}
}
});
}
});
Related
We use PushSharp 4.0.10 to send iOS Push Notifications:
https://github.com/Redth/PushSharp
Recently we recieved this email from Apple Developer:
"If you still send push notifications with the legacy binary protocol, it's time to update to the HTTP/2-based Apple Push Notification service (APNs) provider API. You'll be able to take advantage of great features, such as authentication with a JSON Web Token, improved error messaging, and per-notification feedback.
To give you additional time to prepare, the deadline to upgrade to the APNs provider API has been extended to March 31, 2021. We recommend upgrading as soon as possible, as APNs will no longer support the legacy binary protocol after this date."
My question is: Will PushSharp 4.0.10 still work after March 31, 2021?
There is a discussion about this but the thread was closed. But there are still some suggestions on this thread that you might want to try.
The Apple Push Notification service (APNs) will no longer support the legacy binary protocol as of November 2020
https://github.com/Redth/PushSharp/issues/923
**
EDIT - 25th March 2021
The deadline is close and #Ashita Shah asked some code snippet so I hope the following can save your time.
Add the following class dotAPNSService to your project. You can customise this structure according to your needs. Also I didn't focus the best of best coding C# standards when implementing my own push notification service. You can implement LINQ, Tasks async etc. I tested this dotAPNS library and it works perfectly fine. For Android you can still use PushSharp.
Before you implement the dotAPNSService helper class, get the following from your Apple developer account. The ApnsJwtOptions values should be:
BundleId - your app’s bundle ID. Should not include specific topics (i.e. com.myapp but not com.myapp.voip).
CertFilePath - path to the .p8 certificate you have downloaded from the Developer Center.
KeyId - The 10-character Key ID you obtained from your developer account
TeamId - The 10-character Team ID you use for developing your company’s apps. Obtain this value from your developer account.
public class dotAPNSService : IDisposable
{
public event EventHandler OnTokenExpiredHandler;
private ApnsJwtOptions options = null;
public dotAPNSService()
{
options = new ApnsJwtOptions()
{
BundleId = "com.xx.xxxx",
CertFilePath = "../../certificate.p8",
KeyId = "The_Key_Id",
TeamId = "The_Team_Id"
};
}
public void SendNotifications(String[] deviceTokens, String title, String body)
{
if (deviceTokens == null || deviceTokens.Length <= 0)
{
return;
}
if (String.IsNullOrEmpty(title))
{
return;
}
if (String.IsNullOrEmpty(body))
{
return;
}
// once you've gathered all the information needed and created an options instance, it's time to call
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);
// start the process
foreach (String deviceToken in deviceTokens)
{
var push = new ApplePush(ApplePushType.Alert)
.AddAlert(title, body)
.AddToken(deviceToken);
Send(apns, push, deviceToken);
}
}
public void SendSilentNotifications(String[] deviceTokens)
{
try
{
if (deviceTokens == null || deviceTokens.Length <= 0)
{
return;
}
// once you've gathered all the information needed and created an options instance, it's time to call
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);
// start the process
foreach (String deviceToken in deviceTokens)
{
var push = new ApplePush(ApplePushType.Background)
.AddContentAvailable()
.AddToken(deviceToken);
Send(apns, push, deviceToken);
}
}
finally
{
}
}
private void Send(ApnsClient apns, ApplePush push, String deviceToken)
{
try
{
var response = apns.SendAsync(push);
if (response.Result.Reason == ApnsResponseReason.Success)
{
// the notification has been sent!
}
else
{
Boolean removeToken = false;
switch (response.Result.Reason)
{
case ApnsResponseReason.BadDeviceToken:
removeToken = true;
break;
case ApnsResponseReason.TooManyRequests:
break;
}
// remove the token from database?
if (removeToken)
OnTokenExpired(new ExpiredTokenEventArgs(deviceToken));
}
}
catch (TaskCanceledException)
{
// ERROR - HTTP request timed out, you can use the deviceToken to log the error
}
catch (HttpRequestException ex)
{
// ERROR - HTTP request failed, you can use the deviceToken to log the error
}
}
protected virtual void OnTokenExpired(ExpiredTokenEventArgs args)
{
try
{
EventHandler handler = OnTokenExpiredHandler;
if (handler != null)
{
ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
if (target != null && target.InvokeRequired)
target.Invoke(handler, new object[] { this, args });
else
handler(this, args);
}
}
catch (Exception ex)
{
}
}
}
These are the namespaces of the dotAPNSService helper class:
using System;
using System.ComponentModel;
using System.Net.Http;
using System.Threading.Tasks;
using dotAPNS;
In order to use the dotAPNSService helper on your project just pull the tokens from the database and then pass them to it. For instance, to send silent notifications:
public void SendScheduledSilentNotifications()
{
try
{
IList<User> users = _accountService.GetUsers(true);
if (users != null && users.Count > 0)
{
List<String> deviceTokens = new List<String>();
foreach (User user in users)
{
if (!String.IsNullOrEmpty(user.DeviceToken))
deviceTokens.Add(user.DeviceToken);
}
if (deviceTokens.Count > 0)
{
using (dotAPNSService service = new dotAPNSService())
{
service.OnTokenExpiredHandler += new EventHandler(OnTokenExpired);
service.SendSilentNotifications(deviceTokens.ToArray());
}
}
}
}
finally
{
}
}
To remove the expired tokens from the database you can use the following:
private void OnTokenExpired(object sender, EventArgs e)
{
if (e == null)
return;
if (e.GetType() == typeof(ExpiredTokenEventArgs))
{
var args = (ExpiredTokenEventArgs)e;
User user = _accountService.GetUserByDeviceToken(args.Token);
if (user != null)
{
user.DeviceToken = String.Empty;
Boolean success = !(_accountService.SaveUser(user) == null);
if (success)
// INFO - expired device token has been removed from database
else
// INFO - something went wrong
}
}
}
You can download the source code from here:
https://github.com/alexalok/dotAPNS
The API is now sending thousands of silent notifications at one time and there are no delays, crashes etc. Hope this code snippet helps and saves your time!
I am trying to develop a xamarin forms app in which user can make call
(Navigate to dialer) from taping on number showed on app.In android I accomplished this through dependency service.But in ios I am stuck.I heard about callkit.I saw the documentation of it in https://learn.microsoft.com/en-us/xamarin/ios/platform/callkit?tabs=windows. But how can I actually implement on this in my App? I added all the classes in that document to my app.But how I can make the call from xamal.cs to the ios specified code? By using Dependency service?
Edit: I know how to navigate app to dialer or phone app. Why I am using callkit is I want to get the call duartion.
I created an Instance
public interface IosCallerDialer
{
void StartCall();
}
Implementation on ios
class IosCallDial: IosCallerDialer
{
private CXCallController CallController = new CXCallController();
private void SendTransactionRequest(CXTransaction transaction)
{
// Send request to call controller
CallController.RequestTransaction(transaction, (error) => {
// Was there an error?
if (error == null)
{
// No, report success
Console.WriteLine("Transaction request sent successfully.");
}
else
{
// Yes, report error
Console.WriteLine("Error requesting transaction: {0}", error);
}
});
}
public void StartCall()
{
// Build call action
string contact = "8547085532";
var handle = new CXHandle(CXHandleType.Generic, contact);
var startCallAction = new CXStartCallAction(new NSUuid(), handle);
// Create transaction
var transaction = new CXTransaction(startCallAction);
// Inform system of call request
SendTransactionRequest(transaction);
}
}
My xaml.cs
async void btnCall_Clicked(object sender, System.EventArgs e)
{
DependencyService.Get<IosCallerDialer>().StartCall();
}
Apart this I added all the classes defined in the document.I want only outgoing call. Is this proper way? I cant find any tutorials regarding callkit on xamarin. Any help is appreciated.
EDIT: I understand Callkit only for voip. So is there any other workaround like starting a timer when moves to phone app and stop timer when returns to app? Is it possible? Please provide any insights.
You can try the code below to detect the state of incoming call.
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public CTCallCenter c { get; set; }
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
c = new CTCallCenter();
c.CallEventHandler = delegate (CTCall call)
{
if (call.CallState == call.StateIncoming)
{
//start the timer
}
else if (call.CallState == call.StateDialing)
{
}
else if (call.CallState == call.StateConnected)
{
}
else if(call.CallState == call.StateDisconnected)
{
//end the timer
//use messagecenter to send duartion
MessagingCenter.Send<Object>(new Object(), "Hi");
}
};
return base.FinishedLaunching(app, options);
}
}
And any Where in Xamarin.forms:
MessagingCenter.Subscribe<Object>(this, "Hi", (sender) => {
// do something whenever the "Hi" message is sent
Console.WriteLine("hihihi");
});
Note: I haven't test it on my side yet as I don't have enough device. You can test it and let me know if it works.
I am using Android Firebase Auth Ui for providing Phone Number based sign in option in an android app. I am trying to provide an additional option to signed in users to switch their signed in phone number to another number keeping the same user account.
But as per Firebase Docs for Phone number there are no options to change the signed in number.
There are options for linking different auth providers like email, google or Facebook login etc to same account. But there is no way mentioned about how to change the phone number or email id keeping the same user id.
Is there a workaround or method by which we can achieve this?
An API exists for updating the phone number of a current user: FirebaseUser#updatePhoneNumber(PhoneAuthCredential credential)
I also had this challenge to update user phone number and when I go on documentation I got something by using I have done this task.
you can go for documentation by click here
Now the method you can use : - for java android project.
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential( "+91-98298XXXX2", "OTP_CODE" );
// Update Mobile Number...
firebaseAuth.getCurrentUser().updatePhoneNumber(phoneAuthCredential)
.addOnCompleteListener(new OnCompleteListener <Void>() {
#Override
public void onComplete(#NonNull Task <Void> task) {
if (task.isSuccessful()) {
// Update Successfully
} else {
// Failed
}
}
}
);
val options = PhoneAuthOptions.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(100L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(activity) // Activity (for callback binding)
.setCallbacks(returnCallBack()) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
private fun returnCallBack() = object : PhoneAuthProvider
.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
FirebaseAuth.getCurrentUser()?.updatePhoneNumber(credential)
}
override fun onVerificationFailed(e: FirebaseException) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
Log.e("phone", e.toString())
}
override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
//You need this to pass as a parameter for the update method call.
vericationSent = verificationId
}
}
fun confirmChange(code: String, context: Context?) {
if(code.contains(Regex(onlyNumber))) {
Log.d("codeSent" , "Right code : $code")
FirebaseAuth.getCurrentUser()
?.updatePhoneNumber(PhoneAuthProvider.getCredential(vericationSent, code))
?.addOnCompleteListener {task ->
//it worked if you reach here.
}?.addOnFailureListener {
//Show the error to user
}
}
vericationSent = EMPTY
} else {
Log.d("codeSent" , "wrong code : $code")
}
}
Try this
//Send otp to phone number
String verificationId;
private void startLoginFirebase(){
PhoneAuthProvider.getInstance(firebaseAuth).verifyPhoneNumber(phone, 90L, TimeUnit.SECONDS, PhoneAuthActivity.this, new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onCodeSent(#NonNull String s, #NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
verificationId = s;
updatePhoneNum();
}
#Override
public void onCodeAutoRetrievalTimeOut(#NonNull String s) {
super.onCodeAutoRetrievalTimeOut(s);
}
#Override
public void onVerificationCompleted(#NonNull PhoneAuthCredential phoneAuthCredential) {
}
#Override
public void onVerificationFailed(#NonNull FirebaseException e) {
processFurther(e.getLocalizedMessage().toString(), 0);
}
});
}
//Verify Otp
private void updatePhoneNum(){
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, otp);
firebaseAuth.getCurrentUser().updatePhoneNumber(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
}
});
}
Apparently - according to the project maintainers - FirebaseUI-Android doesn't support this feature, and it looks like they have no plans of doing it any time soon :(
so recently for a work project I've been playing around with speech to text models and in particular custom speech to text models. With a bit of mixing and matching examples I've managed to get a test application to talk to the normal Bing speech to text API. But when I attempt to use it with a custom speech instance only the HTTPS URL works. When I use any of the available long form web socket URLS the error An unhandled exception of type 'System.NullReferenceException' occurred in SpeechClient.dll occurs. This is a bit of a problem as that endpoint only supports 2 minutes of transcription, where as the websocket endpoint supports up to 10 minutes.
This https://learn.microsoft.com/en-us/azure/cognitive-services/custom-speech-service/customspeech-how-to-topics/cognitive-services-custom-speech-use-endpoint page here is what I'm going off of. It says that I should use a web socket url when creating the service, but that leads to the error above.
Here my test bed code for trying it out:
using System;
using Microsoft.CognitiveServices.SpeechRecognition;
using System.IO;
namespace ConsoleApp1
{
class Program
{
DataRecognitionClient dataClient;
static void Main(string[] args)
{
Program p = new Program();
p.Run(args);
}
void Run(string[] args)
{
try
{
// Works
//this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US", "Key");
// Works
//this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US",
// "Key", "Key",
// "https://Id.api.cris.ai/ws/cris/speech/recognize/continuous");
// Doesn't work
this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US",
"Key", "Key",
"wss://Id.api.cris.ai/ws/cris/speech/recognize/continuous");
this.dataClient.AuthenticationUri = "https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken";
this.dataClient.OnResponseReceived += this.ResponseHandler;
this.dataClient.OnConversationError += this.ErrorHandler;
this.dataClient.OnPartialResponseReceived += this.PartialHandler;
Console.WriteLine("Starting Transcription");
this.SendAudioHelper("Audio file path");
(new System.Threading.ManualResetEvent(false)).WaitOne();
} catch(Exception e)
{
Console.WriteLine(e);
}
}
private void SendAudioHelper(string wavFileName)
{
using (FileStream fileStream = new FileStream(wavFileName, FileMode.Open, FileAccess.Read))
{
// Note for wave files, we can just send data from the file right to the server.
// In the case you are not an audio file in wave format, and instead you have just
// raw data (for example audio coming over bluetooth), then before sending up any
// audio data, you must first send up an SpeechAudioFormat descriptor to describe
// the layout and format of your raw audio data via DataRecognitionClient's sendAudioFormat() method.
int bytesRead = 0;
byte[] buffer = new byte[1024];
try
{
do
{
// Get more Audio data to send into byte buffer.
bytesRead = fileStream.Read(buffer, 0, buffer.Length);
// Send of audio data to service.
this.dataClient.SendAudio(buffer, bytesRead);
}
while (bytesRead > 0);
}
finally
{
// We are done sending audio. Final recognition results will arrive in OnResponseReceived event call.
this.dataClient.EndAudio();
}
}
}
void ErrorHandler(object sender, SpeechErrorEventArgs e)
{
Console.WriteLine(e.SpeechErrorText);
}
void ResponseHandler(object sender, SpeechResponseEventArgs e)
{
if(e.PhraseResponse.RecognitionStatus == RecognitionStatus.EndOfDictation || e.PhraseResponse.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout)
{
Console.WriteLine("Trnascription Over");
Console.ReadKey();
Environment.Exit(0);
}
for(int i = 0; i < e.PhraseResponse.Results.Length; i++)
{
Console.Write(e.PhraseResponse.Results[i].DisplayText);
}
Console.WriteLine();
}
void PartialHandler(object sender, PartialSpeechResponseEventArgs e)
{
}
}
}
Thanks in advance for any help.
so you are probably ok with using https ...
we are revisiting the SDKs right now (restructuring/reorganizing). I expect updates in the next couple of months.
Wolfgang
The new speech service SDK supports Custom Speech Service out-of-box. Please also check the samples RecognitionUsingCustomizedModelAsync() here for details.
I am super impressed with the new Firebase and auth options in that. But what if I want to create my own userID-password system to create a user? Like for example I authenticate the user with his phone number (using something like Fabric's Digits) and use that to create an user account. Now, how can I do this in the new Google's firebase? Or is it even doable?
Right now it cannot be done directly, but you could validate the user with Digits, send the security headers to a backend Web Service you developed in which you can create a email/password user using as email phone_number#yourdomain.com and as password a string you randomly created, and using firebase custom authentication to give your end users tokens to reauthenticate, all this would seem as phone authentication to the end user, and he would'n even know he is using a email/password auth to sign in
I've used a simpler method of phone number authentication, by writing my login function to accept the mobile no as input.
and then appending a common domain name to the end of the mobileno in your login.ts function - (everytime you call the authentication methods)
9xxx9#mobileappdomain.com
You don't need to use a 3rd Party Web Service for this, nor even the custom authentication Methods in Firebase.
Simply use the standard email/password authentication in Firebase with very little code change, by appending the email domain to the mobile no and handle it in your code.
login() {
this.login.mobileno = this.login.mobileno + '#appdomain.com';
this.auth.signin(this.login)
.then((data) => {
...............
............................
}
}
Firebase is now supporting phone number authentication.
https://firebase.google.com/docs/auth/ios/phone-auth
now phone auth is available in firebase.Here is Code for Phone Auth using Firebase:
EditText phoneNum,Code; // two edit text one for enter phone number other for enter OTP code
Button sent_,Verify; // sent_ button to request for verification and verify is for to verify code
private PhoneAuthProvider.ForceResendingToken mResendToken;
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;
private FirebaseAuth mAuth;
private String mVerificationId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_phone_number_auth);
phoneNum =(EditText) findViewById(R.id.fn_num);
Code =(EditText) findViewById(R.id.code);
sent_ =(Button)findViewById(R.id.sent_nu);
Verify =(Button)findViewById(R.id.verify);
callback_verificvation();
mAuth = FirebaseAuth.getInstance();
sent_.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String num=phoneNum.getText().toString();
startPhoneNumberVerification(num); // call function for receive OTP 6 digit code
}
});
Verify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String code=Code.getText().toString();
verifyPhoneNumberWithCode(mVerificationId,code); //call function for verify code
}
});
}
private void startPhoneNumberVerification(String phoneNumber) {
// [START start_phone_auth]
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mCallbacks); // OnVerificationStateChangedCallbacks
// [END start_phone_auth]
}
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
FirebaseUser user = task.getResult().getUser();
Toast.makeText(getApplicationContext(), "sign in successfull", Toast.LENGTH_SHORT).show();
// [START_EXCLUDE]
// [END_EXCLUDE]
} else {
// Sign in failed, display a message and update the UI
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
// [START_EXCLUDE silent]
// [END_EXCLUDE]
}
// [START_EXCLUDE silent]
// Update UI
// [END_EXCLUDE]
}
}
});
}
private void verifyPhoneNumberWithCode(String verificationId, String code) {
// [START verify_with_code]
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
// [END verify_with_code]
signInWithPhoneAuthCredential(credential);
}
private void callback_verificvation() {
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential credential) {
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verificaiton without
// user action.
// [START_EXCLUDE silent]
// [END_EXCLUDE]
// [START_EXCLUDE silent]
// Update the UI and attempt sign in with the phone credential
// [END_EXCLUDE]
signInWithPhoneAuthCredential(credential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
// [START_EXCLUDE silent]
// [END_EXCLUDE]
if (e instanceof FirebaseAuthInvalidCredentialsException) {
// Invalid request
// [START_EXCLUDE]
// [END_EXCLUDE]
} else if (e instanceof FirebaseTooManyRequestsException) {
// The SMS quota for the project has been exceeded
// [START_EXCLUDE]
// [END_EXCLUDE]
}
// Show a message and update the UI
// [START_EXCLUDE]
// [END_EXCLUDE]
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
// Save verification ID and resending token so we can use them later
mVerificationId = verificationId;
mResendToken = token;
// [START_EXCLUDE]
// Update UI
// [END_EXCLUDE]
}
};