iOS phone link opening message app instead of calling the number - c#

I want a phone number from a TextView to call the phone number when clicked:
The issue I am facing is that when clicking the link, the message app is opening instead. I tried the following code in iOS 12 and it worked as expected, but when I try on iOS 13 and 14, the message app opens instead of making a call using the "phone dialer app".
Tentative 1:
textView.Editable = false;
textView.DataDetectorTypes = UIDataDetectorType.PhoneNumber;
Tentative 2:
var phoneNumberLink = new Dictionary<string, string>(){ { "(855) 757-7328","tel:8557577328" } }
textView.Editable = false;
textView.SetAttributedTextForLinks("Please call us at (855) 757-7328", phoneNumberLink);

Actually, telpromt://0123456789 also did not work. I had to intercept the interaction with URL, the recommended ShouldInteractWithUrl did not work (ShouldInteractWithUrl was not triggered or called), so I had to use AllowUrlInteraction instead. The code looked something like this:
var description = new KiteEmbeddedLinkTextView()
{
Editable = false,
DataDetectorTypes = UIDataDetectorType.PhoneNumber,
Text = message.MessageText
};
description.AllowUrlInteraction += AllowUrlInteraction;
private bool AllowUrlInteraction(UITextView textView, NSUrl url, NSRange characterRange, UITextItemInteraction interaction)
{
UIApplication.SharedApplication.OpenUrl(url);
return false;
}
For some reason none of the previous options worked for me, besides this one.
See:
https://forums.xamarin.com/discussion/60345/uitextview-and-clickable-phonenumbers
How to intercept click on link in UITextView?

As mentioned https://forums.xamarin.com/discussion/33798/open-phone-dialer-from-app
The correct way to open the dialer is
telprompt://0123456789
Make sure that there are no spaces.

Related

UIDocumentPickerViewController.ModalPresentationStyle can't be changed in iOS 16.1

I've got a app that depends on Xamarin.IOS.
It at some point can display a document picker as a popover.
After updating to XCode14 and doing a build for iOS16 I found the document picker was displaying incorrectly (In its FormSheet style rather than in the Popover style).
The reason for this seems to be that attempting to change ModalPresentationStyle is silently failing and remaining as the same default value - FormSheet.
Reproduced it outside of the app in a simple test app with a single button click handler.
Here I'd expect the ModalPresentationStyle to change or at least throw some sort of an error if not supported. Instead, it silently remains as UIModalPresentationStyle.FormSheet.
partial void BtnClick(UIKit.UIButton sender)
{
var allowedUtis = new List<string>() { ".txt" };
var documentPicker = new UIDocumentPickerViewController(
allowedUtis.ToArray(),
UIDocumentPickerMode.Import);
var previousValue = documentPicker.ModalPresentationStyle;
documentPicker.ModalPresentationStyle = UIModalPresentationStyle.Popover;
Debug.WriteLine($"Changed from {previousValue} to {documentPicker.ModalPresentationStyle}");
if (documentPicker.PopoverPresentationController != null)
{
documentPicker.PopoverPresentationController.SourceView = sender;
documentPicker.PopoverPresentationController.SourceRect = sender.Bounds;
documentPicker.PopoverPresentationController.PermittedArrowDirections = UIPopoverArrowDirection.Up;
}
PresentModalViewController(documentPicker, true);
}
Also reproduced this same behaviour in a test app in swift to check it wasn't Xamarin.IOS that was the problem. Again here the value of modalPresentationStyle remains as .formSheet (2).
let supportedTypes: [UTType] = [UTType.audio]
let pickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true) 1017
print(String(describing: pickerViewController.modalPresentationStyle));
pickerViewController.modalPresentationStyle = .popover
print(String(describing: pickerViewController.modalPresentationStyle));
self.present(pickerViewController, animated: true, completion: {})
This didn't happen on XCode13 but does on XCode14.01 on an 8th gen iPad running iOS 16.1.
Can't be reproduced on XCode14.01 with a simulator running iOS 16.0.
Has the expected behavior changed? I can't seem to find anything in the release notes of documentation about this.
I ran into the same basic issue recently myself. The solution is to setup the popoverPresentationController after you present the modal view controller.
let supportedTypes: [UTType] = [UTType.audio]
let pickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true) 1017
print(String(describing: pickerViewController.modalPresentationStyle));
pickerViewController.modalPresentationStyle = .popover
print(String(describing: pickerViewController.modalPresentationStyle));
self.present(pickerViewController, animated: true)
pickerViewController.popoverPresentationController?.sourceRect = sender.bounds
pickerViewController.popoverPresentationController?.sourceView = sender
pickerViewController.popoverPresentationController?.permittedArrowDirections = .up
The view controller's popoverPresentationController is nil before the call to present. At least that is the case under iOS 16.
While I didn't test this specifically with UIDocumentPickerViewController, this solution worked for a general modal view controller I was trying to present. The view controller would appear as a form sheet, despite being set as a popover, if the popoverPresentationController was setup before the call to present instead of after.

