JNA Objective-C (Rococoa) Calendar Callback - java

I want to access the Objective-C EKEventStore in Java via Rococoa. The API specifies a callback to get notified when the user accepts the calendar access prompt, which works perfectly in pure Objective-C.
Native.loadLibrary("EventKit", EventKitLibrary.class);
EKEventStore store = EKEventStore.CLASS.alloc();
store.init();
//store = store.initWithAccessToEntityTypes(EKEntityType.EKEntityTypeEvent); // no notification
EKEventStoreRequestAccessCompletionHandler handler = new EKEventStoreRequestAccessCompletionHandler() {
#Override
public void invoke(boolean granted, Pointer error) {
System.out.println("Access: " + granted);
NSArray calArray = store.calendarsForEntityType(EKEntityType.EKEntityTypeEvent);
for (int i = 0; i < calArray.count(); i++) {
NSObject calObject = calArray.objectAtIndex(i);
EKCalendar osxcal = Rococoa.cast(calObject, EKCalendar.class);
System.out.println(osxcal.title().toString());
}
}
};
ObjCObject object = Rococoa.proxy(handler); // get Objective C Callback Object to send
store.requestAccessToEntityType_completion(EKEntityType.EKEntityTypeEvent, object.id());
try {
Thread.sleep(10000); // wait for the access prompt
} catch (InterruptedException ex) {
}
// random object access to save instances from gc
System.out.println(handler.toString());
System.out.println(store.id());
System.out.println(object.id());
The Library
public interface EventKitLibrary extends Library {
public static EventKitLibrary INSTANCE = (EventKitLibrary) Native.loadLibrary("EventKit", EventKitLibrary.class);
}
The Mapped Classes
public abstract class EKEventStore extends NSObject {
public static final _Class CLASS = Rococoa.createClass("EKEventStore", _Class.class);
public interface _Class extends ObjCClass {
public abstract EKEventStore alloc();
}
public static interface EKEntityType {
public static final int EKEntityTypeEvent = 0;
public static final int EKEntityTypeReminder = 1;
};
public static interface EKEntityMask {
public static final int EKEntityMaskEvent = (1 << EKEntityType.EKEntityTypeEvent);
public static final int EKEntityMaskReminder = (1 << EKEntityType.EKEntityTypeReminder);
};
public abstract EKEventStore initWithAccessToEntityTypes(int EKEntityMask);
public abstract EKEventStore init();
public abstract void requestAccessToEntityType_completion(int EKEntityType, ID handler);
interface EKEventStoreRequestAccessCompletionHandler {
void invoke(boolean granted, Pointer error);
}
public abstract NSArray calendarsForEntityType(int EKEntityType);
}
public abstract class EKCalendar extends NSObject {
public static final _Class CLASS = Rococoa.createClass("EKCalendar", _Class.class);
public static interface _Class extends ObjCClass {
public NSObject alloc();
}
public abstract NSString title();
}
I only get an IllegalArgumentException for a missing type conversion of the NSError parameter. Am I doing something wrong, or should I implement a TypeConverter? And if, how should I do that?
EDIT:
Now I am using Pointer instead of NSError as parameter for the callback function, and I get the following JVM-Crash.
EDIT2:
Now I am using the Rococoa.proxy(handler) function for the callback like in the Rococoa Library. The input prompt appears, but the callback function doesn't get called. I think my callback initialization is still wrong.

Generally, a TypeMapper is implemented like this which converts a Pointer native type into some other Java type:
class NSErrorTypeMapper extends DefaultTypeMapper {
public NSErrorTypeMapper() {
TypeConverter tc = new TypeConverter() {
public Object toNative(Object value, ToNativeContext ctxt) {
Pointer p = // convert your NSError "value" into a Pointer
return p;
}
public Object fromNative(Object value, FromNativeContext ctxt) {
Pointer p = (Pointer)value;
Object object = // convert the pointer into an NSError object
return object;
}
public class nativeType() {
return Pointer.class;
}
};
addToNativeConverter(NSError.class, tc);
addFromNativeConverter(NSError.class, tc);
}
}

