func show(message string, long bool) { err := mobileinit.RunOnJVM(func(vm, env, ctx uintptr) error { cMessage := C.CString(message) defer C.free(unsafe.Pointer(cMessage)) duration := C.jint(0) // TOAST_SHORT if long { duration = C.jint(1) // TOAST_LONG } C.toast_show(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx), cMessage, duration) return nil }) if err != nil { log.Fatalf("showToast: %v", err) } }
func (self *Environment) setIntField(z interface{}, static bool, name string, val int) (err error) { jval, field, err := self.getField(z, static, name, types.Basic(types.IntKind)) if err != nil { return } if static { C.envSetStaticIntField(self.env, C.valObject(jval), field.field, C.jint(val)) } else { C.envSetIntField(self.env, C.valObject(jval), field.field, C.jint(val)) } if self.ExceptionCheck() { err = self.ExceptionOccurred() } return }
func (self *Environment) newByteObject(bts []byte) (o *Object, err error) { ja := C.envNewByteArray(self.env, C.jint(len(bts))) if ja == nil { err = errors.New("Error allocating byte array") } if err == nil && len(bts) > 0 { bptr := make([]byte, len(bts)) copy(bptr, bts) //log.Printf("bptr: %s %p %p", bptr,bptr, &bptr[0] ) C.envSetByteArrayRegion(self.env, ja, 0, C.jint(len(bptr)), unsafe.Pointer(&bptr[0])) } if err == nil { o = newObject(C.jobject(ja)) } return }
func jIntValue(v interface{}) (C.jvalue, error) { val, ok := intValue(v) if !ok { return errJValue, fmt.Errorf("%#v isn't int", v) } return C.jIntValue(C.jint(val)), nil }
func (an *androidNotification) Close() { err := mobileinit.RunOnJVM(func(vm, env, ctx uintptr) error { C.notification_close(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx), C.jint(an.id)) return nil }) if err != nil { log.Fatalf("Notification.Close: %v", err) } }
func (self *Environment) newObjectArray(sz int, klass *Class, init C.jobject) (o *Object, err error) { ja := C.envNewObjectArray(self.env, C.jint(sz), klass.class, init) if ja == nil { err = self.ExceptionOccurred() } if err == nil { o = newObject(C.jobject(ja)) } return }
func defaultJVMArgs(ver int) (args *C.JavaVMInitArgs, err error) { if ver == 0 { ver = DEFAULT_JVM_VERSION } args = new(C.JavaVMInitArgs) //print("Default args\t", ver,"\n") args.version = C.jint(ver) if 0 != C.JNI_GetDefaultJavaVMInitArgs(unsafe.Pointer(args)) { err = errors.New("Couldn't contruct default JVM args") } return }
// C callbacks actually start in the 'generifiedX' calls (see the .c files) // Next, goCallbackNArgs is used to determine the number of variadic paramers to expect ( // java doesn't inform us of this, and we can't force any of the callback parameters. // // Finally, goCallback looks up the 'fId' - our internal function reference ID (the X in generified), // un(re) marshalls all the parameters appropriately, calls our function, and returns // any underlying value back to generified who will return it to the JVM. // The initial jbool indicates success, and any failure should check for exceptions. // //export goCallback func goCallback(envp, obj uintptr, fId int, nargs int, argp uintptr) (ok C.jboolean, val interface{}) { args := C.ArgListPtr(unsafe.Pointer(argp)) env := AllEnvs.Find(envp) if env == nil { panic("Got a nil environment") } if env.jvm == nil { panic("Environment pointer has no JVM") } var cd callbackDescriptor var _ok bool if cd, _ok = env.jvm.registered[fId]; !_ok { print("Unknown callbackId: \t", fId, "\n") return } // TODO: pack argp somehow... if nargs != len(cd.Signature.Params) { panic("callback/signature length mismatch") } inCall := []reflect.Value{reflect.ValueOf(env), reflect.ValueOf(newObject(C.jobject(unsafe.Pointer(obj))))} var err error for i := 0; i < nargs; i++ { switch cd.Signature.Params[i].Kind() { case types.BoolKind: inCall = append(inCall, reflect.ValueOf(bool(0 != C.valBool(C.getArg(args, C.int(i)))))) case types.LongKind: inCall = append(inCall, reflect.ValueOf(int64(C.valLong(C.getArg(args, C.int(i)))))) case types.IntKind: inCall = append(inCall, reflect.ValueOf(int(C.valInt(C.getArg(args, C.int(i)))))) case types.ShortKind: inCall = append(inCall, reflect.ValueOf(int16(C.valShort(C.getArg(args, C.int(i)))))) case types.FloatKind: inCall = append(inCall, reflect.ValueOf(float32(C.valFloat(C.getArg(args, C.int(i)))))) case types.DoubleKind: inCall = append(inCall, reflect.ValueOf(float64(C.valDouble(C.getArg(args, C.int(i)))))) case types.ClassKind: inCall = append(inCall, reflect.ValueOf(newObject(C.valObject(C.getArg(args, C.int(i)))))) default: err = errors.New("Couldn't reflect kind " + cd.Signature.Params[i].Kind().TypeString()) } if err != nil { break } } if err != nil { return } outCall := reflect.ValueOf(cd.F).Call(inCall) switch cd.Signature.Return.Kind() { case types.VoidKind: return 1, nil } switch cd.Signature.Return.Kind() { case types.BoolKind: if outCall[0].Interface().(bool) { return 1, C.jboolean(C.JNI_TRUE) } else { return 1, C.jboolean(C.JNI_FALSE) } case types.ByteKind: return 1, C.jbyte(outCall[0].Interface().(byte)) case types.CharKind: return 1, C.jchar(outCall[0].Interface().(int)) case types.IntKind: return 1, C.jint(outCall[0].Interface().(int)) case types.ShortKind: return 1, C.jshort(outCall[0].Interface().(int16)) case types.LongKind: return 1, C.jint(outCall[0].Interface().(int64)) case types.FloatKind: return 1, C.jfloat(outCall[0].Interface().(float32)) case types.DoubleKind: return 1, C.jdouble(outCall[0].Interface().(float64)) case types.ClassKind: klass := cd.Signature.Return.(types.Class).Klass if klass.Cmp(types.JavaLangString) == 0 { var obj *Object str := outCall[0].Interface().(string) obj, err = env.NewStringObject(str) if err == nil { return 1, C.jstring(obj.object) } // else, exception occurred // not needed as callbacks will reap their own refs. // env.DeleteLocalRef(obj) print("String Error\t", err.Error()) return 0, nil } return 1, C.jobject(outCall[0].Interface().(*Object).object) default: panic("array return type not yet supported") } panic("not reached") }
// TODO(refcounting): any constructed objects will be leaked on call return, // as nothing cleans up proxy objects. I'm also torn on how to differentiate // the objects made here and those coming in from other references. // // Refcounting attempt 1, objects _we_ construct will be returned in the objStack, // otherwise refcounts of 'pass-through' java natives are untouched by the call to newArgList. // // On error, the stack has already been blown (and will be empty). func newArgList(ctx *Environment, params ...interface{}) (alp argList, objStack []*Object, err error) { alp = make(argList, 0) defer func() { if err != nil { blowStack(ctx, objStack) objStack = []*Object{} } }() for i, param := range params { var ok C.int switch v := param.(type) { case int: alp = append(alp, C.intValue(C.jint(v))) case int64: alp = append(alp, C.longValue(C.jlong(v))) case C.jstring: alp = append(alp, C.objValue(v)) case C.jboolean: alp = append(alp, C.boolValue(v)) case C.jint: alp = append(alp, C.intValue(v)) case C.jobject: alp = append(alp, C.objValue(v)) case *Object: alp = append(alp, C.objValue(v.object)) case *Class: alp = append(alp, C.objValue(v.class)) case C.jvalue: alp = append(alp, v) case string: var str *Object str, err = ctx.NewStringObject(v) if err == nil { objStack = append(objStack, str) alp = append(alp, C.objValue(str.object)) } case []string: var klass *Class var obj *Object klass, err = ctx.GetClassStr("java/lang/String") // classes via this channel are cached and globally referenced by gojvm, not stacked. if err == nil { obj, err = ctx.newObjectArray(len(v), klass, nil) } if err == nil { objStack = append(objStack, obj) for i, s := range v { var str *Object str, err = ctx.NewStringObject(s) if err == nil { // I'm assuming stuffing the array adds a reference inside the JVM. defer ctx.DeleteLocalRef(str) ctx.setObjectArrayElement(obj, i, str) if ctx.ExceptionCheck() { err = ctx.ExceptionOccurred() } } if err != nil { break } } } if err == nil { alp = append(alp, C.objValue(obj.object)) } case []byte: var obj *Object obj, err = ctx.newByteObject(v) if err == nil { alp = append(alp, C.objValue(obj.object)) } objStack = append(objStack, obj) case bool: val := C.jboolean(C.JNI_FALSE) if v { val = C.JNI_TRUE } alp = append(alp, C.boolValue(val)) default: err = errors.New(fmt.Sprintf("Unknown type: %T/%s", v, v)) } if ok != 0 { err = errors.New("Couldn't parse arg #" + strconv.Itoa(i+1)) } if err != nil { break } } return }
func (self *Environment) setObjectArrayElement(arr *Object, pos int, item *Object) (err error) { C.envSetObjectArrayElement(self.env, arr.object, C.jint(pos), item.object) return }
// PushLocalFrame pushes a new local reference frame onto the reference frame // stack. If the return value is >= 0, the new frame will have capacity for at // least the specified number of local references. If the return value is < 0, // the reference frame could not be created. func PushLocalFrame(env Env, capacity int) int { return int(C.PushLocalFrame(env.value(), C.jint(capacity))) }