Xamarin.Forms Strange Behavior when Implementing BindingContextChanged Event - xamarin.forms

I have a list that has icon to most right of cell row
when I implementing BindingContextChanged to control context action (enable and disable according to certain condition )
<customRender:ExtViewCell BindingContextChanged="FlightDetialCell_OnBindingContextChanged">
private void FlightDetialCell_OnBindingContextChanged(object sender, EventArgs e)
{
var deleteAction = new MenuItem { Text="Delete" , IsDestructive=true};
deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
deleteAction.Clicked += (sender2, e2) =>
{
DeleteMenuItem_OnClicked(sender2, e2);
};
ViewCell theViewCell = ((ViewCell)sender);
var item = theViewCell?.BindingContext as DocumentsListItem;
if (item != null)
{
if (item.Title !="certain title" )
{
theViewCell.ContextActions.Add(deleteAction);
}
}
// theViewCell.BindingContextChanged -= FlightDetialCell_OnBindingContextChanged;
}
I has two strange behavior happened
in iOS platform icon take margin to left then when I keep scroll it become normal
in Android platform app crashed
Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
--- End of managed Java.Lang.NullPointerException stack trace ---
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
at android.widget.AdapterView.getPositionForView(AdapterView.java:602)
at md5b60ffeb829f638581ab2bb9b1a7f4f3f.ViewCellRenderer_ViewCellContainer_LongPressGestureListener.n_onLongPress(Native Method)
at md5b60ffeb829f638581ab2bb9b1a7f4f3f.ViewCellRenderer_ViewCellContainer_LongPressGestureListener.onLongPress(ViewCellRenderer_ViewCellContainer_LongPressGestureListener.java:51)
at android.view.GestureDetector.dispatchLongPress(GestureDetector.java:690)
at android.view.GestureDetector.access$200(GestureDetector.java:37)
at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:266)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
my attempts to fix the issue detach listener
theViewCell.BindingContextChanged -= FlightDetialCell_OnBindingContextChanged;
but this don't solve my problem

Related

UiDevice.getUiAutomation(instrumentation) returns null causing NPE, in Robolectric test

In my Roblectric test, I try to confirm permission dialog with UiDevice
#RunWith(RobolectricTestRunner::class)
#Config(sdk = [Build.VERSION_CODES.P])
open class FooTest {
#Before
private fun before() {
var device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Confirm permissions dialog with device object
// ...
}
but this line throws an NPE exception
var device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
with stack trace
java.lang.NullPointerException
at androidx.test.uiautomator.QueryController.<init>(QueryController.java:95)
at androidx.test.uiautomator.UiDevice.<init>(UiDevice.java:109)
at androidx.test.uiautomator.UiDevice.getInstance(UiDevice.java:261)
because UiDevice.getUiAutomation(instrumentation) is returning null
public QueryController(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
UiDevice.getUiAutomation(instrumentation).setOnAccessibilityEventListener(mEventListener);
}

display activity from other application on my own application

I would like to start an application (example Calculator) on a fragment for example on my application.
I try this code but i get an error (line Fragment):
String packageName = "com.android.calculator2";
Context ctx = getApplicationContext().createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE |
Context.CONTEXT_IGNORE_SECURITY);
ClassLoader cl = ctx.getClassLoader();
Class<?> c = cl.loadClass("com.android.calculator2.Calculator");
Fragment fragObj = (Fragment)c.newInstance();
i get this error:
Process: fr.jm.managercamera, PID: 14006
java.lang.RuntimeException: Unable to start activity ComponentInfo{fr.jm.managercamera/fr.jm.managercamera.MainActivity}: java.lang.ClassCastException: com.android.calculator2.Calculator cannot be cast to android.app.Fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
I try this code, i get other problem:
Class requiredClass = null;
final String apkPath = getPackageManager().getApplicationInfo("com.android.calculator2",0).sourceDir;
final File dexTemp = getDir("temp_folder", 0);
final String fullName = "com.android.calculator2.Calculator";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
System.out.println("apkPath: " + apkPath);
System.out.println("dexTemp.getAbsolutePath(): " + dexTemp.getAbsolutePath());
final DexClassLoader classLoader = new DexClassLoader(apkPath,
dexTemp.getAbsolutePath(),
null,
getClass().getClassLoader());
/* DexClassLoader classLoader = new DexClassLoader(apkPath,"/tmp", null,
getClass().getClassLoader());*/
requiredClass = classLoader.loadClass(fullName);
}
I get this error (line loadClass):
10-03 17:50:22.776 14133-14133/? W/System.err: java.lang.ClassNotFoundException: Didn't find class "com.android.calculator2.Calculator" on path: DexPathList[[zip file "/system/app/Calculator/Calculator.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
10-03 17:50:22.776 14133-14133/? W/System.err: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
10-03 17:50:22.776 14133-14133/? W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
10-03 17:50:22.776 14133-14133/? W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
You can't do that. You can launch the calculator as an Activity, but you cannot load foreign code into your own OS process. That would be a security violation.
The calculator app's code is only allowed to run in the calculator app's OS Process, not in any other OS Process. The Android security model doesn't allow that.

