├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── glumes │ │ └── androidcppsolib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── CMakeLists.txt │ │ └── native-lib.cpp │ ├── java │ │ └── com │ │ │ └── glumes │ │ │ └── androidcppsolib │ │ │ ├── MainActivity.kt │ │ │ ├── SoApplication.kt │ │ │ ├── activity │ │ │ ├── AbstractPlayerActivity.kt │ │ │ ├── AviBitmapPlayerActivity.kt │ │ │ ├── AviOpenGLPlayerActivity.kt │ │ │ ├── BitmapOperationActivity.kt │ │ │ ├── InfoManageActivity.kt │ │ │ └── JNIMethodActivity.kt │ │ │ ├── base │ │ │ └── BaseListActivity.kt │ │ │ ├── binder │ │ │ ├── InfoManagerBinder.kt │ │ │ ├── JNIMethodBinder.kt │ │ │ └── MainListItemBinder.kt │ │ │ ├── handler │ │ │ └── JNIOperationHandler.kt │ │ │ ├── utils │ │ │ └── DataBindingUtils.java │ │ │ └── widget │ │ │ ├── CircleImageView.kt │ │ │ └── ItemInfo.kt │ └── res │ │ ├── drawable │ │ ├── avatar.png │ │ ├── info_card_bg.xml │ │ ├── info_item_bg.xml │ │ ├── material_flat.png │ │ ├── minus.png │ │ ├── plus.png │ │ └── woman_16.png │ │ ├── layout │ │ ├── activity_avi_open_glplayer.xml │ │ ├── activity_avi_player.xml │ │ ├── activity_base_list.xml │ │ ├── activity_bitmap_operation.xml │ │ ├── activity_info_manager.xml │ │ ├── info_card.xml │ │ ├── item_jni_method.xml │ │ └── item_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── glumes │ └── androidcppsolib │ └── ExampleUnitTest.java ├── build.gradle ├── cppso ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── glumes │ │ └── cppso │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── CMakeLists.txt │ │ ├── avilib │ │ │ ├── avidump.c │ │ │ ├── avilib.c │ │ │ ├── avilib.h │ │ │ ├── platform.h │ │ │ ├── platform_posix.c │ │ │ ├── platform_tc.c │ │ │ ├── static_avilib.h │ │ │ ├── static_wavlib.h │ │ │ ├── wavlib.c │ │ │ └── wavlib.h │ │ ├── aviplayer │ │ │ ├── AviPlayer.cpp │ │ │ └── AviPlayer.h │ │ ├── common │ │ │ ├── commonutil.cpp │ │ │ ├── commonutil.h │ │ │ └── logutil.h │ │ ├── infomanager │ │ │ ├── LoadManager.cpp │ │ │ ├── Student.cpp │ │ │ └── Student.h │ │ └── jnioperations │ │ │ ├── array-type-operation.cpp │ │ │ ├── basic-type-operation.cpp │ │ │ ├── bitmap_operation.cpp │ │ │ ├── cache_filed_and_method.cpp │ │ │ ├── exceptions-operations.cpp │ │ │ ├── filed_and_method_operation.cpp │ │ │ ├── invoke_constructor.cpp │ │ │ ├── local_and_global_references.cpp │ │ │ ├── native_onload.cpp │ │ │ ├── string-type-operation.cpp │ │ │ ├── thread_operation.cpp │ │ │ └── thread_operation.h │ ├── java │ │ ├── com │ │ │ └── glumes │ │ │ │ └── cppso │ │ │ │ ├── aviplayer │ │ │ │ └── AviPlayer.java │ │ │ │ ├── infomanager │ │ │ │ └── StudentInfoLoader.java │ │ │ │ ├── jnioperations │ │ │ │ ├── ArrayTypeOps.java │ │ │ │ ├── BaseOperation.java │ │ │ │ ├── BasicTypeOps.java │ │ │ │ ├── BitmapOps.java │ │ │ │ ├── CacheFieldAndMethodOps.java │ │ │ │ ├── ExceptionOps.java │ │ │ │ ├── FieldAndMethodOps.java │ │ │ │ ├── InvokeConstructorOps.java │ │ │ │ ├── LocalAndGlobalReferenceOps.java │ │ │ │ ├── NativeOnLoadOps.java │ │ │ │ ├── NoOperation.java │ │ │ │ ├── OperationsFactory.java │ │ │ │ ├── StringTypeOps.java │ │ │ │ └── ThreadOps.java │ │ │ │ ├── model │ │ │ │ ├── Animal.java │ │ │ │ └── Cat.java │ │ │ │ └── utils │ │ │ │ ├── Constants.kt │ │ │ │ └── LogUtil.kt │ │ ├── com_glumes_cppso_aviplayer_AviPlayer.h │ │ └── com_glumes_cppso_jnioperations_BitmapOps.h │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── glumes │ └── cppso │ └── ExampleUnitTest.java ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | 11 | 12 | 13 | .idea/ 14 | 15 | gradle/ 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > 该项目对应的视频课程已在慕课网上线: http://www.imooc.com/learn/1212 2 | 3 | 4 | # Android NDK 开发实践之路 5 | 6 | 在 Android 开发中使用 JNI 和 NDK 技术。 7 | 8 | ## JNI 基础准备 9 | 10 | JNI 全称:**Java Native Interface**。 11 | 12 | 它是独立于 Android 的一套接口,可以实现 Java 代码与 C/C++ 代码之间的交互。 13 | 14 | 打好了 JNI 的基础,才会在 NDK 开发时更加得心应手。 15 | 16 | 输出以下博客: 17 | 18 | * [Android JNI 基本操作](https://glumes.com/post/android/android-jni-basic-operation/) 19 | * [Android JNI 数组 操作](https://glumes.com/post/android/android-jni-array-operation/) 20 | * [Android 通过 JNI 访问 Java 字段和方法调用](https://glumes.com/post/android/android-jni-access-field-and-method/) 21 | * [Android 通过 JNI 调用 Java 类的构造方法和父类的方法](https://glumes.com/post/android/android-jni-invoke-constructor-method-and-super-method/) 22 | * [Android JNI 调用时缓存字段和方法 ID](https://glumes.com/post/android/android-jni-cache-fieldid-and-methodid/) 23 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | android { 7 | compileSdkVersion 26 8 | 9 | defaultConfig { 10 | applicationId "com.glumes.androidcppsolib" 11 | minSdkVersion 22 12 | targetSdkVersion 26 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | externalNativeBuild { 17 | cmake { 18 | cppFlags "-std=c++11" 19 | } 20 | } 21 | 22 | ndk { 23 | abiFilters 'arm64-v8a', 'x86', 'x86_64', 'armeabi-v7a' 24 | } 25 | 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | 34 | externalNativeBuild { 35 | cmake { 36 | path "src/main/cpp/CMakeLists.txt" 37 | } 38 | } 39 | 40 | dataBinding { 41 | enabled = true 42 | } 43 | 44 | } 45 | 46 | dependencies { 47 | implementation fileTree(dir: 'libs', include: ['*.jar']) 48 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 49 | exclude group: 'com.android.support', module: 'support-annotations' 50 | }) 51 | 52 | implementation 'com.android.support:design:26.1.0' 53 | implementation 'com.android.support:cardview-v7:26.1.0' 54 | implementation 'com.android.support:appcompat-v7:26.1.0' 55 | 56 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 57 | testImplementation 'junit:junit:4.12' 58 | implementation 'com.android.support:recyclerview-v7:26.1.0' 59 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 60 | 61 | 62 | 63 | implementation project(':cppso') 64 | 65 | // kapt 'com.android.databinding:compiler:3.1.0' 66 | 67 | implementation 'com.jakewharton.timber:timber:4.6.1' 68 | // debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4' 69 | // releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' 70 | 71 | // 写 demo 用的库 72 | implementation 'com.glumes:sampleutil:0.0.2' 73 | implementation 'com.glumes:databindingadapter:0.0.3' 74 | 75 | implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar' 76 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' 77 | implementation 'io.reactivex.rxjava2:rxjava:2.1.14' 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/glumes/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/glumes/androidcppsolib/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.glumes.androidcppsolib", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | add_library( # Sets the name of the library. 14 | native-lib 15 | 16 | # Sets the library as a shared library. 17 | SHARED 18 | 19 | # Provides a relative path to your source file(s). 20 | ${CMAKE_SOURCE_DIR}/native-lib.cpp ) 21 | 22 | 23 | # Searches for a specified prebuilt library and stores the path as a 24 | # variable. Because CMake includes system libraries in the search path by 25 | # default, you only need to specify the name of the public NDK library 26 | # you want to add. CMake verifies that the library exists before 27 | # completing its build. 28 | 29 | find_library( # Sets the name of the path variable. 30 | log-lib 31 | 32 | # Specifies the name of the NDK library that 33 | # you want CMake to locate. 34 | log ) 35 | 36 | 37 | 38 | # Specifies libraries CMake should link to your target library. You 39 | # can link multiple libraries, such as libraries you define in this 40 | # build script, prebuilt third-party libraries, or system libraries. 41 | 42 | target_link_libraries( # Specifies the target library. 43 | native-lib 44 | 45 | # Links the target library to the log library 46 | # included in the NDK. 47 | ${log-lib} ) 48 | -------------------------------------------------------------------------------- /app/src/main/cpp/native-lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | extern "C" 6 | JNIEXPORT void JNICALL 7 | Java_com_glumes_androidcppsolib_MainActivity_outputString(JNIEnv *env, jobject instance, 8 | jstring msg_) { 9 | const char *msg = env->GetStringUTFChars(msg_, 0); 10 | 11 | env->ReleaseStringUTFChars(msg_, msg); 12 | } 13 | 14 | extern "C" 15 | JNIEXPORT jstring JNICALL 16 | Java_com_glumes_androidcppsolib_MainActivity_stringFromJNI( 17 | JNIEnv *env, 18 | jobject /* this */) { 19 | std::string hello = "Hello from C++"; 20 | 21 | return env->NewStringUTF(hello.c_str()); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib 2 | 3 | 4 | import android.graphics.Color 5 | import android.os.Bundle 6 | import android.support.v7.widget.RecyclerView 7 | import android.support.v7.widget.Toolbar 8 | import com.glumes.androidcppsolib.base.BaseListActivity 9 | import com.glumes.androidcppsolib.binder.MainItem 10 | import com.glumes.androidcppsolib.binder.MainListItemBinder 11 | import com.glumes.cppso.utils.JUMP_BITMAP_OPERATION_ACTIVITY 12 | import com.glumes.cppso.utils.JUMP_GRAPHIC_API_ACTIVITY 13 | import com.glumes.cppso.utils.JUMP_INFO_MANAGER_ACTIVITY 14 | import com.glumes.cppso.utils.JUMP_JNI_METHOD_ACTIVITY 15 | import com.glumes.databindingadapter.DataBindingAdapter 16 | import com.glumes.databindingadapter.Items 17 | 18 | class MainActivity : BaseListActivity() { 19 | 20 | 21 | private val items = Items() 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | items.add(MainItem("JNI • 基础操作", JUMP_JNI_METHOD_ACTIVITY)) 26 | items.add(MainItem("JNI 基础实践 • 学生信息管理", JUMP_INFO_MANAGER_ACTIVITY)) 27 | items.add(MainItem("Native • 图形 API ", JUMP_GRAPHIC_API_ACTIVITY)) 28 | items.add(MainItem("JNI • Bitmap 操作 ", JUMP_BITMAP_OPERATION_ACTIVITY)) 29 | } 30 | 31 | override fun setUpToolbar(toolbar: Toolbar) { 32 | toolbar.title = resources.getString(R.string.app_name) 33 | toolbar.setTitleTextColor(Color.WHITE) 34 | } 35 | 36 | 37 | override fun initAdapter(): RecyclerView.Adapter { 38 | 39 | val mAdapter = DataBindingAdapter() 40 | mAdapter.map(MainItem::class.java, MainListItemBinder()) 41 | .setItems(items) 42 | 43 | return mAdapter 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/SoApplication.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib 2 | 3 | //import com.squareup.leakcanary.LeakCanary 4 | import android.app.Application 5 | import timber.log.Timber 6 | import timber.log.Timber.DebugTree 7 | 8 | 9 | /** 10 | * Created by glumes on 28/02/2018 11 | */ 12 | class SoApplication : Application() { 13 | 14 | override fun onCreate() { 15 | super.onCreate() 16 | initLeakCanary() 17 | initTimber() 18 | 19 | } 20 | 21 | private fun initTimber() { 22 | if (BuildConfig.DEBUG) { 23 | Timber.plant(DebugTree()) 24 | } 25 | } 26 | 27 | private fun initLeakCanary() { 28 | // if (LeakCanary.isInAnalyzerProcess(this)) { 29 | // // This process is dedicated to LeakCanary for heap analysis. 30 | // // You should not init your app in this process. 31 | // return 32 | // } 33 | // LeakCanary.install(this) 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/AbstractPlayerActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | import android.support.v7.app.AppCompatActivity 4 | import com.glumes.cppso.aviplayer.AviPlayer 5 | 6 | /** 7 | * @Author glumes 8 | */ 9 | abstract class AbstractPlayerActivity : AppCompatActivity() { 10 | 11 | protected var mAvi: Long = 0L 12 | 13 | 14 | override fun onStart() { 15 | super.onStart() 16 | } 17 | 18 | 19 | override fun onStop() { 20 | super.onStop() 21 | if (mAvi != 0L) { 22 | AviPlayer.close(mAvi) 23 | mAvi = 0 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/AviBitmapPlayerActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | import android.Manifest 4 | import android.graphics.Bitmap 5 | import android.support.v7.app.AppCompatActivity 6 | import android.os.Bundle 7 | import android.os.Environment 8 | import android.view.SurfaceHolder 9 | import android.view.SurfaceView 10 | import android.widget.Toast 11 | import com.glumes.androidcppsolib.R 12 | import com.glumes.cppso.aviplayer.AviPlayer 13 | import com.glumes.cppso.utils.LogUtil 14 | import com.tbruyelle.rxpermissions2.RxPermissions 15 | import java.io.File 16 | import java.util.concurrent.atomic.AtomicBoolean 17 | 18 | class AviBitmapPlayerActivity : AbstractPlayerActivity() { 19 | 20 | private val path = Environment.getExternalStorageDirectory().toString() + File.separator + "galleon.avi" 21 | 22 | private lateinit var mSurfaceView: SurfaceView 23 | 24 | private var isPlaying = AtomicBoolean() 25 | 26 | private var surfaceHolder: SurfaceHolder? = null 27 | 28 | private lateinit var rxPermissions: RxPermissions 29 | 30 | private val surfaceHolderCallback = object : SurfaceHolder.Callback { 31 | 32 | override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) { 33 | } 34 | 35 | override fun surfaceDestroyed(holder: SurfaceHolder?) { 36 | isPlaying.set(false) 37 | } 38 | 39 | override fun surfaceCreated(holder: SurfaceHolder?) { 40 | isPlaying.set(true) 41 | Thread(renderer).start() 42 | } 43 | } 44 | 45 | private val renderer = Runnable { 46 | val bitmap = Bitmap.createBitmap( 47 | AviPlayer.getWidth(mAvi), 48 | AviPlayer.getHeight(mAvi), 49 | Bitmap.Config.RGB_565 50 | ) 51 | val frameDelay = (1000 / AviPlayer.getFrameRate(mAvi)).toLong() 52 | 53 | while (isPlaying.get()) { 54 | AviPlayer.render(mAvi, bitmap) 55 | val canvas = surfaceHolder!!.lockCanvas() 56 | if (canvas != null) { 57 | canvas.drawBitmap(bitmap, 0f, 0f, null) 58 | surfaceHolder!!.unlockCanvasAndPost(canvas) 59 | Thread.sleep(frameDelay) 60 | } 61 | } 62 | } 63 | 64 | override fun onCreate(savedInstanceState: Bundle?) { 65 | super.onCreate(savedInstanceState) 66 | setContentView(R.layout.activity_avi_player) 67 | 68 | mSurfaceView = findViewById(R.id.surfaceView) 69 | 70 | rxPermissions = RxPermissions(this) 71 | 72 | rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE) 73 | .subscribe { 74 | if (it) { 75 | preparePlay() 76 | } else { 77 | Toast.makeText(this, "No Permission", Toast.LENGTH_SHORT).show() 78 | } 79 | } 80 | } 81 | 82 | private fun preparePlay() { 83 | if (File(path).exists()) { 84 | 85 | mAvi = AviPlayer.open(path) 86 | 87 | printAVIInfo() 88 | 89 | surfaceHolder = mSurfaceView.holder 90 | 91 | surfaceHolder!!.addCallback(surfaceHolderCallback) 92 | } else { 93 | Toast.makeText(this, "File not exist", Toast.LENGTH_SHORT).show() 94 | } 95 | } 96 | 97 | 98 | private fun printAVIInfo() { 99 | LogUtil.d("file path is $path") 100 | LogUtil.d("get avi id is $mAvi") 101 | LogUtil.d("get avi width is " + AviPlayer.getWidth(mAvi)) 102 | LogUtil.d("get avi height is " + AviPlayer.getHeight(mAvi)) 103 | LogUtil.d("get avi frameRate is " + AviPlayer.getFrameRate(mAvi)) 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/AviOpenGLPlayerActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | import android.opengl.GLSurfaceView 4 | import android.support.v7.app.AppCompatActivity 5 | import android.os.Bundle 6 | import com.glumes.androidcppsolib.R 7 | import com.glumes.cppso.aviplayer.AviPlayer 8 | import java.util.concurrent.atomic.AtomicBoolean 9 | import javax.microedition.khronos.egl.EGLConfig 10 | import javax.microedition.khronos.opengles.GL10 11 | 12 | class AviOpenGLPlayerActivity : AppCompatActivity() { 13 | 14 | 15 | private var isPlaying = AtomicBoolean() 16 | 17 | private var instance: Long = 0 18 | private var mAvi: Long = 0L 19 | 20 | private lateinit var glSurfaceView: GLSurfaceView 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | setContentView(R.layout.activity_avi_open_glplayer) 25 | 26 | glSurfaceView = findViewById(R.id.glsurfaceview) 27 | 28 | 29 | } 30 | 31 | override fun onStart() { 32 | super.onStart() 33 | instance = AviPlayer.init(mAvi) 34 | } 35 | 36 | override fun onResume() { 37 | super.onResume() 38 | } 39 | 40 | override fun onPause() { 41 | super.onPause() 42 | } 43 | 44 | override fun onStop() { 45 | super.onStop() 46 | } 47 | 48 | private val renderer = object :GLSurfaceView.Renderer{ 49 | 50 | override fun onDrawFrame(gl: GL10?) { 51 | } 52 | 53 | override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { 54 | } 55 | 56 | override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { 57 | // initSurface(instance,mAvi) 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/BitmapOperationActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.BitmapFactory 5 | import android.support.v7.app.AppCompatActivity 6 | import android.os.Bundle 7 | import com.glumes.androidcppsolib.R 8 | import com.glumes.cppso.jnioperations.BitmapOps 9 | import com.glumes.cppso.utils.LogUtil 10 | import kotlinx.android.synthetic.main.activity_bitmap_operation.* 11 | 12 | class BitmapOperationActivity : AppCompatActivity() { 13 | 14 | 15 | private val mBitmapOps = BitmapOps() 16 | lateinit var mBitmap: Bitmap 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_bitmap_operation) 20 | 21 | initBitmap() 22 | 23 | // 顺时针旋转 90° 的操作 24 | rotate.setOnClickListener { rotateBitmap(mBitmap) } 25 | // 上下翻转的操作 26 | convert.setOnClickListener { convertBitmap(mBitmap) } 27 | // 左右对调的操作 28 | mirror.setOnClickListener { mirrorBitmap(mBitmap) } 29 | } 30 | 31 | private fun initBitmap() { 32 | mBitmap = BitmapFactory.decodeResource(resources, R.drawable.avatar) 33 | } 34 | 35 | private fun rotateBitmap(bitmap: Bitmap) { 36 | val result = mBitmapOps.rotateBitmap(bitmap) 37 | updateBitmap(result) 38 | } 39 | 40 | private fun convertBitmap(bitmap: Bitmap) { 41 | val result = mBitmapOps.convertBitmap(bitmap) 42 | updateBitmap(result) 43 | } 44 | 45 | private fun mirrorBitmap(bitmap: Bitmap) { 46 | val result = mBitmapOps.mirrorBitmap(bitmap) 47 | updateBitmap(result) 48 | } 49 | 50 | private fun updateBitmap(bitmap: Bitmap?) { 51 | if (bitmap == null) { 52 | LogUtil.e("operation failed") 53 | } 54 | resultView.setImageBitmap(bitmap) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/InfoManageActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | import android.os.Bundle 4 | import android.support.design.widget.FloatingActionButton 5 | import android.support.v7.app.AppCompatActivity 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.support.v7.widget.RecyclerView 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import com.glumes.androidcppsolib.R 11 | import com.glumes.androidcppsolib.base.BaseListActivity 12 | import com.glumes.androidcppsolib.binder.InfoManagerBinder 13 | import com.glumes.androidcppsolib.binder.SampleBinder 14 | import com.glumes.androidcppsolib.binder.SampleModel 15 | import com.glumes.androidcppsolib.binder.Student 16 | import com.glumes.cppso.infomanager.StudentInfoLoader 17 | import com.glumes.cppso.utils.* 18 | import com.glumes.databindingadapter.DataBindingAdapter 19 | import com.glumes.databindingadapter.Items 20 | 21 | class InfoManageActivity : BaseListActivity(), View.OnClickListener { 22 | 23 | 24 | private var mItems = Items() 25 | 26 | lateinit var mPlus: FloatingActionButton 27 | lateinit var mMinus: FloatingActionButton 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | initData() 32 | mPlus = findViewById(R.id.plus) 33 | mMinus = findViewById(R.id.minus) 34 | mPlus.setOnClickListener(this) 35 | mMinus.setOnClickListener(this) 36 | } 37 | 38 | private fun initData() { 39 | mItems.add(Student("name", 1, "male", 12, 12, R.drawable.woman_16)) 40 | loadData() 41 | } 42 | 43 | override fun getLayoutId(): Int { 44 | return R.layout.activity_info_manager 45 | } 46 | 47 | override fun initAdapter(): RecyclerView.Adapter { 48 | val mAdapter = DataBindingAdapter() 49 | 50 | mAdapter 51 | .map(SampleModel::class.java, SampleBinder()) 52 | .map(Student::class.java, InfoManagerBinder()) 53 | .setItems(mItems) 54 | 55 | return mAdapter 56 | } 57 | 58 | override fun onClick(v: View) { 59 | when (v.id) { 60 | R.id.minus -> { 61 | minusData() 62 | } 63 | R.id.plus -> { 64 | plusData() 65 | } 66 | } 67 | } 68 | 69 | companion object { 70 | init { 71 | System.loadLibrary("info-manger") 72 | } 73 | } 74 | 75 | private external fun loadData() 76 | 77 | private external fun plusData() 78 | 79 | private external fun minusData() 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/activity/JNIMethodActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.activity 2 | 3 | 4 | import android.graphics.Color 5 | import android.os.Bundle 6 | import android.support.v7.widget.RecyclerView 7 | import android.support.v7.widget.Toolbar 8 | import com.glumes.androidcppsolib.base.BaseListActivity 9 | import com.glumes.androidcppsolib.binder.SampleBinder 10 | import com.glumes.androidcppsolib.binder.SampleModel 11 | import com.glumes.cppso.utils.* 12 | import com.glumes.databindingadapter.DataBindingAdapter 13 | import com.glumes.databindingadapter.Items 14 | 15 | class JNIMethodActivity : BaseListActivity() { 16 | 17 | 18 | private val items = Items() 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | initData() 23 | } 24 | 25 | override fun setUpToolbar(toolbar: Toolbar) { 26 | toolbar.title = "JNI 方法调用" 27 | } 28 | 29 | private fun initData() { 30 | items.add(SampleModel("JNI 动态注册", NATIVE_ON_LOAD)) 31 | items.add(SampleModel("JNI 基础类型操作", NATIVE_BASIC_TYPE)) 32 | items.add(SampleModel("JNI String 操作", NATIVE_STRING)) 33 | items.add(SampleModel("JNI 数组操作", NATIVE_ARRAY)) 34 | items.add(SampleModel("JNI 访问 Java 字段和方法", NATIVE_FIELD_AND_METHOD)) 35 | items.add(SampleModel("JNI 调用构造方法", NATIVE_INVOKE_CONSTRUCTORS)) 36 | items.add(SampleModel("JNI 缓存字段和方法", NATIVE_CACHE_FIELD_AND_METHOD)) 37 | items.add(SampleModel("JNI 不同引用类型管理", NATIVE_LOCAL_AND_GLOBAL_REFERENCES)) 38 | items.add(SampleModel("JNI 异常处理", NATIVE_EXCEPTIONS_OPERATIONS)) 39 | items.add(SampleModel("JNI 线程操作", NATIVE_THREAD_OPS)) 40 | } 41 | 42 | override fun initAdapter(): RecyclerView.Adapter { 43 | 44 | val mAdapter = DataBindingAdapter() 45 | 46 | mAdapter.map(SampleModel::class.java, SampleBinder()).setItems(items) 47 | 48 | return mAdapter 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/base/BaseListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.base 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.support.annotation.LayoutRes 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.support.v7.widget.RecyclerView 8 | import android.support.v7.widget.Toolbar 9 | import com.glumes.androidcppsolib.R 10 | import com.glumes.sampleutil.BaseToolbarActivity 11 | 12 | /** 13 | * Created by glumes on 28/02/2018 14 | */ 15 | abstract class BaseListActivity : BaseToolbarActivity() { 16 | 17 | 18 | lateinit var mRecyclerView: RecyclerView 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(getLayoutId()) 23 | 24 | mRecyclerView = findViewById(R.id.mRecyclerView) 25 | 26 | initRecyclerView() 27 | } 28 | 29 | @LayoutRes 30 | open fun getLayoutId(): Int { 31 | return R.layout.activity_base_list 32 | } 33 | 34 | fun initRecyclerView() { 35 | val layoutManager = LinearLayoutManager(this) 36 | layoutManager.orientation = LinearLayoutManager.VERTICAL 37 | mRecyclerView.layoutManager = layoutManager 38 | mRecyclerView.setHasFixedSize(true) 39 | 40 | mRecyclerView.adapter = initAdapter() 41 | } 42 | 43 | abstract fun initAdapter(): RecyclerView.Adapter 44 | 45 | override fun setUpToolbar(toolbar: Toolbar) { 46 | toolbar.title = getString(R.string.app_name) 47 | toolbar.setTitleTextColor(Color.WHITE) 48 | } 49 | 50 | 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/binder/InfoManagerBinder.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.binder 2 | 3 | import android.databinding.DataBindingUtil 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import com.glumes.androidcppsolib.R 7 | import com.glumes.androidcppsolib.databinding.InfoCardBinding 8 | import com.glumes.databindingadapter.BindingViewHolder 9 | import com.glumes.databindingadapter.ViewHolderBinder 10 | 11 | /** 12 | * Created by glumes on 26/03/2018 13 | */ 14 | 15 | data class Student(var name: String, var age: Int, var sex: String, var grade: Int, var stuId: Int, var avatarId: Int) 16 | 17 | class InfoManagerViewHolder(binding: InfoCardBinding) : BindingViewHolder(binding) { 18 | 19 | override fun onBind(data: Student?, position: Int) { 20 | mBinding.model = data 21 | mBinding.executePendingBindings() 22 | } 23 | } 24 | 25 | class InfoManagerBinder : ViewHolderBinder() { 26 | 27 | override fun onBindViewHolder(holder: InfoManagerViewHolder?, data: Student?, position: Int) { 28 | holder!!.onBind(data, position) 29 | } 30 | 31 | override fun createViewHolder(inflater: LayoutInflater?, parent: ViewGroup?): InfoManagerViewHolder { 32 | val mBindind = DataBindingUtil.inflate(inflater!!, R.layout.info_card, parent, false) 33 | return InfoManagerViewHolder(mBindind) 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/binder/JNIMethodBinder.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.binder 2 | 3 | import android.databinding.DataBindingUtil 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.glumes.androidcppsolib.R 8 | import com.glumes.androidcppsolib.databinding.ItemJniMethodBinding 9 | import com.glumes.androidcppsolib.handler.JNIOperationHandler 10 | import com.glumes.cppso.utils.NO_NATIVE_OPERATION 11 | import com.glumes.databindingadapter.BindingViewHolder 12 | import com.glumes.databindingadapter.ViewHolderBinder 13 | 14 | /** 15 | * Created by glumes on 28/02/2018 16 | */ 17 | data class SampleModel(var content: String, val type: Int = NO_NATIVE_OPERATION) 18 | 19 | 20 | class SampleViewHolder(binding: ItemJniMethodBinding?) : BindingViewHolder(binding) { 21 | 22 | override fun onBind(data: SampleModel?, position: Int) { 23 | mBinding.model = data!! 24 | mBinding.executePendingBindings() 25 | mBinding.eventhandler = NativeEventHandler() 26 | } 27 | } 28 | 29 | 30 | class SampleBinder : ViewHolderBinder() { 31 | 32 | override fun onBindViewHolder(holder: SampleViewHolder?, data: SampleModel?, position: Int) { 33 | holder!!.onBind(data, position) 34 | } 35 | 36 | override fun createViewHolder(inflater: LayoutInflater?, parent: ViewGroup?): SampleViewHolder { 37 | val mBinding = DataBindingUtil.inflate(inflater!!, R.layout.item_jni_method, parent, false) as ItemJniMethodBinding 38 | return SampleViewHolder(mBinding) 39 | } 40 | } 41 | 42 | 43 | class NativeEventHandler { 44 | 45 | fun onClick(view: View, model: SampleModel) { 46 | JNIOperationHandler.handle(model.type) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/binder/MainListItemBinder.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.binder 2 | 3 | import android.content.Intent 4 | import android.databinding.DataBindingUtil 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import com.glumes.androidcppsolib.R 9 | import com.glumes.androidcppsolib.activity.AviBitmapPlayerActivity 10 | import com.glumes.androidcppsolib.activity.BitmapOperationActivity 11 | import com.glumes.androidcppsolib.databinding.ItemMainBinding 12 | import com.glumes.androidcppsolib.activity.InfoManageActivity 13 | import com.glumes.androidcppsolib.activity.JNIMethodActivity 14 | import com.glumes.cppso.utils.JUMP_BITMAP_OPERATION_ACTIVITY 15 | import com.glumes.cppso.utils.JUMP_GRAPHIC_API_ACTIVITY 16 | import com.glumes.cppso.utils.JUMP_INFO_MANAGER_ACTIVITY 17 | import com.glumes.cppso.utils.JUMP_JNI_METHOD_ACTIVITY 18 | import com.glumes.databindingadapter.BindingViewHolder 19 | import com.glumes.databindingadapter.ViewHolderBinder 20 | 21 | /** 22 | * Created by glumes on 26/03/2018 23 | */ 24 | 25 | data class MainItem(var title: String, var type: Int) 26 | 27 | class MainViewHolder(binding: ItemMainBinding) : BindingViewHolder(binding) { 28 | 29 | override fun onBind(data: MainItem?, position: Int) { 30 | mBinding.model = data!! 31 | mBinding.executePendingBindings() 32 | mBinding.eventhandler = MainEventHandler() 33 | } 34 | 35 | } 36 | 37 | 38 | class MainListItemBinder : ViewHolderBinder() { 39 | 40 | override fun onBindViewHolder(holder: MainViewHolder?, data: MainItem?, position: Int) { 41 | holder!!.onBind(data, position) 42 | } 43 | 44 | override fun createViewHolder(inflater: LayoutInflater?, parent: ViewGroup?): MainViewHolder { 45 | val mBinding = DataBindingUtil.inflate(inflater!!, R.layout.item_main, parent, false) as ItemMainBinding 46 | return MainViewHolder(mBinding) 47 | } 48 | 49 | } 50 | 51 | 52 | class MainEventHandler { 53 | 54 | fun onClick(view: View, model: MainItem) { 55 | when (model.type) { 56 | JUMP_JNI_METHOD_ACTIVITY -> { 57 | view.context.startActivity(Intent(view.context, JNIMethodActivity::class.java)) 58 | } 59 | 60 | JUMP_INFO_MANAGER_ACTIVITY -> { 61 | view.context.startActivity(Intent(view.context, InfoManageActivity::class.java)) 62 | } 63 | 64 | JUMP_GRAPHIC_API_ACTIVITY -> { 65 | view.context.startActivity(Intent(view.context, AviBitmapPlayerActivity::class.java)) 66 | } 67 | 68 | JUMP_BITMAP_OPERATION_ACTIVITY -> { 69 | view.context.startActivity(Intent(view.context, BitmapOperationActivity::class.java)) 70 | } 71 | } 72 | } 73 | 74 | } 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/handler/JNIOperationHandler.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.handler 2 | 3 | import com.glumes.cppso.jnioperations.OperationsFactory 4 | 5 | /** 6 | * @Author glumes 7 | */ 8 | 9 | class JNIOperationHandler { 10 | 11 | companion object { 12 | 13 | fun handle(type: Int) { 14 | 15 | OperationsFactory.getInstance().getOperations(type).invoke() 16 | 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/utils/DataBindingUtils.java: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.utils; 2 | 3 | import android.content.res.Resources; 4 | import android.databinding.BindingAdapter; 5 | import android.graphics.drawable.Drawable; 6 | import android.widget.ImageView; 7 | 8 | import com.glumes.androidcppsolib.R; 9 | 10 | /** 11 | * @Author glumes 12 | */ 13 | 14 | public class DataBindingUtils { 15 | 16 | @BindingAdapter("app:imageDrawableId") 17 | public static void bindImageDrawable(ImageView view, Integer drawableId) { 18 | 19 | try { 20 | Drawable drawable = view.getContext().getResources().getDrawable(drawableId); 21 | view.setImageDrawable(drawable); 22 | } catch (Resources.NotFoundException e) { 23 | view.setImageResource(R.drawable.woman_16); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/widget/CircleImageView.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.ImageView 6 | 7 | /** 8 | * @Author glumes 9 | */ 10 | class CircleImageView @JvmOverloads constructor( 11 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 12 | ) : ImageView(context, attrs, defStyleAttr) { 13 | 14 | 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/glumes/androidcppsolib/widget/ItemInfo.kt: -------------------------------------------------------------------------------- 1 | package com.glumes.androidcppsolib.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.LinearLayout 6 | 7 | /** 8 | * @Author glumes 9 | */ 10 | class ItemInfo @JvmOverloads constructor( 11 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 12 | ) : LinearLayout(context, attrs, defStyleAttr) { 13 | 14 | init { 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glumes/AndroidDevWithCpp/1223713cf634ad9e515641aba3245c284f205bc7/app/src/main/res/drawable/avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/info_card_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/info_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/material_flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glumes/AndroidDevWithCpp/1223713cf634ad9e515641aba3245c284f205bc7/app/src/main/res/drawable/material_flat.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glumes/AndroidDevWithCpp/1223713cf634ad9e515641aba3245c284f205bc7/app/src/main/res/drawable/minus.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glumes/AndroidDevWithCpp/1223713cf634ad9e515641aba3245c284f205bc7/app/src/main/res/drawable/plus.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/woman_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glumes/AndroidDevWithCpp/1223713cf634ad9e515641aba3245c284f205bc7/app/src/main/res/drawable/woman_16.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_avi_open_glplayer.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_avi_player.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_base_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_bitmap_operation.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 26 | 27 | 33 | 34 | 44 | 45 |