Related

How to access a parent class variable via a child class

I am trying to re-build an OOP approach to mobile verification at the developers discretion. The concept I come up with is to allow for interfaces to manipulate the class. If the class implements the interface, then the verify method will be executed.
The problem I am facing, because I am only used to programming in less strongly-typed languages (PHP) is how to get a protected variable from a class extending the current class.
_areaCodes.stream().forEach(o -> {
try {
int prefix = Integer.parseInt(this._mobileNumber.charAt(0), this._mobileNumber.charAt(1));
} catch (Exception e) {}
});
This line of code is now giving me an error
_mobileNumber cannot be resolved or is not a field
Here is my full code and here is an example I wrote of the same concept in PHP which I am trying to implement in Java.
import java.util.ArrayList;
interface Verification
{
public void initVerification();
}
class AreaCode
{
private int _code;
private String _country;
public AreaCode(int code, String country)
{
this._code = code;
this._country = country;
}
public int getAreaCode() { return this._code; }
public String getAreaCountry() { return this._country; }
}
class VerificationHandler
{
private ArrayList<AreaCode> _areaCodes = new ArrayList<AreaCode>() {{
this.add(new AreaCode(44, "UNITED KINGDOM"));
this.add(new AreaCode(91, "INDIA"));
}};
public void initVerification()
{
if(this instanceof Verification) {
this.verify();
}
}
protected void verify()
{
_areaCodes.stream().forEach(o -> {
try {
int prefix = Integer.parseInt(this._mobileNumber.charAt(0), this._mobileNumber.charAt(1));
} catch (Exception e) {}
});
}
}
class Main extends VerificationHandler implements Verification {
protected String _mobileNumber = "+447435217761";
}
public class Hack1337 { public static void main(String[] args) { new Main(); } }
How can I retrieve a variable in a class extending another, ie:
class A { public String getB() { return this.b; } }
class B extends A { protected String b = 'A should get this'; }
B b = new B().getB();
Only instances of class B, or sub-classes of B can access the b instance variable directly (unless you cast A to B within the body of the A class, which is bad practice).
You can give class A read-only access to that value by overriding getB():
class B extends A
{
protected String b = 'A should get this';
#Override
public String getB() {
return this.b;
}
}
and you may also want to make the getB() method abstract in class A (which means making class A abstract):
abstract class A
{
public abstract String getB();
}
This would only make sense if different sub-classes of A are expected to return different things in getB(). Otherwise, you may as well move the b variable to the base class A.

JNA callback function with pointer to structure argument