How to fix 'IllegalStateException' when using custom JavaFXBuilderFactory

First of all, I'm using Kotlin in my JavaFX Project.
I'm trying to implement my own JavaFX Node that extends Canvas.
class BrikkCanvas(width: Double, height: Double, private val rows: Int, private val cols: Int) : Canvas(width, height)
I also want to be able to add BrikkCanvas directly in the FXML File like so
<BrikkCanvas fx:id="myCanvas" width="100.0" height="100.0" rows="1" cols="1" />
My class has no default constructor, that's why including it in FXML is not trivial.
I found out, however, that you can implement custom BuilderFactory, so I did:
class BrikkCanvasBuilderFactory : BuilderFactory {
private val defaultBuilderFactory = JavaFXBuilderFactory()
override fun getBuilder(clazz: Class<*>): Builder<*> =
if (clazz == BrikkCanvas::class.java) BrikkCanvasBuilder()
else defaultBuilderFactory.getBuilder(clazz)
private class BrikkCanvasBuilder : Builder<BrikkCanvas> {
var width: Double = 0.0
var height: Double = 0.0
var rows: Int = 0
var cols: Int = 0
override fun build(): BrikkCanvas = BrikkCanvas(width, height, rows, cols)
}
}
In the App class that extends Application I use my BrikkCanvasBuilderFactory like this:
fun startTheGame(playerName: String) {
val loader = FXMLLoader(App::class.java.getResource("game.fxml"), null, BrikkCanvasBuilderFactory())
val scene = Scene(loader.load())
val controller = loader.getController<GameController>()
primaryStage.scene = scene
}
However, when I start the application and click the button that invokes startTheGame, I get the following error:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
...
Caused by: javafx.fxml.LoadException:
/path to project/target/classes/game.fxml:21
at App$Companion.startTheGame(App.kt:18)
...
Caused by: java.lang.IllegalStateException: defaultBuilderFactory.getBuilder(clazz) must not be null
at controller.BrikkCanvasBuilderFactory.getBuilder(BrikkCanvasBuilderFactory.kt:12)
game.fxml:21 = fx:controller="controller.GameController"
App$Companion.startTheGame(App.kt:18) = val scene = Scene(loader.load())
BrikkCanvasBuilderFactory.kt:12 = else defaultBuilderFactory.getBuilder(clazz)
Please note that I haven't even included any <BrikkCanvas ... /> tags in the FXML File yet
I'm pretty sure that I'm missing something really basic that probably has to do with the fact that I'm using Kotlin instead of Java
As I understand it, the BuilderFactory and Builder interfaces are relics of the past (essentially deprecated) and should be avoided in new code—pretend they don't exist. You should instead annotate your constructor parameters with the #NamedArg annotation.
class BrikkCanvas(
#NamedArg("width") width: Double,
#NamedArg("height") height: Double,
#param:NamedArg("rows") private val rows: Int,
#param:NamedArg("cols") private val cols: Int
) : Canvas(width, height)
The FXMLLoader will then be able to tell which FXML attribute corresponds with which parameter, and thus can set the properties via the constructor.

Manage wait cursor for task