How to get all enabled keyboard in xamarin.forms with C#

Good day,
in android phone -> virtual keyboard, system list all the enabled keyboards in this page, how can i get all enabled keyboards type with C# in my Xamarin.forms APP?
Thanks!
Roll
In Android, you could use InputDevice.
InputDevice: https://developer.android.com/reference/android/view/InputDevice
You could try the code below:
int[] devicesIds = InputDevice.GetDeviceIds();
foreach (var item in devicesIds)
{
//Check the device you want
InputDevice device = InputDevice.GetDevice(item);
//device.getName must to have virtual
var s = device.Name;
var b = device.KeyboardType;
}
You could use DependencyService to call this in Xamarin.Forms.
DependencyService: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction
thanks your reply, i try the way you suggested, but the returned value was not i want...
i found another post here, use that way and finally get the things i want,
here is my code to share:
InputMethodManager manager = (InputMethodManager)context.GetSystemService(Context.InputMethodService);
IList<InputMethodInfo> mInputMethodProperties = manager.EnabledInputMethodList;
IEnumerator<InputMethodInfo> imi = mInputMethodProperties.GetEnumerator();
while (imi.MoveNext())
{
InputMethodInfo inputInfo = imi.Current;
var iN = inputInfo.ServiceName;
}
Best Regards & thanks
Roll

Selenium can't handle multiple ChromiumWebBrowser instances in C#

I have two instances of the ChromiumWebBrowser in my WinForms project (Visual Studio 2012). My goal is to have the second browser instance "copy" the behavior of the user input in the first browser instance. I can successfully retrieve the input from the first browser, and I managed to hook up Selenium in the project as well.
However, I'm having one issue. Whenever Selenium sends its commands, the first browser is the one that responds to them. For the life of me, I can't seem to figure out how to make the second browser respond. Whenever I completely remove the first browser, the second one starts responding correctly, but adding the first browser again will make only have the first browser use the Selenium commands. I even tried to switch out the moments the browsers are added to the form, but to no avail: whenever there are two available, the wrong one is responsive.
Relevant code:
public BrowserManager(Controller controller, string startingUrl)
{
_controller = controller;
var settings = new CefSettings { RemoteDebuggingPort = 9515 };
Cef.Initialize(settings);
// Input browser
inputBrowser = new ChromiumWebBrowser(startingUrl);
var obj = new XPathHelper(this);
inputBrowser.RegisterJsObject("bound", obj); //Standard object registration
inputBrowser.FrameLoadEnd += obj.OnFrameLoadEnd;
// Output browser
var browserSettings = new BrowserSettings();
var requestContextSettings = new RequestContextSettings { CachePath = "" };
var requestContext = new RequestContext(requestContextSettings);
outputBrowser = new ChromiumWebBrowser(startingUrl);
outputBrowser.RequestContext = requestContext;
outputBrowser.AddressChanged += InitializeOutputBrowser;
outputBrowser.Enabled = false;
outputBrowser.Name = "outputBrowser";
}
The selenium part:
public class SeleniumHelper
{
public SeleniumHelper()
{
DoWorkAsync();
}
private Task DoWorkAsync()
{
Task.Run(() =>
{
string chromeDriverDir = #"ActionRecorder\bin\x64\Debug\Drivers";
var chromeDriverService = ChromeDriverService.CreateDefaultService(chromeDriverDir);
chromeDriverService.HideCommandPromptWindow = true;
ChromeOptions options = new ChromeOptions();
options.BinaryLocation = #"ActionRecorder\bin\x64\Debug\ActionRecorder.exe";
options.DebuggerAddress = "127.0.0.1:9515";
options.AddArguments("--enable-logging");
using (IWebDriver driver = new OpenQA.Selenium.Chrome.ChromeDriver(chromeDriverService, options))
{
driver.Navigate().GoToUrl("http://www.google.com");
var query = driver.FindElement(By.Name("q"));
query.SendKeys("A google search test");
query.Submit();
}
});
return null;
}
}
And finally, a screenshot for some visualization:
Some help with the issue would be very much appreciated. If i missed some crucial info, feel free to ask for it. Thanks in advance!
Greetz,
Tybs
The behavior is correct. You have one debug address and you can only have one debug address for CEF. Which means when you use Selenium it is only seeing one browser.
By default Selenium will send an command to current active Tab or Window. Now in your case you have multiple Chrome view embedded, but they are technically Chrome Tab/Windows which you have placed on the same form.
So if you are in luck below code in should be able to move you to the Window you are interested in
driver.SwitchTo().Window(driver.WindowHandles.Last());
See if it works. If it doesn't then your only other workaround would be to change the order of Adding ChromiumWebBrowser and that should reverse the window it works on.
Below are some important threads that you should read from top to bottom. Very relevant to your issue/request
https://code.google.com/archive/p/chromiumembedded/issues/421
https://github.com/cefsharp/CefSharp/issues/1076