I am busy with a project in which I have to do native calls to a proprietary C library. I came across JNA, which seems to be tried and tested with a number of successful projects.
I am having trouble passing a structure (or pointer to) through to a callback function. I have tried many different scenarios before, and basically, any structure member that requires memory allocation, like a String (char *), for instance, is null when I retrieve it.
I have tried to illustrate the problem with the following example:
C code:
typedef struct {
int number;
char *string;
} TEST_STRUCT;
typedef union {
int number;
TEST_STRUCT test_struct;
} TEST_UNION;
typedef void (*TEST_CB)(TEST_UNION*);
void test(TEST_CB test_cb)
{
TEST_STRUCT *test_struct = malloc(sizeof *test_struct);
test_struct->number = 5;
test_struct->string = "Hello";
TEST_UNION *test_union = malloc(sizeof *test_union);
test_union->number = 10;
test_union->test_struct = *test_struct;
test_cb(test_union);
free(test_struct);
free(test_union);
}
Java-code:
public interface TestLib extends Library
{
class TestStruct extends Structure
{
public int number;
public String string;
public TestStruct() {
super();
}
protected List<? > getFieldOrder() {
return Arrays.asList("number", "string");
}
public TestStruct(int number, String string) {
super();
this.number = number;
this.string = string;
}
public TestStruct(Pointer peer) {
super(peer);
}
public static class ByReference extends MBTStatus implements Structure.ByReference {}
public static class ByValue extends MBTStatus implements Structure.ByValue {}
}
class TestUnion extends Union {
public int number;
public TestStruct testStruct;
public TestUnion() {
super();
}
public TestUnion(int number, TestStruct testStruct) {
super();
this.number = number;
this.testStruct = testStruct;
}
public TestUnion(Pointer pointer) {
super(pointer);
}
public static class ByReference extends TestUnion implements com.sun.jna.Structure.ByReference {}
public static class ByValue extends TestUnion implements com.sun.jna.Structure.ByValue {}
}
interface TestCallback extends Callback
{
public void callback(TestUnion testUnion);
}
void test(TestCallback testCallback);
}
The main Java class:
public class TestMain
{
static
{
System.loadLibrary("test");
}
public static void main (String [] args)
{
TestLib.INSTANCE.test(
new TestLib.TestCallback()
{
public void callback(TestLib.TestUnion testUnion)
{
System.out.println(testUnion.testStruct.string == null ? "The string value is null" : "The string value is: " + testUnion.testStruct.string);
}
}
);
}
}
The string value is then null:
The string value is null
I am a complete noob when it comes to JNA, so I have lots to learn. I'm not sure if the mapping of the structure is correct, which might be the cause of the null value.
Any help will be greatly appreciated!
EDIT: I made the question a bit more interesting:
So the argument to a callback function is a union, instead of a struct. The struct is now part of the union. When I do it this way, the value of the struct string variable seems to be null as well.
I just found the answer to the updated question myself. This example ultimatley shows how to do it. As a union only takes up the memory of its largest member, its type has to be set to that member. The Union.read() function must then be called to read the "selected" variable. This is done as follows:
testUnion.setType(TestLib.TestStruct.class);
testUnion.read();
The testStruct variable can then be accessed. The correct callback function is then:
public void callback(TestLib.TestUnion testUnion)
{
testUnion.setType(TestLib.TestStruct.class);
testUnion.read();
System.out.println(testUnion.testStruct.string == null ? "The string value is null" : "The string value is: " + testUnion.testStruct.string);
}
It might be useful when you implement the Union's Pointer-based constructor to invoke read after calling super, and override read() so that it always does the right thing, e.g.
class MyStructure1 {
public int type;
public int intField;
}
class MyStructure2 {
public int type;
public float floatField;
}
class MyUnion extends Union {
public int type;
public MyStructure1 s1;
public MyStructure2 s2;
public MyUnion(Pointer p) {
super(p);
read();
}
protected void read() {
int type = getPointer().getInt(0);
switch(type) {
case 0: setType(MyStruct1); break;
case 1: setType(MyStruct2); break;
}
super.read();
}
}
JNA will generally try to auto-populate as much data as it can if the union's type has not been set, avoiding any pointer fields (like strings) which might result in memory faults if they contain invalid data.

Android AIDL with Java generics

