Google-Apps-Script gadget in Sites inconsistent on iOS device - mobile

I am creating UI in Google Sites by inserting a google apps script Gadget. Things work well on my desktop, but when I access the site on my iPhone or iPad, then I get intermittent UI behavior. That is, my buttons or text boxes do not respond every time these are touched.
I have broken this down to the basic code for my script, below, and still see this.
Thanks for your time - Larry King
function doGet() {
var eventApp = UiApp.createApplication();
var eventIDBox = eventApp.createTextBox();
var eventButton = eventApp.createButton("Submit");
var eventLabel = eventApp.createLabel("Welcome").setVisible(false);
var eventHandler = eventApp.createClientHandler().forTargets(eventLabel).setVisible(true);
eventButton.addClickHandler(eventHandler);
eventApp.add(eventIDBox).add(eventButton).add(eventLabel);
return eventApp;
}

This happens because in iOS, the first tap goes in selecting the iFrame housing the UI and the second goes to the actual UI control. This is a known issue and is recorded in Issue 1086. Please star the issue to register your interest for a solution.

Related

Codenameone: AppArg is null on ios when app open via applink

When opening my ios app via an applink, as specified by associated domains feature, the AppArg is null.
The consecutive call of start() method, as described in this issue, does not occur.
In my case, start() is called only once, with a null AppArg, and that's it.
The first thing a do, in the start() method, is call
Display.getInstance().getProperty("AppArg",null);
This works fine when opening the app via a custom scheme, but not when opening via an applink.
Note: I use the ios.glAppDelegateBody and ios.afterFinishLaunching build hints to handle app open via push notification. I figured this might interfere with AppArg reading so I removed those temporarily and tried again, but to no avail.
Currently, the only solution I see is to write some native code and try to get the opening url this way, but I'd very much like for the AppArg to work as it states.
I've tested on iphone 6s with ios 15.1.
Update 3:
This problem occurs due to the call of the facebook sdk in the didFinishLaunchingWithOptions which causes the method to return NO, and that prevents continueUserActivity to execute and retrieve the launch url. The offending code is this:
return [[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
This code gets executed if the facebook.appIdbuild hint is present in the codenameone settings.
After I removed it, things started working.
However, you won't be able to do this if you actually use facebook connect.
Update 2
I added the following snippet to the apple-app-site-association file hosted on my domain, as per the documentation here.
"activitycontinuation": {
"apps": [ <id of my app> ]
}
It didn't work still.
The same documentation also states the an associated domain entitlement like this: activitycontinuation:example.com should be added. So I added it to the ios.associatedDomains build hint, along with the applinks, looking like this:
ios.associatedDomains=applinks:mydomain.com,activitycontinuation:mydomain.com
It still didn't work. The build suceeded, but I'm not sure that codename one is actually doing something with activitycontinuation service.
So, the problem is still not solved!
Update:
So, the flow start,stop,start only happens when the app is in background and gets opened via an applink click, and both times start is called with the AppArg populated with the applink. All well in this case.
However, if the app is closed, and opepend via applink click, start is called only once and the AppArg is null. Problem!
The method shouldApplicationHandleURL is never called. I implemented it on the main app class, returning true.
I have also tried adding native code to try to get the applink, for the case when the app was previously closed. I tried to add the code below to the glAppDelegateBody build hint, but the build failed complaining that the continueUserActivity is duplicate. The code used was something like this:
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
NSURL *url = userActivity.webpageURL;
// Handle url
return YES;
}
Currently, I'm running out of ideas. So, please, help. Thank you.
iOS uses a different mechanism for dealing with applinks than it does for custom app URL schemes, so it is likely that there is a race condition here -where start() is being called before the URL is provided to the app.
Try implementing the com.codename1.system.URLCallback interface in your main lifecycle class and implement the shouldApplicationHandleURL method. This should be called when an applink is processed.
The solution, in my case, was to remove the facebook.appId build hint from the condenameone_settings.properties. I wasn't using facebook anymore, but forgot about the build hint. After removing it, things started working.
Found about this here.
By adding the following code to the ios.afterFinishLaunching build hint, the AppArg will be populated at start with the app launchUrl (if any), regardless of the fact that facebook sdk is used or not:
NSDictionary *activityDictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsUserActivityDictionaryKey];
if (activityDictionary) {
NSUserActivity *userActivity = [activityDictionary valueForKey:#"UIApplicationLaunchOptionsUserActivityKey"];
if (userActivity != nil) {
if ([NSUserActivityTypeBrowsingWeb isEqualToString:userActivity.activityType] && userActivity.webpageURL != nil) {
JAVA_OBJECT launchUrlStr = fromNSString(CN1_THREAD_GET_STATE_PASS_ARG [userActivity.webpageURL absoluteString]);
JAVA_OBJECT appArgKey = fromNSString(CN1_THREAD_GET_STATE_PASS_ARG #"AppArg");
JAVA_OBJECT displayInstObj = com_codename1_ui_Display_getInstance__(CN1_THREAD_GET_STATE_PASS_SINGLE_ARG);
com_codename1_ui_Display_setProperty___java_lang_String_java_lang_String(CN1_THREAD_GET_STATE_PASS_ARG displayInstObj, appArgKey, launchUrlStr);
}
}
}

Microsoft UI Automation for Web Application

Has anyone tried "Microsoft UI Automation" for web application?
I have a WPF application which has a embedded wpfbrowser.
Since this is basically a desktop app, I cant use Selenium Webdriver.
I tried CodedUI but i am facing a issue, Which i have asked here:
Coded UI - Unable to identify a html controls on a Wpfbrowser
I am planning to use UIAutomation, But again itseems that i am unable to identify a control using id property
Ex:
<button id="but1">Click Me</button>
For this i have:
PropertyCondition ps = new PropertyCondition(AutomationElement.AutomationIdProperty, "but1");
AutomationElement Clickme = elementMainWindow.FindFirst(TreeScope.Descendants, ps);
But this is not working. "Clickme" is null.
How to do this is UIAutomation??
EDIT: Attaching a screeshot:
I would try actually navigating the tree view down to the control you are looking for instead of doing it based on decedents. Also another thing you could try is doing a retry loop if it is null. Here is an example of a generic Retry for FlaUI. So your code would look something like this.
PropertyCondition ps = new PropertyCondition(AutomationElement.AutomationIdProperty, "but1");
Func<AutomationElement> func = () => elementMainWindow.FindFirst(TreeScope.Descendants, ps);
Predicate<AutomationElement> retry = element => element == null;
AutomationElement clickMe = Retry.While<AutomationElement>(func, retry, TimeSpan.FromSeconds(1));
So this code will retry finding the element for 1 second and will retry finding it if the element comes back null or it exceptions. If either of those happens it waits 200 milliseconds and tries again. This will tell me if the elements are just not rendered when you try to find them or if their is a difference between how inspect finds them and how System.Windows.Automation is finding them.
If this doesn't work I will post a solution using the tree walker but I suggest using this solution over the tree walker because if this was an application others would want to write automation against they would expect these functions to work the way you are attempting to use them.
Not sure if <button id="but1"> equals with automationId. You can set automation id using AutomationProperties.AutomationId="but1" if you can use that namespace in the code where you define your UI (XAML), which is probaly only for WPF applications.
In your case if your UI defined in HTML I think you can use the button's caption.
So something like this.
var ps = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.NameProperty, "Click Me"));
AutomationElement Clickme = elementMainWindow.FindFirst(TreeScope.Descendants, ps);
ControlTypeProperty can help in filtering results by type. Not mandatory, but it can help if you have automation elements with different type, but with same name property.