I'm outside the UI and wish to display a wait cursor while stuff is
happening and using this basic pattern:
on UI - primaryStage.scene.cursor = Cursor.WAIT
try {
do stuff off UI...
} finally {
on UI - primaryStage.scene.cursor = Cursor.DEFAULT
}
While running I can start another process which completes quickly and the Cursor is restored before the first task completes.
I don't mind "waiting" while the first task completes, but I don't think this means doing the work on the UI thread?
Is there any built in solution for this pattern provided in javafx?
My tab contains 2 Combo Box. When I hit the 2nd Combo Box drop down, a WAIT cursor sometimes appears over the list even though the Cursor is currently DEFAULT state. If I move the mouse pointer outside/back on the list the cursor is correctly displayed as Default. Would this be a separate issue or somehow related?
VIEW
label 'From'
comboBox(items: bind(model.wcomboFromItemsProperty()), value: bind(model.wcomboFromProperty()), selectFromAction)
label 'To'
comboBox(items: bind(model.wcomboFromItemsProperty()), value: bind(model.wcomboToProperty()), selectToAction)
MODEL
#FXObservable ListElement wcomboFrom = new ListElement()
#FXObservable ListElement wcomboTo = new ListElement()
#FXObservable List wcomboFromItems = FXCollections.observableArrayList()
#FXObservable List wcomboToItems = FXCollections.observableArrayList()
final ObjectProperty<Cursor> CURSOR_DEFAULT = new SimpleObjectProperty<>(Cursor.DEFAULT)
final ObjectProperty<Cursor> CURSOR_WAIT = new SimpleObjectProperty<>(Cursor.WAIT)
CONTROLLER
//lifecycle
void onReadyStart(GriffonApplication application) {
loadWindowData()
}
// both combo boxes contain the same items
protected void loadWindowData() {
def list = [new ListElement(textValue: '')]
list.addAll dataService.getData().collect {
new ListElement(textValue: it.name, objectValue: it)
}
runInsideUIAsync {
model.wcomboFromItems.addAll(list)
model.wcomboToItems.addAll(list)
}
}
void selectFrom() {
performAction {
gcListFrom = getControlList(model.wcomboFrom.objectValue)
setTreeItems(model.wtreeGcFrom, gcListFrom, model.wcomboFrom)
setTreeItems(model.wtreeGcTo, gcListTo, model.wcomboTo)
}
}
void selectTo() {
performAction {
gcListTo = getControlList(model.wcomboTo.objectValue)
setTreeItems(model.wtreeGcTo, gcListTo, model.wcomboTo)
}
}
def performAction = {c ->
Task<Void> t = new Task() {
#Override protected Void call() {
println "Running closure " + isUIThread()
c.call()
}
}
runInsideUISync {
application.primaryStage.scene.cursorProperty().bind(Bindings.when(t.runningProperty())
.then(model.CURSOR_WAIT).otherwise(model.CURSOR_DEFAULT))
}
runOutsideUI(t)
}
OTHER
#EqualsAndHashCode(includes = 'textValue')
class ListElement implements Serializable {
String textValue = ""
Serializable objectValue // Serializable object from business model
#Override
String toString() {
textValue
}
}
The Griffon framework automatically invokes the onAction controller events outside the UI thread. GroovyFX contains some magic which adds an "onSelect" action bound to selectionModel.selectedItemProperty i.e.
class GroovyFXEnhancer {
static void enhanceClasses() {
...
ComboBox.metaClass {
cellFactory << { Closure closure -> delegate.setCellFactory(closure as Callback)}
onSelect << { Closure closure ->
delegate.selectionModel.selectedItemProperty().addListener(closure as ChangeListener);
}
...
}
}
Is there any built in solution for this pattern provided in javafx?
I would advice you to use the built in Task ;)
It has predefined methods to handle everything you need.
private Task<Void> backgroundTask = new Task() {
#Override
protected Void call() throws Exception {
// Something to do on background thread ;
return null;
}
};
It has a runningProperty(), which can bind to the cursorProperty() of the scene.
You can create two ObjectProperty<Cursor> containing Cursor.DEFAULT and CURSOR.WAIT.
final ObjectProperty<Cursor> CURSOR_DEFAULT = new SimpleObjectProperty<>(Cursor.DEFAULT);
final ObjectProperty<Cursor> CURSOR_WAIT = new SimpleObjectProperty<>(Cursor.WAIT);
Then you can bind them to the task :
scene.cursorProperty().bind(Bindings.when(backgroundTask.runningProperty())
.then(CURSOR_WAIT).otherwise(CURSOR_DEFAULT));
Would this be a separate issue or somehow related?
If your action on the ComboBox is somehow invoking the background thread, then it might be related, else it is difficult to comment.
You can also use the griffon-tasks-plugin http://griffon-plugins.github.io/griffon-tasks-plugin/
This plugin delivers and UI toolkit agnostik SwingWorker-like API for executing tasks in a background thread.

org.openqa.selenium.WebDriverException: ReferenceError: jQuery is not defined