Issues authenticating with Facebook sdk .net - blank white screen in browser

I am having issues with Authentication in my Windows Phone 7 app using Facebook SDK .net
here is the authentication part
var facebookClient = new FacebookClient();
facebookClient.AppId = FacebookAppId;
facebookClient.AppSecret = FacebookSecret;
var authUrl = facebookClient.GetLoginUrl(new
{
client_id = FacebookAppId,
client_secret = FacebookSecret,
scope = "publish_stream",
response_type = "token",
display = "touch",
redirect_uri = "https://www.facebook.com/connect/login_success.html"
});
browser.Navigate(authUrl);
So the browser screens seem to work fine, login screen shows and then the permissions screens show. When I press OK on the last permission screen I just get a white screen. In fact I have been staring at this white screen for 10mins now.
Any ideas?
Here is the Browser.Navigated event handler. I have commented where I have put breakpoints
async void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
FacebookOAuthResult result;
var facebookClient = new FacebookClient(); // Put break point here to make sure the event is handled
if(facebookClient.TryParseOAuthCallbackUrl(e.Uri, out result))
{
if (result.IsSuccess) // Put break point here to check result but its never reached
{
Logging.WriteLine("Authentication was a success!");
Classes.Facebook.Instance.AccessToken = result.AccessToken;
CreateFacebookPost();
}
else
{
MessageBox.Show(string.Format("Error: {0}\nReason:{1}", result.ErrorDescription, result.ErrorReason), "Authentication Error", MessageBoxButton.OK);
Logging.WriteLine("Authentication Failed");
Logging.WriteLine(string.Format("Error: {0}\nReason:{1}", result.ErrorDescription, result.ErrorReason));
}
browser.Visibility = System.Windows.Visibility.Collapsed;
browser.Navigated -= browser_Navigated;
}
}
EDIT 1:
Just some more info. I know the authentication (from Facebooks view) is a success as I can now see the app on my Facebook. Also, if I push back on the phone to go to previous screen of the app and then go back into the facebook section it shows everything is ok and I can make posts.
EDIT 2:
Using very similar code, this works fine in a Windows Phone 8 app. I have compared the 2 and can't seen any difference.
Looks like I have found the solution. You have to set IsScriptedEnabled=True on the WebBrowser control. By default it is false.

Setting Value of an Input Tag in WebBrowser Control

I am attempting to help a user log into their account using a custom WebBrowser control. I am trying to set the value of an input tag to the players username using the WebBrowser's InvokeScript function. However, my current solution is doing nothing but rendering a blank white page.
My current code looks like this (web is the name for my WebBrowser control):
web.Navigate(CurrentURL, null, #"<script type='text/javascript'>
function SetPlayerData(input) {
username.value = input;
return true;
}
</script>");
web.Navigated += (o, e) =>
{
web.IsScriptEnabled = true;
web.InvokeScript("SetPlayerData", #"test");
};
As mentioned, this does not work right now. I am attempting to do this on Windows Phone so a number of the example's I have found here and in other places will not work as I do not have access to the same functions.
How would I perform this successfully?
EDIT: Perhaps I was not clear, but I am working with Windows Phone, which has a limited API available meaning I do not have access to the Document property and a number of other functions. I do have access to InvokeScript, but not much more.
webBrowser1.Document.GetElementById("navbar_username").InnerText ="Tester";
webBrowser1.Document.GetElementById("navbar_password").InnerText = "xxxxxxxxxxx";
foreach (HtmlElement HtmlElement1 in webBrowser1.Document.Body.All)
{
if (HtmlElement1.GetAttribute("value") == "Log in")
{
HtmlElement1.InvokeMember("click");
break;
}
}
you may find more here : http://deltahacker.gr/2011/08/15/ftiakste-to-diko-sas-robot/
It's been along time since this question is posted but I think I'll post an answer to this so that it will help some one who came across the same situation
try
{
webBrowser1.Document.GetElementById("navbar_username").SetAttribute("value", "your user");
webBrowser1.Document.GetElementById("navbar_password").SetAttribute("value", "your pass");
webBrowser1.Document.GetElementById("Log in").InvokeMember("click");
}
catch { }

Categories