Rendering problems when saving multiple Dygraphs as a PNG on mobile devices

I have a web application that uses Dygraphs to create charts.
The application allows a user to create multiple Dygraph charts (each with their own Y-Axis) that will be stacked on top of each other.
Here's an example of what the multiple Dygraphs look like on a PC browser: Notice that the example displays three different Dygraphs each having their own Y-axis, but the X-axis is hidden for the top 2 charts and visible on the bottom chart.
I will allow the user to save the chart to disk as a PNG. - The way I currently save the multiple Dygraphs as one PNG is:
Create a target canvas that will be used to contain all the visible Dygraphs
Extract each canvas out of each Dygraph, then add each canvas to the target canvas **
Create a PNG via the .toDataURL() function on the target canvas
Here's an example of what the above screenshot looks like when saved as one PNG: (This is exactly what I want from the PNG)
The procedure works fine on browsers on a PC. But when I attempt to save the multiple Dygraphs into one PNG on a phone/tablet browser, the resultant PNG doesn't match the graph that is visible on the screen.
Example:
Here's what the multiple Dygraphs look like on an iPad (screenshot)
And here's what the resultant PNG looks like (Notice how the width and height of each chart does not match the actual iPad display).
I don't understand why the PNG is rendered correctly when I use a PC browser, but is not rendered correctly when I use a browser on a mobile device.
I'm not sure if this problem is due to limitations of the Canvas.toDataURL() function or if this is a Dygraphs problem or something else. I'm fishing for advice that may point me in the right direction and/or shed light on this particular problem.
**I should mention that I use Juan Manuel Caicedo Carvajal's Dygraph-Export extension
I'm guessing the Problem occurs, because the generated canvas isn't rendered fully to the responsive screen of an iPad.
You can try to export the original canvas (instead of generating a new one with the said library) yourself with toDataUrl https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
Dygraphs generates 2 canvas, one for the legend and one for the actual graph and lays them ontop of each other. So make sure you choose the right one (not the _hidden_canvas). If the examples works you can draw the legend onto the graph canvas with canvas.drawImage(otherCanvas)
How to Copy Contents of One Canvas to Another Canvas Locally
Hope this helps. Keep me updated!
My workaround/hack for the problem stated in my OP was to make a change to the Dygraph source in the Dygraph.getContextPixelRatio function.
Notice in the code below that I set devicePixelRatio = 1
dygraph-combined.js
Dygraph.getContextPixelRatio = function (context) {
try {
//var devicePixelRatio = window.devicePixelRatio;
var devicePixelRatio = 1; // Hack!!!
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
if (devicePixelRatio !== undefined) {
return devicePixelRatio / backingStoreRatio;
} else {
// At least devicePixelRatio must be defined for this ratio to make sense.
// We default backingStoreRatio to 1: this does not exist on some browsers
// (i.e. desktop Chrome).
return 1;
}
} catch (e) {
return 1;
}
};
In my case, this hack fixed my problem (stated in the OP) and didn't negatively affect any other parts of my application that uses Dygraphs. That said, if you find a better/correct way to fix the problem stated in the OP, please share.