Hi I am trying to write autonomous test using Webdriver for firefox profile, I enabled the javascript equal to true while creating Driver object.
In some view jquery responses late so for that I tried to put one check in webdriver code to wait For JQuery Processing
Code snippet for waitForJQueryProcessing:
public static boolean waitForJQueryProcessing(WebDriver driver,
int timeOutInSeconds) {
boolean jQcondition = false;
try {
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driverObject) {
return (Boolean) ((JavascriptExecutor) driverObject)
.executeScript("return jQuery.active == 0");
}
});
jQcondition = (Boolean) ((JavascriptExecutor) driver)
.executeScript("return jQuery.active == 0");
return jQcondition;
} catch (Exception e) {
e.printStackTrace();
}
return jQcondition;
}
But the above code is rising exception
Stacktrace
org.openqa.selenium.WebDriverException: ReferenceError: jQuery is not defined
Command duration or timeout: 10 milliseconds
Build info: version: '2.32.0', revision: '6c40c187d01409a5dc3b7f8251859150c8af0bcb', time: '2013-04-09 10:39:28'
System info: os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.6.0_17'
Session ID: 58ad81d0-53f9-4862-a916-a1900efdc9c0
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{platform=XP, acceptSslCerts=true, javascriptEnabled=true, browserName=firefox, rotatable=false, locationContextEnabled=true, version=21.0, cssSelectorsEnabled=true, databaseEnabled=true, handlesAlerts=true, browserConnectionEnabled=true, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=true, takesScreenshot=true}]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:187)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:554)
at org.openqa.selenium.remote.RemoteWebDriver.executeScript(RemoteWebDriver.java:463)
at com.iclinica.utils.WaitTool$9.apply(WaitTool.java:309)
at com.iclinica.utils.WaitTool$9.apply(WaitTool.java:1)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:208)
at com.iclinica.utils.WaitTool.waitForJQueryProcessing(WaitTool.java:304)
at com.iclinica.globals.FirefoxCustomWebdriver.findElement(FirefoxCustomWebdriver.java:14)
at com.iclinica.page.studyconfig.studydetails.StudyDetailsPage.studydetails(StudyDetailsPage.java:20)
at com.iclinica.studyconfig.AddPatients.teststudycreation(AddPatients.java:168)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
I googled for setting jquery file path in webdriver object, but didn't find any result
I hope it makes sense.
Thanks
Gaurav
Use this instead:
public static boolean waitForJQueryProcessing(WebDriver driver,
int timeOutInSeconds) {
boolean jQcondition = false;
try {
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driverObject) {
return (Boolean) ((JavascriptExecutor) driverObject)
.executeScript("return jQuery.active == 0");
}
});
jQcondition = (Boolean) ((JavascriptExecutor) driver)
.executeScript("return window.jQuery != undefined && jQuery.active === 0");
return jQcondition;
} catch (Exception e) {
e.printStackTrace();
}
return jQcondition;
}
The change from your original code snippet is:
.executeScript("return window.jQuery != undefined && jQuery.active === 0");
This will make sure that your jQuery object is defined before checking if there are any active jQuery processes. Selenium runs fast and can sometimes make queries to jQuery before it has had a chance to load into the page you are testing.
There is one shorter version of code which works for me:
public void waitForAjaxLoad(WebDriver driver) throws InterruptedException{
JavascriptExecutor executor = (JavascriptExecutor)driver;
if((Boolean) executor.executeScript("return window.jQuery != undefined")){
while(!(Boolean) executor.executeScript("return jQuery.active == 0")){
Thread.sleep(1000);
}
}
return;
}
Milliseconds (1000) can be added to parameter of method.
When you test for jQuery completion do not forget to add a check for jQuery being undefined else you will end up with :
ReferenceError: jQuery is not defined error.
jQuery check you should perform:
(Boolean)((JavascriptExecutor) wd).executeScript("return window.jQuery != undefined && jQuery.active == 0")
Now when you write method then I would suggest to use Fluent Wait in your selenium code rather than implicit or explicit wait. Fluent wait method will help you do operation in between the polling interval wait unlike other waits and is very useful or rather powerful.
Below is the working method which you can directly use :
public static void pageJqueryLoad(WebDriver driver, Duration waitTimeout) {
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(waitTimeout)
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class);
wait.until((ExpectedCondition<Boolean>) wd -> {
log.info("Waiting for Page jQuery to complete");
log.info("jQuery.active value is : " + ((JavascriptExecutor) wd).executeScript("return window.jQuery != undefined && jQuery.active"));
(Boolean)((JavascriptExecutor) wd).executeScript("return window.jQuery != undefined && jQuery.active == 0");
});
}
In the above method :
You need to pass your driver and waitTimeout duration as argument to this method. For ex: pageJqueryLoad(driver, Duration.ofSeconds(120));
I have defined polling interval as 500 ms. You can modify as per your need.
Every time a poll is done it prints the 3 statement given under log.info.
Using this you can easily add code to determine the exact time your page was rendered completely before doing test operations.

Resources