/// <summary>
        /// Calls a non-static method with a void return type.
        /// </summary>
        /// <param name="name">Name.</param>
        /// <param name="args">Arguments.</param>
        public void CallVoid(string name, params object[] args)
        {
            string sig    = GetSignature(null, args);
            IntPtr method = AndroidJNIHelper.GetMethodID(RawClass, name, sig, false);

            jvalue[] jArgs = ConstructArgArray(args);
            try {
                JNISafe.CallVoidMethod(mObject, method, jArgs);
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
            }
        }
        internal JavaObject(IntPtr jobject) : this()
        {
            if (jobject == IntPtr.Zero)
            {
                throw new Exception("JavaObject: have tried to init JavaObject with null ptr!");
            }

            IntPtr objectClass = JNISafe.GetObjectClass(jobject);

            mObject = CreateGlobalRef(jobject);
            mClass  = CreateGlobalRef(objectClass);

            JNISafe.DeleteLocalRef(objectClass);
        }
        public static IntPtr ObjectCallStatic(IntPtr type, string name, string className, params object[] args)
        {
            string sig = GetSignature(className, args);

            IntPtr method = AndroidJNIHelper.GetMethodID(type, name, sig, true);

            jvalue[] jArgs = ConstructArgArray(args);
            try {
                IntPtr val = JNISafe.CallStaticObjectMethod(type, method, jArgs);

                return(val);
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
            }
        }
        internal JavaObject(params object[] args)
        {
            if (args == null)
            {
                args = new object[0];
            }
            mClass = CreateGlobalRef(FindClass(GetClass(GetType())));
            string sign = GetSignature(null, args);

            jvalue[] jniArgArray = ConstructArgArray(args);
            try {
                IntPtr num = JNISafe.NewObject(mClass, AndroidJNIHelper.GetConstructorID(mClass, sign), jniArgArray);
                mObject = CreateGlobalRef(num);
                JNISafe.DeleteLocalRef(num);
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jniArgArray);
            }
        }
        public void Dispose()
        {
            if (mDisposed)
            {
                return;
            }

            mDisposed = true;

            if (mObject != IntPtr.Zero)
            {
                JNISafe.DeleteGlobalRef(mObject);
            }

            if (mClass != IntPtr.Zero)
            {
                JNISafe.DeleteGlobalRef(mClass);
            }
        }