Watin AttachTo: Timeout while waiting for frame document becoming available

I am trying to make WatiN attach to an IE popup window (IE 10).
This popup contains a frameset --> a single frame --> a pdf document.
My goal is to save this pdf to my disk.
Dim winExists = IE.Exists(Of IE)(Find.ByUrl(Function(url) url.Contains("__ADFvDlg")))
If winExists Then 'this evaluates to true
Dim win = IE.AttachTo(Of IE)(Find.ByUrl(Function(url) url.Contains("__ADFvDlg"))) ' Timeout while waiting for frame document becoming available
End If
1) I have tried using the above code inline or in a STA thread
2) When coded inline, its parent thread is also STA
3) I have tried to increase the default timeout to 8 minutes, same result after 8 minutes have passed
There is no other option for me than to parse this particular popup, since it is a site built with Oracle ADF and, apart from the fact that it is A MESS, it is very strange at times...this popup has a URL that somehow works only once. If I try to use it in another window, no pdf is returned. The same happens when I refresh the popup.
I cannot fetch the PDF in the Temporary Internet Files since it is not there (I suppose this is because the website works under SSL).
Any guidelines or solutions even outside WatiN's scope is more than welcome since I've hit a brick wall.
Technologies: VS2012, WPF
Thanks a lot in advance.
I found it easiest when I tried the same thing by making the pop-up show up as a new tab. That way I could attach to it's URL. From there I would use
File.WriteAllText(fileName, responseDownLoad.Content.ReadAsStringAsync().Result);
Where responseDownload will be a HttpResponseMessage

HTML Bridge not working with cross-domain Silverlight XAP

I've got a complex Silverlight app that uses the HTML bridge functionality quite extensively (in both directions). The app runs fine when the hosting page is from the same domain as the XAP source. Unfortunately, I can't get the HTML bridge functionality to work when the hosting page is on a different domain.
Now, I know the various tricks normally required to get this to work, i.e., everything that's documented here: http://msdn.microsoft.com/en-us/library/cc645023(VS.95).aspx. I've even put together my own simplified cross-domain repro that I was hoping would highlight the problem, but unfortunately, my "repro" works, i.e., both JS->SL and SL->JS functionality work just fine in it, even if the XAP is hosted on a different domain.
Here's what I've tried so far to narrow down the problem:
On my production solution (where I'm having the problem):
Confirmed that "EnableHtmlAccess" is set to true in the <object> tag.
Confirmed that "ExternalCallersFromCrossDomain" is set to "ScriptableOnly" in the AppManifest.xml file.
On my repro solution (where I can't get it to have the problem):
Added multiple libraries with multiple registered scriptable objects.
Added events to the registered objects.
On both:
Tried it with a static <object> tag and with a dynamically created <object> tag (via Silverlight.js).
Tried it with and without specifying handlers for onSourceDownloadProgressChanged, onSourceDownloadComplete, onError, and onLoad.
Tried it with and without a splashscreen.
I'm kinda running out of ideas. Anyone have any suggestions for other troubleshooting steps?
Well, so far I haven't been able to track down the precise difference between the working and the non-working versions. But I came up with a workaround that's sufficient for my needs. As it turns out, only the JS->SL functionality was broken; any calls from SL->JS still worked. So what I did was to register the scriptable SL objects from within Silverlight. In my controlling JavaScript class, I created a function with a unique name, and registered it with the window object:
var mLoadingController;
var mAppId = 'alantaClient_' + Alanta.makeId();
var mSetLoadingControllerId = mAppId + '_SetLoadingController';
window[mSetLoadingControllerId] = function (value) {
mLoadingController = value;
onLoad();
};
And then I pass in the name of the function as a part of the Silverlight app's InitParams:
var initParams = 'setLoadingControllerId=' + mSetLoadingControllerId;
Silverlight.createObject(mSource, mAppHost, mAppId, params, events, initParams);
And then I call that registration function from within Silverlight, like so:
// Do everything necessary to make the LoadingController scriptable.
HtmlPage.RegisterScriptableObject("LoadingController", LoadingController.Instance);
string setLoadingControllerId;
if (e.InitParams.TryGetValue(LoaderConstants.SetLoadingControllerIdReference, out setLoadingControllerId))
{
HtmlPage.Window.Invoke(setLoadingControllerId, LoadingController.Instance);
}
And then I can call it from JS, like so:
mLoadingController.GoToRoom();
Kinda hacky, but it works. Close enough for now.

Resources