Does Android AIDL support generics?
For example, assume that I have a class Result<T>, where T can be any type including primitives (via autoboxing) or other custom classes such as Car. Any custom classes implement Parcelable as required by Binder.
Then possible AIDL method signatures would be
Result<Car> m1();
Result<Void> m2();
Result<Boolean> m3();
From what I could gather, the AIDL compiler doesn't like things like Result<Animal> getResult();. However, Result getResult(); does work. So this is what I did:
Created a class with the signature public class Result<T extends Parcelable> implements Parcelable.
Created a new class to throw into the first one, which is called Animal. The signature is public class Animal implements Parcelable.
Had to implement methods required by interface Parcelable and a CREATOR in both Result and Animal, and also created one AIDL for each as is required and imported both classes in the main AIDL. This stuff is regular AIDL work and is describe in the AIDL site.
Inside Result, we store not only an object of type T but also a Class object. When writing the parcel we need to write first the class type and only then the generic object. When reading, we do it in the same order. We need to write the class type because when we read we have to do t = (T) in.readValue(classType.getClassLoader()); and without a class type we do not know which class loader to fetch. There are probably other ways to do this but this is how I've done it for this example.
When receiving on the client node, I can successfully do Result<Animal> r = MainActivity.this.service.getResult(); and then call methods on both Result and Animal.
Some code that will hopefully makes things more clearer can be found below.
public class Result<T extends Parcelable> implements Parcelable {
private String msg;
private Class classType;
private T value;
public Result(String msg, T value, Class classType) {
this.msg = msg;
this.value = value;
this.classType = classType;
}
// to reconstruct object
public Result(Parcel in) {
readFromParcel(in);
}
public String getMsg() {
return msg;
}
public T getValue() {
return value;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(msg);
dest.writeValue(classType);
dest.writeValue(value);
}
private void readFromParcel(Parcel in) {
this.msg = in.readString();
this.classType = (Class) in.readValue(Class.class.getClassLoader());
this.value = (T) in.readValue(classType.getClassLoader());
}
public static final Creator<Result> CREATOR = new Creator<Result>() {
#Override
public Result createFromParcel(Parcel source) {
return new Result(source);
}
#Override
public Result[] newArray(int size) {
return new Result[size];
}
};
}
public class Animal implements Parcelable {
private int n;
public Animal(int n) {
this.n = n;
}
public Animal(Parcel in) {
readFromParcel(in);
}
public int getN() {
return n;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(n);
}
private void readFromParcel(Parcel in) {
n = in.readInt();
}
public static final Creator<Animal> CREATOR = new Creator<Animal>() {
#Override
public Animal createFromParcel(Parcel source) {
return new Animal(source);
}
#Override
public Animal[] newArray(int size) {
return new Animal[size];
}
};
}
Excerpt from the Service:
#Override
public Result getResult() throws RemoteException {
Result<Animal> r = new Result<Animal>("this is an animal", new Animal(42), Animal.class);
return r;
}
Excerpt from the Client:
Result<Animal> r = MainActivity.this.service.getResult();
Log.d(TAG, "Received the following (Outer): " + r.getMsg());
Log.d(TAG, "Received the following (Inner): " + r.getValue().getN());
Another way to do it is changing the signature of Result into public class Result<T extends Serializable> implements Parcelable, making Animal implement Serializable, and then use dest.writeSerializable(value); and this.value = (T) in.readSerializable(); inside Result.
With this approach there is no need to send the class type to the other side or even use it at all. You will, nonetheless, pay the price.
Daniels solution almost worked for me except the thing with marshalling and unmarshaling classtype.
Instead of "dest.writeValue(classType);" and "this.classType = (Class) in.readValue(Class.class.getClassLoader());" I had to use "dest.writeSerializable(classType);" and "classType = (Class) in.readSerializable();" and it worked like a charm
Thank you Daniel

Passing parameter to anonymous class in Java