//        public TReturnType ObjectCall<TReturnType>(string name, params object[] args) {
//            Debug.LogWarning("ObjectCall1: " + name);
//            string sig = GetSignature<TReturnType>(args);
//            Debug.LogWarning("ObjectCall2: " + name + " => " + sig);
//            IntPtr methodId = AndroidJNIHelper.GetMethodID(RawClass, name, sig, false);
//
//            jvalue[] jArgs = ConstructArgArray(args);
//            try {
//                IntPtr val = JNISafe.CallObjectMethod(RawObject, methodId, jArgs);
//
//                if (val.Equals(IntPtr.Zero)) {
//                    return default(TReturnType);
//                }
//
//                var t = typeof(TReturnType);
//                if (t.IsSubclassOf(typeof(JavaObject))) {
//                    ConstructorInfo c = t.GetConstructor(new[] { val.GetType() });
//                    if (c != null) {
//                        return (TReturnType)c.Invoke(new object[] { val });
//                    }
//                }
//            }
//            finally {
//                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
//            }
//
//            return default(TReturnType);
//        }

        public IntPtr ObjectCall(string name, string className, params object[] args)
        {
            string sig      = GetSignature(className, args);
            IntPtr methodId = AndroidJNIHelper.GetMethodID(RawClass, name, sig, false);

            jvalue[] jArgs = ConstructArgArray(args);
            try {
                IntPtr val = JNISafe.CallObjectMethod(RawObject, methodId, jArgs);

                if (val.Equals(IntPtr.Zero))
                {
                    return(IntPtr.Zero);
                }

                return(val);
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
            }
        }
        public static IntPtr ConvertToJNIArray <TElement>(Array array)
        {
            System.Type elementType = typeof(TElement);

            System.Diagnostics.Debug.Assert(elementType != null, "elementType != null");
            if (elementType.IsSubclassOf(typeof(JavaObject)))
            {
                int      length1 = array.GetLength(0);
                IntPtr[] array2  = new IntPtr[length1];
                IntPtr   class1  = FindClass(GetClass(elementType));
                IntPtr   type    = IntPtr.Zero;
                for (int index = 0; index < length1; ++index)
                {
                    JavaObject obj = array.GetValue(index) as JavaObject;
                    if (obj != null)
                    {
                        array2[index] = obj.RawObject;
                        IntPtr rawClass = obj.RawClass;
                        if (type != rawClass)
                        {
                            type = !(type == IntPtr.Zero) ? class1 : rawClass;
                        }
                    }
                    else
                    {
                        array2[index] = IntPtr.Zero;
                    }
                }
                IntPtr num = JNISafe.ToObjectArray(array2, type);
                JNISafe.DeleteLocalRef(class1);

                return(num);
            }

            return(AndroidJNIHelper.ConvertToJNIArray(array));
        }
        public void Set <TFieldType>(string fieldName, TFieldType val)
        {
            var t = typeof(TFieldType);

            IntPtr fieldId = AndroidJNIHelper.GetFieldID(mClass, fieldName, GetSignature <TFieldType>(), false);

            if (AndroidReflection.IsPrimitive(t))
            {
                if (t == typeof(int))
                {
                    JNISafe.SetIntField(mObject, fieldId, (int)(object)val);
                    return;
                }
                if (t == typeof(bool))
                {
                    JNISafe.SetBooleanField(mObject, fieldId, (bool)(object)val);
                    return;
                }
                if (t == typeof(byte))
                {
                    JNISafe.SetByteField(mObject, fieldId, (byte)(object)val);
                    return;
                }
                if (t == typeof(short))
                {
                    JNISafe.SetShortField(mObject, fieldId, (short)(object)val);
                    return;
                }
                if (t == typeof(long))
                {
                    JNISafe.SetLongField(mObject, fieldId, (long)(object)val);
                    return;
                }
                if (t == typeof(float))
                {
                    JNISafe.SetFloatField(mObject, fieldId, (float)(object)val);
                    return;
                }
                if (t == typeof(double))
                {
                    JNISafe.SetDoubleField(mObject, fieldId, (double)(object)val);
                    return;
                }

                if (t != typeof(char))
                {
                    return;
                }

                JNISafe.SetCharField(mObject, fieldId, (char)(object)val);
                return;
            }

            if (t == typeof(string))
            {
                JNISafe.SetStringField(mObject, fieldId, (string)(object)val);
                return;
            }

            if (t.IsSubclassOf(typeof(JavaObject)))
            {
                JNISafe.SetObjectField(mObject, fieldId, ((JavaObject)(object)val).mObject);
            }
        }
        /// <summary>
        /// Gets the value of an object field.
        ///
        /// <para>
        /// NOTE: be sure you passing correct type (it shoud be the primitive or the type derived from <see cref="JavaObject"/>)!
        /// </para>
        ///
        /// </summary>
        /// <returns>The static object field.</returns>
        /// <param name="name">Field name.</param>
        /// <typeparam name="TFieldType"></typeparam>
        public TFieldType Get <TFieldType>(string name)
        {
            IntPtr fieldId = AndroidJNIHelper.GetFieldID(mClass, name, GetSignature <TFieldType>(), false);

            var t = typeof(TFieldType);

            if (AndroidReflection.IsPrimitive(t))
            {
                if (typeof(TFieldType) == typeof(int))
                {
                    return((TFieldType)(object)JNISafe.GetIntField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(bool))
                {
                    return((TFieldType)(object)JNISafe.GetBooleanField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(byte))
                {
                    return((TFieldType)(object)JNISafe.GetByteField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(short))
                {
                    return((TFieldType)(object)JNISafe.GetShortField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(long))
                {
                    return((TFieldType)(object)JNISafe.GetLongField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(float))
                {
                    return((TFieldType)(object)JNISafe.GetFloatField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(double))
                {
                    return((TFieldType)(object)JNISafe.GetDoubleField(mObject, fieldId));
                }
                if (typeof(TFieldType) == typeof(char))
                {
                    return((TFieldType)(object)JNISafe.GetCharField(mObject, fieldId));
                }
                return(default(TFieldType));
            }

            if (t == typeof(string))
            {
                return((TFieldType)(object)JNISafe.GetStringField(mObject, fieldId));
            }

            if (t.IsSubclassOf(typeof(JavaObject)))
            {
                IntPtr val = JNISafe.GetObjectField(mObject, fieldId);

                if (val == IntPtr.Zero)
                {
                    return(default(TFieldType));
                }

                ConstructorInfo c = t.GetConstructor(new[] { val.GetType() });
                if (c != null)
                {
                    return((TFieldType)c.Invoke(new object[] { val }));
                }

                DebugPrint("Can't instantiate class, probably no constructor with IntPtr arg");
            }

            return(default(TFieldType));
        }
        /// <summary>
        /// Calls a class static method.
        ///
        /// <para>
        /// NOTE: be sure you passing correct type (it shoud be the primitive or the type derived from <see cref="JavaObject"/>)!
        /// </para>
        ///
        /// </summary>
        /// <returns>The invoke call.</returns>
        /// <param name="type">Type.</param>
        /// <param name="name">Method name.</param>
        /// <param name="args">Arguments.</param>
        /// <typeparam name="TReturnType"></typeparam>
        public static TReturnType CallStatic <TReturnType>(string type, string name, params object[] args)
        {
            Type   t        = typeof(TReturnType);
            string sig      = GetSignature <TReturnType>(args);
            IntPtr rawClass = FindClass(type);
            IntPtr method   = AndroidJNIHelper.GetMethodID(rawClass, name, sig, true);

            jvalue[] jArgs = ConstructArgArray(args);
            try {
                if (AndroidReflection.IsPrimitive(t))
                {
                    if (t == typeof(bool))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticBooleanMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(int))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticIntMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(float))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticFloatMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(double))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticDoubleMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(byte))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticByteMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(char))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticCharMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(long))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticLongMethod(rawClass, method, jArgs));
                    }
                    if (t == typeof(short))
                    {
                        return((TReturnType)(object)JNISafe.CallStaticShortMethod(rawClass, method, jArgs));
                    }
                }

                if (t == typeof(string))
                {
                    return((TReturnType)(object)JNISafe.CallStaticStringMethod(rawClass, method, jArgs));
                }

                if (t.IsSubclassOf(typeof(JavaObject)))
                {
                    IntPtr val = JNISafe.CallStaticObjectMethod(rawClass, method, jArgs);

                    if (val == IntPtr.Zero)
                    {
                        return(default(TReturnType));
                    }

                    ConstructorInfo c = t.GetConstructor(new[] { val.GetType() });

                    if (c != null)
                    {
                        return((TReturnType)c.Invoke(new object[] { val }));
                    }
                    else
                    {
                        DebugPrint("Can't instantiate class, probably no constructor with IntPtr arg");
                    }
                }
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
            }

            return(default(TReturnType));
        }
        /// <summary>
        /// Calls a class method.
        ///
        /// <para>
        /// NOTE: be sure you passing correct type (it shoud be the primitive or the type derived from <see cref="JavaObject"/>)!
        /// </para>
        ///
        /// </summary>
        /// <returns>The invoke call.</returns>
        /// <param name="name">Method name.</param>
        /// <param name="args">Arguments.</param>
        /// <typeparam name="TReturnType"></typeparam>
        public TReturnType Call <TReturnType>(string name, params object[] args)
        {
            Type   t        = typeof(TReturnType);
            string sig      = GetSignature <TReturnType>(args);
            IntPtr methodId = AndroidJNIHelper.GetMethodID(RawClass, name, sig, false);

            jvalue[] jArgs = ConstructArgArray(args);
            try {
                if (methodId == IntPtr.Zero)
                {
                    Debug.LogError("Cannot get method for " + name);

                    throw new Exception("Cannot get method for " + name);
                }
                if (AndroidReflection.IsPrimitive(t))
                {
                    if (t == typeof(bool))
                    {
                        return((TReturnType)(object)JNISafe.CallBooleanMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(int))
                    {
                        return((TReturnType)(object)JNISafe.CallIntMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(float))
                    {
                        return((TReturnType)(object)JNISafe.CallFloatMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(double))
                    {
                        return((TReturnType)(object)JNISafe.CallDoubleMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(byte))
                    {
                        return((TReturnType)(object)JNISafe.CallByteMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(char))
                    {
                        return((TReturnType)(object)JNISafe.CallCharMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(long))
                    {
                        return((TReturnType)(object)JNISafe.CallLongMethod(RawObject, methodId, jArgs));
                    }
                    if (t == typeof(short))
                    {
                        return((TReturnType)(object)JNISafe.CallShortMethod(RawObject, methodId, jArgs));
                    }
                }

                if (t == typeof(string))
                {
                    return((TReturnType)(object)JNISafe.CallStringMethod(RawObject, methodId, jArgs));
                }

                if (t.IsSubclassOf(typeof(JavaObject)))
                {
                    IntPtr val = JNISafe.CallObjectMethod(RawObject, methodId, jArgs);

                    if (val == IntPtr.Zero)
                    {
                        return(default(TReturnType));
                    }

                    ConstructorInfo c = t.GetConstructor(new[] { val.GetType() });

                    if (c != null)
                    {
                        return((TReturnType)c.Invoke(new object[] { val }));
                    }
                    else
                    {
                        DebugPrint("Can't instantiate class, probably no constructor with IntPtr arg");
                    }
                }
            }
            finally {
                AndroidJNIHelper.DeleteJNIArgArray(args, jArgs);
            }

            return(default(TReturnType));
        }