github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/asset/asset_android.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package asset 6 7 /* 8 #cgo LDFLAGS: -llog -landroid 9 #include <android/log.h> 10 #include <android/asset_manager.h> 11 #include <android/asset_manager_jni.h> 12 #include <jni.h> 13 #include <stdlib.h> 14 15 #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go/asset", __VA_ARGS__) 16 17 // asset_manager is the asset manager of the app. 18 AAssetManager* asset_manager; 19 20 void asset_manager_init(void* java_vm, void* ctx) { 21 JavaVM* vm = (JavaVM*)(java_vm); 22 JNIEnv* env; 23 int err; 24 int attached = 0; 25 26 err = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6); 27 if (err != JNI_OK) { 28 if (err == JNI_EDETACHED) { 29 if ((*vm)->AttachCurrentThread(vm, &env, 0) != 0) { 30 LOG_FATAL("cannot attach JVM"); 31 } 32 attached = 1; 33 } else { 34 LOG_FATAL("GetEnv unexpected error: %d", err); 35 } 36 } 37 38 // Equivalent to: 39 // assetManager = ctx.getResources().getAssets(); 40 jclass ctx_clazz = (*env)->FindClass(env, "android/content/Context"); 41 jmethodID getres_id = (*env)->GetMethodID(env, ctx_clazz, "getResources", "()Landroid/content/res/Resources;"); 42 jobject res = (*env)->CallObjectMethod(env, ctx, getres_id); 43 jclass res_clazz = (*env)->FindClass(env, "android/content/res/Resources"); 44 jmethodID getam_id = (*env)->GetMethodID(env, res_clazz, "getAssets", "()Landroid/content/res/AssetManager;"); 45 jobject am = (*env)->CallObjectMethod(env, res, getam_id); 46 47 // Pin the AssetManager and load an AAssetManager from it. 48 am = (*env)->NewGlobalRef(env, am); 49 asset_manager = AAssetManager_fromJava(env, am); 50 51 if (attached) { 52 (*vm)->DetachCurrentThread(vm); 53 } 54 } 55 */ 56 import "C" 57 import ( 58 "fmt" 59 "io" 60 "os" 61 "sync" 62 "unsafe" 63 64 "github.com/c-darwin/mobile/internal/mobileinit" 65 ) 66 67 var assetOnce sync.Once 68 69 func assetInit() { 70 ctx := mobileinit.Context{} 71 C.asset_manager_init(ctx.JavaVM(), ctx.AndroidContext()) 72 } 73 74 func openAsset(name string) (File, error) { 75 assetOnce.Do(assetInit) 76 cname := C.CString(name) 77 defer C.free(unsafe.Pointer(cname)) 78 a := &asset{ 79 ptr: C.AAssetManager_open(C.asset_manager, cname, C.AASSET_MODE_UNKNOWN), 80 name: name, 81 } 82 if a.ptr == nil { 83 return nil, a.errorf("open", "bad asset") 84 } 85 return a, nil 86 } 87 88 type asset struct { 89 ptr *C.AAsset 90 name string 91 } 92 93 func (a *asset) errorf(op string, format string, v ...interface{}) error { 94 return &os.PathError{ 95 Op: op, 96 Path: a.name, 97 Err: fmt.Errorf(format, v...), 98 } 99 } 100 101 func (a *asset) Read(p []byte) (n int, err error) { 102 n = int(C.AAsset_read(a.ptr, unsafe.Pointer(&p[0]), C.size_t(len(p)))) 103 if n == 0 && len(p) > 0 { 104 return 0, io.EOF 105 } 106 if n < 0 { 107 return 0, a.errorf("read", "negative bytes: %d", n) 108 } 109 return n, nil 110 } 111 112 func (a *asset) Seek(offset int64, whence int) (int64, error) { 113 // TODO(crawshaw): use AAsset_seek64 if it is available. 114 off := C.AAsset_seek(a.ptr, C.off_t(offset), C.int(whence)) 115 if off == -1 { 116 return 0, a.errorf("seek", "bad result for offset=%d, whence=%d", offset, whence) 117 } 118 return int64(off), nil 119 } 120 121 func (a *asset) Close() error { 122 C.AAsset_close(a.ptr) 123 return nil 124 }