This might seem a duplicate but I couldn't find an answer or solution for my problem.
I have a screen on my Flutter app where I choose a file from the phone's file system (in Asynchronous way via file_picker).
When I choose a file I'd like to make the 'Next' button enabled.
However, I could not manage to do that.
I tried with a boolean expression and a boolean function but with no success because the build function happens before the user picks a file(By clicking on a button to open the file picker).
I tried several solutions:
onPressed: upload_flag ? () => myAction() : null,
but when updating the flag after the file picking, it won't enable it.
This is how the file picking functions and checking functions look:
File _scanned_file = null;
bool upload_flag = false;
void isUploaded() {
if (_scanned_file != null) {
upload_flag = true;
}
else{
upload_flag = false;
}
}
Future<bool> chooseFile() async {
_scanned_file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf', 'png'],
);
isUploaded();
}
I have tried many different methods with no success.
Any tips and help will be super helpful!
Thank you all!
Have you tried setState?
void isUploaded() {
if (_scanned_file != null) {
setState(() {
upload_flag = true;
});
} else {
setState(() {
upload_flag = false;
});
}
}
void isUploaded() {
if (_scanned_file != null) {
upload_flag = true;
}
upload_flag = false;
}
In this method, you are always setting upload_flag to false even after just setting it to true in case the condition is true. Also, you need to call setState() for the change to reflect in the UI. Need to change to..
void isUploaded() {
setState(() {
if (_scanned_file != null) {
upload_flag = true;
} else {
upload_flag = false;
}
});
}
Related
I would to check if my Live Wallpaper App is set as Live Wallpaper.
The following code works on Android <= 12, but not in Android 13 (sdk 33).
public static boolean isLiveWallpaper(Context context) {
if (Service._handler == null) {
return false;
}
WallpaperManager wpm = WallpaperManager.getInstance(context);
WallpaperInfo info = wpm.getWallpaperInfo();
try {
return (info != null && info.getPackageName().equals(context.getPackageName()));
} catch (Exception e) {
return false;
}
}
On Android 13 wpm.getWallpaperInfo() always return null.
Why? I searched on Google and on the Android Developer Documentation, but I did'n find anything...
Edit:
I set the live wallpaper with this code and it works, but I can't check programmatically if the live wallpaper is setted.
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(context, Service.class));
context.startActivity(intent);
Check the source code of WallpaperManagerService.java
public WallpaperInfo getWallpaperInfo(int userId) {
final boolean allow =
hasPermission(READ_WALLPAPER_INTERNAL) || hasPermission(QUERY_ALL_PACKAGES);
if (allow) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
synchronized (mLock) {
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper != null && wallpaper.connection != null) {
return wallpaper.connection.mInfo;
}
}
}
return null;
}
We can see some permissions are needed to query the wallpaper info.
So, please add the following permission request in your AndroidManifest.xml
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
There is a bug reported to Google. I'm not sure if Google is going to fix it. This is the workaround I've been using. LiveWallpaperService.isEngineRunning can tell your app is set as LiveWallpaper or not.
class LiveWallpaperService : WallpaperService() {
...
class MyEngine : WallpaperService.Engine() {
...
override fun onCreate(surfaceHolder: SurfaceHolder) {
if (!isPreview) {
isEngineRunning = true
}
}
override fun onDestroy() {
if (!isPreview) {
isEngineRunning = false
}
}
}
companion object {
var isEngineRunning = false
}
}
I'm using a webview in xamarin, i followed many tutorials to handle navigation, and all works fine.
My issue is : when an anchor tag has a target="_blank" the event Navigating is never fired.
I see arround someone give a javascript solution which remove target=_blank and attach it at the end of href link.
Is really that the right way to do that? Look wired..
Thank you
This is initialization in xamarin.android renderer
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
global::Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
((HybridWebView)Element).Cleanup();
}
if (e.NewElement != null)
{
Control.Settings.JavaScriptEnabled = true;
Control.Settings.DomStorageEnabled = true;
Control.Settings.JavaScriptCanOpenWindowsAutomatically = true;
Control.Settings.SetSupportMultipleWindows(true);
Control.Settings.AllowFileAccessFromFileURLs = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.UserAgentString = Control.Settings.UserAgentString + " crmvw";
Android.Webkit.WebChromeClient xCC = new CustChromeWebViewClient(_context);
Control.SetWebChromeClient(xCC);
Control.SetWebViewClient(new CrmWebViewClient(this, $"javascript: {JavascriptFunction}"));
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl(((HybridWebView)Element).Uri);
}
}
And this is my navigating event, never fired when anchor has target=_blank
private void webv_Navigating(object sender, WebNavigatingEventArgs e)
{
if (IsFirstLoad) {
IsBusy = true;
IsFirstLoad = false;
}
if (e.Url.ToLower().StartsWith("tel:") || e.Url.ToString().StartsWith("wtai:") || e.Url.ToLower().StartsWith("sms:") || e.Url.ToLower().StartsWith("mailto:"))
{
e.Cancel = true;
}
}
here my override function for URL in my custom WEBView
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, Android.Webkit.IWebResourceRequest request)
{
Android.Net.Uri url = request.Url;
if (url.ToString().StartsWith("tel:") || url.ToString().StartsWith("wtai:"))
{
Xamarin.Essentials.PhoneDialer.Open(UtilityXam.Contact.GetPhoneFromHTML(url.ToString()));
return true;
}else if (url.ToString().StartsWith("mailto:"))
{
UtilityXam.Contact xE = new UtilityXam.Contact();
string xEmail = UtilityXam.Contact.GetEmailFromHTML( url.ToString());
var xTask = xE.SendEmail("","",new System.Collections.Generic.List<string>(){ xEmail });
return true;
}
else if (url.ToString().StartsWith("sms:"))
{
UtilityXam.Contact xE = new UtilityXam.Contact();
string xPh = UtilityXam.Contact.GetPhoneFromHTML(url.ToString());
var xTask = xE.SendSMS("", "", new System.Collections.Generic.List<string>() { xPh });
}
else
{
view.LoadUrl(url.ToString());
}
view.SetDownloadListener(new CrmDownloadListener(_context));
return true;
}
After the great help of Jack Hua i'm able to solve the problem.
In OnElementChanged of Hybrid renderer i set support for multiple windows.
Control.Settings.SetSupportMultipleWindows(true);
and next i had to menage onCreateWindow event in the custom chrome webview.
Here the code converted in c# from the link suggested by Jack.
public override bool OnCreateWindow(Android.Webkit.WebView view, bool isDialog, bool isUserGesture, Android.OS.Message resultMsg)
{
Android.Webkit.WebView newWebView = new Android.Webkit.WebView(_context);
view.AddView(newWebView);
Android.Webkit.WebView.WebViewTransport transport = (Android.Webkit.WebView.WebViewTransport) resultMsg.Obj;
transport.WebView = newWebView;
resultMsg.SendToTarget();
return true;
}
This is an introduced bug in Xamarin Forms since v4.8.0.1364 (According to the bug report at least)
You can work around it for now by removing the target="_blank" from the url or by setting a property
webView.Settings.SetSupportMultipleWindows(true);
I have fixed it for our app by striping target="_blank" and target='_blank' in some replacement logic that already runs over the content
There are multiple open issues reporting it for Xamarin Forms github
[Bug] Cannot open URLs with WebView android when the target is _blank #12917
[Bug] Android WebView's Navigating and Navigated events not fired #12852
I tried a completely different approach, because the above answers didn't really help (my target _blank links would always open in a new chrome instance and not in the in-app browser).
First, you'll need to set SetSupportMultipleWindows to false. As soon as you do that, all the windows will open in the same webView:
Control.Settings.SetSupportMultipleWindows(false);
More information on how you set these settings: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview
Next, all I did was change the back-button behaviour, to make sure the back button doesn't close the app and instead navigates the webview pages (HybridWebView is my custom webview that I created in the first step).
HybridWebView _browser;
public MainPage()
{
_browser = new HybridWebView
{
Source = "https://brandschutzplaner-stahltragwerke.promat.ch"
};
Content = _browser;
}
protected override bool OnBackButtonPressed()
{
base.OnBackButtonPressed();
if (_browser.CanGoBack)
{
_browser.GoBack();
return true;
}
else
{
base.OnBackButtonPressed();
return true;
}
}
I am trying to turn on hardware acceleration for my application
but I never seem to get a 'true' result from this function.
I tried all the methods in the Android Developers blog post about the
the tag android:hardwareAccelerated=true to the application
and even called
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
You should always call isHardwareAccelearted() after the view is attached to the window. I am not sure about your case as I can't see where actually you are calling it.
Also, the support level of various operations across API levels are mentioned here. I hope this helps.
You can also try this method to verify hardwareAcceleration.
public static boolean hasHardwareAcceleration(Activity activity) {
// Has HW acceleration been enabled manually in the current window?
Window window = activity.getWindow();
if (window != null) {
if ((window.getAttributes().flags
& WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
return true;
}
}
// Has HW acceleration been enabled in the manifest?
try {
ActivityInfo info = activity.getPackageManager().getActivityInfo(
activity.getComponentName(), 0);
if ((info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
Log.e("Chrome", "getActivityInfo(self) should not fail");
}
return false;
}
For checking for View try this.
chat_wv.post(new Runnable() {
#Override
public void run() {
Log.e("isHardwareAccelerated", ""+chat_wv.isHardwareAccelerated());
}
});
I want to check that Rectangle was tapped. This mehod does the job and it works almost how I want:
private bool CheckRectangleTouch(Rectangle target)
{
var touchCollection = TouchPanel.GetState();
if (touchCollection.Count > 0)
{
foreach (var touch in touchCollection)
{
if (target.Contains(touch.Position))
{
return true;
}
}
}
return false;
}
Problem I have is that after I've tapped rectangle it keeps returning true until I release it (it can register 10-30 times for one tap) and I want it to return true just once - for the first touch.
I've tried this (replace code inside foreach):
var isFirstTouch = !touch.TryGetPreviousLocation(out _);
if (target.Contains(touch.Position) && isFirstTouch)
{
return true;
}
And this (bad one, I don't really want it to register after release):
if (target.Contains(touch.Position) && touch.State == TouchLocationState.Released)
{
return true;
}
But nothing is does it. Either logic is not consistent or doesn't work at all.
So how do I check for tap?
Update: this works but it's very hacky, has delay and gives me random phantom taps:
try
{
var tap = TouchPanel.ReadGesture(); // falls each time when no input
return tap.GestureType == GestureType.Tap && target.Contains(tap.Position);
}
catch { }
return false;
Here's what I ended up doing:
I have singleton to hold my game state (many different props updated as needed). I added to it:
public TouchCollection TouchCollection { get; set; }
Prop to hold TouchPanel.GetState result. I fill it in Games Update method once per frame, as #craftworkgames suggested:
State.TouchCollection = TouchPanel.GetState();
Also I added this prop to my game state:
public bool TouchActive { get; set; }
And this is the method to check for rectangle tap. It returns true only for the first contact in tap:
private bool CheckRectangleTap(Rectangle target)
{
if (State.TouchCollection.Count == 0)
{ // if no input
return State.TouchActive = false;
}
var targetTouched = false;
foreach (var touch in State.TouchCollection)
{
if (target.Contains(touch.Position))
{
targetTouched = true;
}
}
if (targetTouched && !State.TouchActive)
{ // if target is touched and it's first contact
return State.TouchActive = true;
}
return false;
}
It doesn't seem ideal but it works for my case.
In Xamarin Native Android app I am calling methodOne() and getting some details. After this I want to updated the details to text view and then calls the methodTwo(). After executing MethodTwo I have to clear the text details from text view. I tried with
RunOnUiThread(() => tColorDetail.SetText("text", TextView.BufferType.Normal));
The details are displaying after finishing all the methods it is not showing immediately after executing MethodOne().
What is missing here?
.....................................................
public class MainActivity : Activity
{
int count = 1;
ticket Ticket;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button bClick= FindViewById<Button>(Resource.Id.bSub);
try {
bClick.Click += delegate {
Job Job;
Action act = new Action();
EditText Address = (EditText)FindViewById(Resource.Id.Address);
act.Address = Address.Text.ToString();
if (!ValidateIPv4(act.Address))
{
ShowMessage("Invalid IP");
}
else
{//TextView Mode = (TextView)FindViewById(Resource.Id.Mode);
string httpUrl = act.iPAddress ;
Ticket = act.ExecuteTicket(httpUrl, "Ticket");
//RunOnUiThread(() => tColorMode.SetText("text", TextView.BufferType.Normal));
// this.RunOnUiThread(() => setTicket(true));
setStatus(" Ticket : Success", true);
setTicket(true);
//tColorMode.SetText("text",TextView.BufferType.Normal);
//tColorMode.Invalidate();
Job = act.executeJob(httpUrl, Ticket);
setStatus(" Job : Success", true);
act.File(httpUrl, Ticket, Job);
setStatus("File Retrieval : Success", true);
setTicket(false);
setStatus("File Retrieval : Success", false);
}
};
}
catch (Exception ex)
{
ShowMessage(ex.Message.ToString());
}
}
public bool ValidateIPv4(string ipString)
{
if (String.IsNullOrWhiteSpace(ipString))
{
return false;
}
string[] splitValues = ipString.Split('.');
if (splitValues.Length != 4)
{
return false;
}
return true;
}
public void setTicket(bool b)
{
//TextView tMode = (TextView)FindViewById(Resource.Id.tMode);
// tMode.SetText("text",TextView.BufferType.Normal);
RunOnUiThread(() => {
TextView tMode = (TextView)FindViewById(Resource.Id.Mode);
tColorMode.SetText("text",TextView.BufferType.Normal);// b==true?Ticket.getProcessing():"";
((TextView)this.FindViewById(Resource.Id.tRes)).Text = b == true ? Ticket.getHeight().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tFormat)).Text = b == true ? Ticket.getFormat().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tOrode)).Text = b == true ? Ticket.getType().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tRot)).Text = b == true ? Ticket.getValue().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSource)).Text = b == true ? Ticket.getSource().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSize)).Text = b == true ? Ticket.getAutoDetect().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tExpo)).Text = b == true ? Ticket.getAuto().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSharp)).Text = b == true ? Ticket.getSharp().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tComp)).Text = b == true ? Ticket.getComp().ToString() : "";
//tColorMode.Invalidate();
}); }
private void ShowMessage(string msg)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog = builder.Create();
dialog.SetMessage(msg);
dialog.SetButton("OK", (s, ev) =>
{
dialog.Cancel();
});
dialog.Show();
}
private void setStatus(string status,bool b)
{
((TextView)this.FindViewById(Resource.Id.tStatus)).Text = b == true ? status : " ";
}
}
Without access to the full code it is tricky to give you an answer but
Ticket = act.ExecuteTicket(httpUrl, "Ticket");
this line has the potential to take a while to complete if it performs network operations and probably runs in a background thread not to freeze the UI.
Presumably when you get to
// this.RunOnUiThread(() => setTicket(true));setStatus(" Ticket : Success", true);
setTicket(true);
the act.ExecuteTicket call might not have finished
also if there are async operations taking place in
Job = act.executeJob(httpUrl, Ticket);
it could take a while to complete
All taken into consideration, you could probably be getting to
setTicket(false);
setStatus("File Retrieval : Success", false);
before the first calls finish
It could be worth checking
ANSWER UPDATE after discussion in comments:
Since your problem is that your asynchronous calls are taking a long time and you are experiencing "race conditions" because of it (your UI thread is proceeding with the updates on the TextViews before it should), you can solve the situation by changing your button click delegate to an async delegate, and forcing an await on the long operations' result before proceeding.
bClick.Click += async delegate {
//...
Job = await act.executeJob(httpUrl, Ticket);
//...
}