i'm trying to write anonymous inner class
interface Face{
void seeThis(String what);
}
class Eyes {
public void show(Face f){}
}
public class Seen {
public void test() {
Eyes e = new Eyes();
e.show(new Face() {
#Override
public void seeThis(String what){
System.out.print(what);
}
});
public static void main(String[] args) {
Seen s = new Seen();
s.test();
}
}
How to call seeThis() and how to pass parameter to it?
Method seeThis() belongs to Face class, which instance is anonymous and thus cannot be reached without storing reference to it. If you want to store a reference, you can do this in the following way:
public class Seen {
public Face face;
....
this.face = new Face() { ... };
e.show(this.face);
And then,
Seen s = new Seen();
s.face.seeThis();
Now, regarding passing the parameter. You have two options - declare parameter outside of anonymous class and make it final in order to be reachable by this anonymous class, or replace anonymous class with normal one and pass the parameter to its constructor:
Approach one:
final int parameter = 5;
...(new Face() {
#Override
public void seeThis() {
System.out.println(parameter);
}
});
Approach two:
public class MyFace implements Face() {
private final int parameter;
public MyFace(int parameter) {
this.parameter = parameter;
}
#Override
public void seeThis() {
System.out.println(parameter);
}
}
Then,
...
e.show(new MyFace(10));

Is it possible to parcel a generic class?

I'm trying to create public class MyClass<T extends Parcelable> implements Parcelable. I'm having trouble implementing Parcelable. Is it possible to create a generic class that implements Parcelable? (Note that T is bounded so that it also must implement Parcelable).
I am running into trouble with the fact that the Parcelable interface requires a static variable: public static final Parcelable.Creator<MyParcelable> CREATOR. Thus I cannot do public static final Parcelable.Creator<MyClass<T>> CREATOR because MyParcelable<T> is nonstatic.
André
I had similar issues with implementing Parcelable on a class with a generic, the first issue was the same as what you were experiencing:
Thus I cannot do public static final Parcelable.Creator> CREATOR because MyParcelable is nonstatic.
The second was to read in a Parcelable object you need access to the ClassLoader which cannot be gotten from T due to type erasure.
The class below is an adaption of a class I am using in production which overcomes both issues. Note: I have not tested this class specifically, so let me know if you have any issues.
public class TestModel<T extends Parcelable> implements Parcelable {
private List<T> items;
private String someField;
public List<T> items() {
return items;
}
public void setItems(List<T> newValue) {
items = newValue;
}
public String someField() {
return someField;
}
public void setSomeField(String newValue) {
someField = newValue;
}
//region: Parcelable implementation
public TestModel(Parcel in) {
someField = in.readString();
int size = in.readInt();
if (size == 0) {
items = null;
}
else {
Class<?> type = (Class<?>) in.readSerializable();
items = new ArrayList<>(size);
in.readList(items, type.getClassLoader());
}
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(someField);
if (items == null || items.size() == 0)
dest.writeInt(0);
else {
dest.writeInt(items.size());
final Class<?> objectsType = items.get(0).getClass();
dest.writeSerializable(objectsType);
dest.writeList(items);
}
}
public static final Parcelable.Creator<TestModel> CREATOR = new Parcelable.Creator<TestModel>() {
public TestModel createFromParcel(Parcel in) {
return new TestModel(in);
}
public TestModel[] newArray(int size) {
return new TestModel[size];
}
};
//endregion
}
Write the generic data member class name to the parcel and then read it back in order to create its class loader. Example,
public class MyClass<T> implements Parcelable {
T data;
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(data.getClass().getName());
dest.writeParcelable((Parcelable) data, 0);
}
private MyClass(Parcel in) {
final String className = in.readString();
try {
data = in.readParcelable(Class.forName(className).getClassLoader());
} catch (ClassNotFoundException e) {
Log.e("readParcelable", className, e);
}
}
Yes you can. You just need to store the class name or class loader during the construction of your subclass object and then you can pass it during the read/write operation of the parcelable.
Step by step instructions:
Step 1. Store the class name that extends from your Generic class like this:
public abstract class GenericClass<T> implements Parcelable {
private String className;
Step 2. Any classes that extends from your generic class must specify the class name during its construction like this:
public class MyClass extends GenericClass<MyClass> {
public MyClass () {
super();
setClassName(MyClass.class.getName()); // Generic class setter method
}
Step 3. In your generic class, you can then read/write your class names to getClassLoader() like this:
public abstract class GenericClass<T> implements Parcelable {
private String className;
T myGenericObject;
protected MyClass (Parcel in) {
super(in);
this.className = in.readString();
ClassLoader classLoader;
try {
classLoader = Class.forName(this.className).getClassLoader();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
myGenericObject = in.readParcelable(classLoader);
//... Other class members can go here
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(className);
//... Other class members can go here
}
}
Based on answers above, have created extension functions for this.
fun <T : Parcelable> Parcel.writeGenericParcelable(data: T, flags: Int) {
writeString(data::class.java.name)
writeParcelable(data, flags)
}
fun <T : Parcelable> Parcel.readGenericParcelable(): T {
val className = readString()!!
val classNameLoader = Class.forName(className).classLoader
return readParcelable(classNameLoader)!!
}

Categories

Resources