├── .gitignore ├── MyToast.js ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lighters │ │ └── demos │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── aidl │ │ └── com │ │ │ └── lighters │ │ │ └── demos │ │ │ └── ITestAidlInterface.aidl │ ├── java │ │ └── com │ │ │ └── lighters │ │ │ └── demos │ │ │ ├── MainActivity.java │ │ │ ├── aidl │ │ │ ├── LocalClientActivity.java │ │ │ └── RemoteService.java │ │ │ ├── anim │ │ │ ├── FirstActivity.java │ │ │ └── SecondActivity.java │ │ │ ├── app │ │ │ └── base │ │ │ │ ├── BaseActivity.java │ │ │ │ └── BaseApplication.java │ │ │ ├── canvas │ │ │ └── conver │ │ │ │ ├── CanvasCoverActivity.java │ │ │ │ └── RoundPointView.java │ │ │ ├── jni │ │ │ └── JniTestActivity.java │ │ │ ├── reactnative │ │ │ ├── MyToastModule.java │ │ │ ├── ToastExampleReactPackage.java │ │ │ └── ToastRnActivity.java │ │ │ ├── service │ │ │ └── test │ │ │ │ ├── TestIntentActivity.java │ │ │ │ └── TestIntentService.java │ │ │ ├── token │ │ │ ├── TokenTestActivity.java │ │ │ └── http │ │ │ │ ├── GlobalToken.java │ │ │ │ ├── IGlobalManager.java │ │ │ │ ├── RetrofitUtil.java │ │ │ │ ├── api │ │ │ │ ├── ApiModel.java │ │ │ │ ├── ErrorCode.java │ │ │ │ ├── IApiService.java │ │ │ │ ├── ResultModel.java │ │ │ │ └── TokenModel.java │ │ │ │ ├── converter │ │ │ │ ├── GsonConverterFactory.java │ │ │ │ ├── GsonRequestBodyConverter.java │ │ │ │ └── GsonResponseBodyConverter.java │ │ │ │ ├── exception │ │ │ │ ├── ApiException.java │ │ │ │ ├── TokenInvalidException.java │ │ │ │ └── TokenNotExistException.java │ │ │ │ └── proxy │ │ │ │ └── ProxyHandler.java │ │ │ └── util │ │ │ └── ColorUtil.java │ ├── jni │ │ ├── Android.mk │ │ ├── Application.mk │ │ └── hello-jni.c │ ├── libs │ │ ├── arm64-v8a │ │ │ └── libhello-jni.so │ │ ├── armeabi-v7a │ │ │ └── libhello-jni.so │ │ ├── armeabi │ │ │ └── libhello-jni.so │ │ ├── mips │ │ │ └── libhello-jni.so │ │ ├── mips64 │ │ │ └── libhello-jni.so │ │ ├── x86 │ │ │ └── libhello-jni.so │ │ └── x86_64 │ │ │ └── libhello-jni.so │ └── res │ │ ├── layout │ │ ├── activity_aidl.xml │ │ ├── activity_canvas_cover.xml │ │ ├── activity_first.xml │ │ ├── activity_intent_service_test.xml │ │ ├── activity_main.xml │ │ ├── activity_second.xml │ │ └── activity_token_test.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── lighters │ └── demos │ └── junit │ ├── AssertTests.java │ └── RuleTest.java ├── asmtest ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── lighters │ └── asm │ ├── Example.java │ └── HelloWorld.java ├── build.gradle ├── gradle-app.setting ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── index.android.js ├── mockito ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── lighters │ │ └── mockito │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── lighters │ └── mockito │ └── MockTest.java ├── mybutton.png ├── package.json ├── robolectric ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lighters │ │ └── robolectric │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lighters │ │ │ └── robolectric │ │ │ ├── TestMainActivity.java │ │ │ └── TestToastActivity.java │ └── res │ │ ├── layout │ │ └── test_main_layout.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── lighters │ └── robolectric │ ├── CustomShadowTest.java │ ├── CustomShadowToast.java │ └── RobolectricTestMainActivity.java ├── server └── refresh_token.js └── 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 | 10 | # Custom 11 | _site 12 | 13 | # Ant 14 | MANIFEST.MF 15 | ./*.jar 16 | build.num 17 | build 18 | 19 | # ADT 20 | .classpath 21 | .project 22 | .settings 23 | local.properties 24 | bin 25 | gen 26 | _layouts 27 | proguard.cfg 28 | 29 | # OSX 30 | .DS_Store 31 | 32 | # Github 33 | gh-pages 34 | 35 | # Gradle 36 | .gradle 37 | build 38 | 39 | # IDEA 40 | *.iml 41 | *.ipr 42 | *.iws 43 | out 44 | .idea 45 | 46 | # Maven 47 | target 48 | release.properties 49 | pom.xml.* 50 | 51 | # VIM 52 | *.swp 53 | 54 | 55 | # React Native 56 | node_modules 57 | .flowconfig 58 | *.log 59 | -------------------------------------------------------------------------------- /MyToast.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | import { NativeModules } from 'react-native'; 5 | module.exports = NativeModules.MyToast; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Android Test Demos 2 | 记录一些 Android 的简单测试Demo 以及实现。 3 | 4 | ## SCREEN ANIM 5 | desc: 界面( Activity )之前切换动画的原理实现测试。 6 | 7 | 对应代码为:anim 包。 8 | 9 | 主要内容:去掉界面间的跳转动画,在第二个界面设置与第一个界面相同的元素。界面跳转之后,对第二个界面的元素做动画,给人以还是在同一个界面的错觉。 10 | 11 | ## JNI TEST 12 | desc: 测试 JNI 调用的简单 Demo. 13 | 14 | 对应代码: jni 包。 15 | 16 | ## TOKEN TEST 17 | desc: 实现 APP 请求的 token 的自动刷新 18 | 19 | 对应代码:token 包 , 根目录下的 server 文件夹 20 | 21 | 介绍文章: 22 | + [Rxjava+Retrofit 实现全局过期 Token 自动刷新](http://alighters.com/blog/2016/05/02/rxjava-plus-retrofitshi-xian-wang-luo-dai-li/) 23 | + [RxJava+Retrofit实现全局过期token自动刷新Demo篇](http://alighters.com/blog/2016/08/22/rxjava-plus-retrofitshi-xian-zhi-demo/) 24 | 25 | 启动: 需要在 server 文件夹下, 执行 `node refresh_token.js`, 用来启动本地服务。 26 | 27 | ## INTENTSERVICE TEST 28 | desc: 测试当使用 IntentService 启动一个耗时的任务,通过 Service 的 stop 方法,并不会将这个耗时的任务也终止掉。 29 | 30 | 对应代码: service.test 包下 31 | 32 | ## INSTANT RUN HOT TEST 33 | desc: 当开启 Instant Run 时,对一个方法内部的实现做简单的修改,来查看类加载的情况。(主要为类中的 $change 字段) 34 | 35 | 代码:MainActivity 中的 testInstantRunHotMode 方法。 36 | 37 | ## REACT NATIVE TEST 38 | desc: 将当前项目集成 React Native 内容,并使用 NativeModule 来测试对 native 代码的调用。 39 | 40 | 代码: reactnative 包 41 | 42 | 启动: 需要在根目录下,执行 `npm install `, `npm start` 命令。 43 | 44 | ## AIDL TEST 45 | desc: 测试 aidl 的使用 46 | 47 | 代码: aidl 包 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-apt' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion '25.0.0' 7 | 8 | defaultConfig { 9 | applicationId "com.lighters.demos" 10 | minSdkVersion 16 11 | targetSdkVersion 21 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | sourceSets.main { 22 | // jniLibs.srcDirs = ['src/main/libs'] // <-- Set your folder here! 23 | } 24 | 25 | compileOptions.incremental = true 26 | } 27 | 28 | dependencies { 29 | compile fileTree(dir: 'libs', include: ['*.jar']) 30 | 31 | // view 32 | compile 'com.android.support:appcompat-v7:23.1.0' 33 | 34 | 35 | compile 'com.jakewharton:butterknife:8.2.1' 36 | apt 'com.jakewharton:butterknife-compiler:8.2.1' 37 | 38 | compile 'com.squareup.retrofit2:retrofit:2.1.0' 39 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 40 | compile 'com.squareup.okhttp3:okhttp:3.4.1' 41 | compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' 42 | compile 'com.google.code.gson:gson:2.5' 43 | compile 'io.reactivex:rxjava:1.1.9' 44 | compile 'io.reactivex:rxandroid:1.2.1' 45 | 46 | compile "com.facebook.react:react-native:+" 47 | 48 | // test 49 | testCompile 'junit:junit:4.12' 50 | } 51 | -------------------------------------------------------------------------------- /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/david/dev/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lighters/demos/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/lighters/demos/ITestAidlInterface.aidl: -------------------------------------------------------------------------------- 1 | // ITestAidlInterface.aidl 2 | package com.lighters.demos; 3 | 4 | // Declare any non-default types here with import statements 5 | 6 | interface ITestAidlInterface { 7 | /** 8 | * Demonstrates some basic types that you can use as parameters 9 | * and return values in AIDL. 10 | */ 11 | void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 12 | double aDouble, String aString); 13 | 14 | String sayHello(String msg); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.widget.Toast; 6 | import butterknife.OnClick; 7 | import com.lighters.demos.aidl.LocalClientActivity; 8 | import com.lighters.demos.anim.FirstActivity; 9 | import com.lighters.demos.app.base.BaseActivity; 10 | import com.lighters.demos.canvas.conver.CanvasCoverActivity; 11 | import com.lighters.demos.jni.JniTestActivity; 12 | import com.lighters.demos.reactnative.ToastRnActivity; 13 | import com.lighters.demos.service.test.TestIntentActivity; 14 | import com.lighters.demos.token.TokenTestActivity; 15 | 16 | public class MainActivity extends BaseActivity { 17 | 18 | @Override 19 | protected int getLayoutId() { 20 | return R.layout.activity_main; 21 | } 22 | 23 | @Override 24 | protected void setView(Bundle savedInstanceState) { 25 | 26 | } 27 | 28 | @Override 29 | protected void initData() { 30 | 31 | } 32 | 33 | @OnClick(R.id.btn_screen_anim) 34 | void gotoAnimScreen() { 35 | startActivity(new Intent(this, FirstActivity.class)); 36 | } 37 | 38 | @OnClick(R.id.btn_jni_test) 39 | void gotoJniTest() { 40 | startActivity(new Intent(this, JniTestActivity.class)); 41 | } 42 | 43 | @OnClick(R.id.btn_token_test) 44 | void gotoTokenTest() { 45 | startActivity(new Intent(this, TokenTestActivity.class)); 46 | } 47 | 48 | @OnClick(R.id.btn_intent_service_test) 49 | void gotoIntentServiceTest() { 50 | startActivity(new Intent(this, TestIntentActivity.class)); 51 | } 52 | 53 | @OnClick(R.id.btn_instant_run_hot_test) 54 | void testInstantRunHotMode() { 55 | String abc = "Instant Run Test224"; 56 | Toast.makeText(this, abc, Toast.LENGTH_SHORT).show(); 57 | } 58 | 59 | @OnClick(R.id.btn_rn_test) 60 | void testReactNativeInvoke() { 61 | startActivity(new Intent(this, ToastRnActivity.class)); 62 | } 63 | 64 | @OnClick(R.id.btn_aidl_test) 65 | void testAidl() { 66 | startActivity(new Intent(this, LocalClientActivity.class)); 67 | } 68 | 69 | @OnClick(R.id.btn_canvas_cover_test) 70 | void testCanvasCoverTest() { 71 | startActivity(new Intent(this, CanvasCoverActivity.class)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/aidl/LocalClientActivity.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.aidl; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.content.pm.PackageManager; 8 | import android.content.pm.ResolveInfo; 9 | import android.os.Bundle; 10 | import android.os.IBinder; 11 | import android.os.RemoteException; 12 | import android.view.View; 13 | import android.widget.Button; 14 | import android.widget.EditText; 15 | import android.widget.Toast; 16 | import butterknife.BindView; 17 | import com.lighters.demos.ITestAidlInterface; 18 | import com.lighters.demos.R; 19 | import com.lighters.demos.app.base.BaseActivity; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by david on 16/11/8. 24 | * Email: huangdiv5@gmail.com 25 | * GitHub: https://github.com/alighters 26 | */ 27 | 28 | public class LocalClientActivity extends BaseActivity { 29 | 30 | private static final String ACTION_BIND_SERVICE = "com.lighters.demos.RemoteService"; 31 | 32 | @BindView(R.id.et_message) EditText mEtMessage; 33 | @BindView(R.id.btn_send) Button mBtnSend; 34 | 35 | ITestAidlInterface mTestAidlInterface; 36 | 37 | @Override 38 | protected int getLayoutId() { 39 | return R.layout.activity_aidl; 40 | } 41 | 42 | @Override 43 | protected void setView(Bundle savedInstanceState) { 44 | mBtnSend.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | if (mTestAidlInterface != null) { 48 | try { 49 | Toast.makeText(LocalClientActivity.this, mTestAidlInterface.sayHello(mEtMessage.getText().toString()), 50 | Toast.LENGTH_LONG).show(); 51 | } catch (RemoteException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | } 56 | }); 57 | } 58 | 59 | @Override 60 | protected void initData() { 61 | Intent intent = new Intent(); 62 | intent.setAction(ACTION_BIND_SERVICE); 63 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 64 | bindService(createExplicitFromImplicitIntent(this, intent), mConnection, BIND_AUTO_CREATE); 65 | } 66 | 67 | private ServiceConnection mConnection = new ServiceConnection() { 68 | @Override 69 | public void onServiceConnected(ComponentName name, IBinder service) { 70 | mTestAidlInterface = ITestAidlInterface.Stub.asInterface(service); 71 | } 72 | 73 | @Override 74 | public void onServiceDisconnected(ComponentName name) { 75 | mTestAidlInterface = null; 76 | } 77 | }; 78 | 79 | @Override 80 | protected void onDestroy() { 81 | super.onDestroy(); 82 | if (mTestAidlInterface != null) { 83 | unbindService(mConnection); 84 | } 85 | } 86 | 87 | /*** 88 | * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, 89 | * "java.lang.IllegalArgumentException: Service Intent must be explicit" 90 | * 91 | * If you are using an implicit intent, and know only 1 target would answer this intent, 92 | * This method will help you turn the implicit intent into the explicit form. 93 | * 94 | * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 95 | * 96 | * @param implicitIntent - The original implicit intent 97 | * @return Explicit Intent created from the implicit original intent 98 | */ 99 | public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { 100 | // Retrieve all services that can match the given intent 101 | PackageManager pm = context.getPackageManager(); 102 | List resolveInfo = pm.queryIntentServices(implicitIntent, 0); 103 | 104 | // Make sure only one match was found 105 | if (resolveInfo == null || resolveInfo.size() != 1) { 106 | return null; 107 | } 108 | 109 | // Get component info and create ComponentName 110 | ResolveInfo serviceInfo = resolveInfo.get(0); 111 | String packageName = serviceInfo.serviceInfo.packageName; 112 | String className = serviceInfo.serviceInfo.name; 113 | ComponentName component = new ComponentName(packageName, className); 114 | 115 | // Create a new intent. Use the old one for extras and such reuse 116 | Intent explicitIntent = new Intent(implicitIntent); 117 | 118 | // Set the component to be explicit 119 | explicitIntent.setComponent(component); 120 | 121 | return explicitIntent; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/aidl/RemoteService.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.aidl; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.os.Parcel; 7 | import android.os.RemoteException; 8 | import android.support.annotation.Nullable; 9 | import com.lighters.demos.ITestAidlInterface; 10 | 11 | /** 12 | * Created by david on 16/11/8. 13 | * Email: huangdiv5@gmail.com 14 | * GitHub: https://github.com/alighters 15 | */ 16 | 17 | public class RemoteService extends Service { 18 | 19 | String mGreeter = "David.wei"; 20 | 21 | IBinder mBinder = new ITestAidlInterface.Stub() { 22 | 23 | @Override 24 | public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) 25 | throws RemoteException { 26 | 27 | } 28 | 29 | @Override 30 | public String sayHello(String msg) throws RemoteException { 31 | return "Say Hello:" + msg + " from: " + mGreeter; 32 | } 33 | 34 | @Override 35 | public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 36 | return super.onTransact(code, data, reply, flags); 37 | } 38 | }; 39 | 40 | @Nullable 41 | @Override 42 | public IBinder onBind(Intent intent) { 43 | return mBinder; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/anim/FirstActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.anim; 18 | 19 | import android.content.Intent; 20 | import android.os.Bundle; 21 | import android.view.View; 22 | import android.widget.Button; 23 | import butterknife.BindView; 24 | import com.lighters.demos.R; 25 | import com.lighters.demos.app.base.BaseActivity; 26 | 27 | public class FirstActivity extends BaseActivity { 28 | 29 | @BindView(R.id.view_first) View mViewFirst; 30 | @BindView(R.id.btn_goto_next_page) Button mBtnGotoNextPage; 31 | 32 | @Override 33 | protected int getLayoutId() { 34 | return R.layout.activity_first; 35 | } 36 | 37 | @Override 38 | protected void setView(Bundle savedInstanceState) { 39 | mBtnGotoNextPage.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | startActivity(new Intent(FirstActivity.this, SecondActivity.class)); 43 | overridePendingTransition(0, 0); 44 | } 45 | }); 46 | } 47 | 48 | @Override 49 | protected void initData() { 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/anim/SecondActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.anim; 18 | 19 | import android.animation.ValueAnimator; 20 | import android.graphics.drawable.Drawable; 21 | import android.os.Bundle; 22 | import android.util.Log; 23 | import android.view.View; 24 | import butterknife.BindView; 25 | import com.lighters.demos.R; 26 | import com.lighters.demos.app.base.BaseActivity; 27 | import com.lighters.demos.util.ColorUtil; 28 | 29 | /** 30 | * Created by david on 16/7/26. 31 | * Email: huangdiv5@gmail.com 32 | * GitHub: https://github.com/alighters 33 | */ 34 | public class SecondActivity extends BaseActivity { 35 | 36 | @BindView(R.id.view_second) View mViewSecond; 37 | 38 | Drawable mBackground; 39 | 40 | @Override 41 | protected int getLayoutId() { 42 | return R.layout.activity_second; 43 | } 44 | 45 | @Override 46 | protected void setView(Bundle savedInstanceState) { 47 | //mBackground = getResources().getDrawable(R.drawable.background); 48 | //mBackground.setAlpha(1); 49 | //getWindow().setBackgroundDrawable(mBackground); 50 | } 51 | 52 | @Override 53 | protected void initData() { 54 | startAnim(); 55 | } 56 | 57 | private void startAnim() { 58 | final int colorFrom = getResources().getColor(R.color.red); 59 | final int colorTo = getResources().getColor(R.color.blue); 60 | //ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); 61 | //colorAnimation.setDuration(3000); // milliseconds 62 | //colorAnimation.addListener(new AnimatorListenerAdapter() { 63 | // @Override 64 | // public void onAnimationEnd(Animator animation) { 65 | // super.onAnimationEnd(animation); 66 | // //mBackground.setAlpha(1); 67 | // //getWindow().setBackgroundDrawable(mBackground); 68 | // } 69 | //}); 70 | //colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 71 | // 72 | // @Override 73 | // public void onAnimationUpdate(ValueAnimator animator) { 74 | // mViewSecond.setBackgroundColor((int) animator.getAnimatedValue()); 75 | // } 76 | //}); 77 | //colorAnimation.start(); 78 | 79 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f); 80 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 81 | @Override 82 | public void onAnimationUpdate(ValueAnimator animation) { 83 | Log.d("animtion_value:", animation.getAnimatedValue().toString()); 84 | int color = ColorUtil.getInterColor(colorFrom, colorTo, (Float) animation.getAnimatedValue()); 85 | mViewSecond.setBackgroundColor(color); 86 | } 87 | }); 88 | valueAnimator.setDuration(3000); // milliseconds 89 | valueAnimator.start(); 90 | } 91 | 92 | @Override 93 | public void finish() { 94 | super.finish(); 95 | overridePendingTransition(0, 0); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/app/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.app.base; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.LayoutRes; 22 | import android.support.annotation.Nullable; 23 | import android.support.v7.app.AppCompatActivity; 24 | import butterknife.ButterKnife; 25 | 26 | /** 27 | * Created by david on 16/7/27. 28 | * Email: huangdiv5@gmail.com 29 | * GitHub: https://github.com/alighters 30 | */ 31 | public abstract class BaseActivity extends Activity { 32 | 33 | @Override 34 | protected void onCreate(@Nullable Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(getLayoutId()); 37 | ButterKnife.bind(this); 38 | setView(savedInstanceState); 39 | initData(); 40 | } 41 | 42 | @LayoutRes 43 | protected abstract int getLayoutId(); 44 | 45 | protected abstract void setView(Bundle savedInstanceState); 46 | 47 | protected abstract void initData(); 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/app/base/BaseApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.app.base; 18 | 19 | import android.app.Application; 20 | import android.content.Context; 21 | 22 | /** 23 | * Created by david on 16/7/27. 24 | * Email: huangdiv5@gmail.com 25 | * GitHub: https://github.com/alighters 26 | */ 27 | public class BaseApplication extends Application { 28 | 29 | private static Context mContext; 30 | 31 | @Override 32 | public void onCreate() { 33 | super.onCreate(); 34 | mContext = this; 35 | } 36 | 37 | 38 | public static Context getContext(){ 39 | return mContext; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/canvas/conver/CanvasCoverActivity.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.canvas.conver; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import com.lighters.demos.R; 7 | 8 | public class CanvasCoverActivity extends AppCompatActivity { 9 | 10 | private boolean mHandled; 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_canvas_cover); 16 | final RoundPointView roundPointView = (RoundPointView) findViewById(R.id.rpv_normal); 17 | roundPointView.setHandled(true); 18 | roundPointView.setOnClickListener(new View.OnClickListener() { 19 | @Override 20 | public void onClick(View v) { 21 | mHandled = !mHandled; 22 | roundPointView.setHandled(mHandled); 23 | roundPointView.invalidate(); 24 | } 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/canvas/conver/RoundPointView.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.canvas.conver; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.PorterDuff; 8 | import android.graphics.PorterDuffXfermode; 9 | import android.support.annotation.Nullable; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | 13 | /** 14 | * Created by david on 2017/4/23. 15 | * Email: huangdiv5@gmail.com 16 | * GitHub: https://github.com/alighters 17 | */ 18 | 19 | public class RoundPointView extends View { 20 | 21 | /** 22 | * 是否可以操作 23 | */ 24 | private boolean mHandled; 25 | 26 | private Paint mPaint; 27 | 28 | public RoundPointView(Context context) { 29 | this(context, null); 30 | } 31 | 32 | public RoundPointView(Context context, @Nullable AttributeSet attrs) { 33 | super(context, attrs); 34 | init(); 35 | } 36 | 37 | private void init() { 38 | mPaint = new Paint(); 39 | mPaint.setAntiAlias(true); 40 | } 41 | 42 | @Override 43 | protected void onDraw(Canvas canvas) { 44 | //super.onDraw(canvas); 45 | if (!mHandled) { 46 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); 47 | mPaint.setColor(Color.WHITE); 48 | canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, getHeight() / 3, mPaint); 49 | mPaint.setXfermode(null); 50 | } else { 51 | mPaint.setColor(Color.LTGRAY); 52 | canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, getHeight() / 2, mPaint); 53 | mPaint.setColor(Color.RED); 54 | canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, getHeight() / 4, mPaint); 55 | } 56 | } 57 | 58 | public void setHandled(boolean handled) { 59 | mHandled = handled; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/jni/JniTestActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.jni; 18 | 19 | import android.os.Bundle; 20 | import android.support.annotation.Nullable; 21 | import android.support.v7.app.AppCompatActivity; 22 | import android.widget.TextView; 23 | 24 | /** 25 | * Created by david on 16/8/2. 26 | * Email: huangdiv5@gmail.com 27 | * GitHub: https://github.com/alighters 28 | */ 29 | public class JniTestActivity extends AppCompatActivity { 30 | 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | /* Create a TextView and set its content. 35 | * the text is retrieved by calling a native 36 | * function. 37 | */ 38 | TextView tv = new TextView(this); 39 | tv.setText(stringFromJNI()); 40 | setContentView(tv); 41 | } 42 | 43 | /* A native method that is implemented by the 44 | * 'hello-jni' native library, which is packaged 45 | * with this application. 46 | */ 47 | public native String stringFromJNI(); 48 | 49 | /* This is another native method declaration that is *not* 50 | * implemented by 'hello-jni'. This is simply to show that 51 | * you can declare as many native methods in your Java code 52 | * as you want, their implementation is searched in the 53 | * currently loaded native libraries only the first time 54 | * you call them. 55 | * 56 | * Trying to call this function will result in a 57 | * java.lang.UnsatisfiedLinkError exception ! 58 | */ 59 | public native String unimplementedStringFromJNI(); 60 | 61 | /* this is used to load the 'hello-jni' library on application 62 | * startup. The library has already been unpacked into 63 | * /data/data/com.example.hellojni/lib/libhello-jni.so at 64 | * installation time by the package manager. 65 | */ 66 | static { 67 | System.loadLibrary("hello-jni"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/reactnative/MyToastModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.reactnative; 18 | 19 | import android.widget.Toast; 20 | import com.facebook.react.bridge.ReactApplicationContext; 21 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 22 | import com.facebook.react.bridge.ReactMethod; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | import javax.annotation.Nullable; 26 | 27 | /** 28 | * Created by david on 16/10/12. 29 | * Email: huangdiv5@gmail.com 30 | * GitHub: https://github.com/alighters 31 | */ 32 | 33 | public class MyToastModule extends ReactContextBaseJavaModule { 34 | 35 | private static final String DURATION_SHORT_KEY = "SHORT"; 36 | private static final String DURATION_LONG_KEY = "LONG"; 37 | 38 | 39 | public MyToastModule(ReactApplicationContext reactContext) { 40 | super(reactContext); 41 | } 42 | 43 | @Override 44 | public String getName() { 45 | return "MyToast"; 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public Map getConstants() { 51 | final Map constants = new HashMap<>(); 52 | constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT); 53 | constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG); 54 | return constants; 55 | } 56 | 57 | @ReactMethod 58 | public void show(String message, int duration) { 59 | Toast.makeText(getReactApplicationContext(), message, duration).show(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/reactnative/ToastExampleReactPackage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.reactnative; 18 | 19 | import com.facebook.react.ReactPackage; 20 | import com.facebook.react.bridge.JavaScriptModule; 21 | import com.facebook.react.bridge.NativeModule; 22 | import com.facebook.react.bridge.ReactApplicationContext; 23 | import com.facebook.react.uimanager.ViewManager; 24 | import java.util.ArrayList; 25 | import java.util.Collections; 26 | import java.util.List; 27 | 28 | /** 29 | * Created by david on 16/10/11. 30 | * Email: huangdiv5@gmail.com 31 | * GitHub: https://github.com/alighters 32 | */ 33 | 34 | public class ToastExampleReactPackage implements ReactPackage { 35 | @Override 36 | public List createNativeModules(ReactApplicationContext reactContext) { 37 | List modules = new ArrayList<>(); 38 | modules.add(new MyToastModule(reactContext)); 39 | return modules; 40 | } 41 | 42 | @Override 43 | public List> createJSModules() { 44 | return Collections.emptyList(); 45 | } 46 | 47 | @Override 48 | public List createViewManagers(ReactApplicationContext reactContext) { 49 | return Collections.emptyList(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/reactnative/ToastRnActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.reactnative; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.view.KeyEvent; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.ReactRootView; 24 | import com.facebook.react.common.LifecycleState; 25 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 26 | import com.facebook.react.shell.MainReactPackage; 27 | import com.lighters.demos.BuildConfig; 28 | 29 | /** 30 | * Created by david on 16/10/12. 31 | * Email: huangdiv5@gmail.com 32 | * GitHub: https://github.com/alighters 33 | */ 34 | 35 | public class ToastRnActivity extends Activity implements DefaultHardwareBackBtnHandler { 36 | private ReactRootView mReactRootView; 37 | private ReactInstanceManager mReactInstanceManager; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | 43 | mReactRootView = new ReactRootView(this); 44 | mReactInstanceManager = ReactInstanceManager.builder() 45 | .setApplication(getApplication()) 46 | .setBundleAssetName("index.android.bundle") 47 | .setJSMainModuleName("index.android") 48 | .addPackage(new MainReactPackage()) 49 | .addPackage(new ToastExampleReactPackage()) 50 | .setUseDeveloperSupport(BuildConfig.DEBUG) 51 | //.setUseDeveloperSupport(false) 52 | .setInitialLifecycleState(LifecycleState.RESUMED) 53 | //.setUseOldBridge(true) // uncomment this line if your app crashes 54 | .build(); 55 | mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null); 56 | 57 | setContentView(mReactRootView); 58 | } 59 | 60 | @Override 61 | public void invokeDefaultOnBackPressed() { 62 | super.onBackPressed(); 63 | } 64 | 65 | @Override 66 | protected void onPause() { 67 | super.onPause(); 68 | if (mReactInstanceManager != null) { 69 | mReactInstanceManager.onHostPause(this); 70 | } 71 | } 72 | 73 | @Override 74 | protected void onResume() { 75 | super.onResume(); 76 | 77 | if (mReactInstanceManager != null) { 78 | mReactInstanceManager.onHostResume(this, this); 79 | } 80 | } 81 | 82 | @Override 83 | protected void onDestroy() { 84 | super.onDestroy(); 85 | 86 | if (mReactInstanceManager != null) { 87 | mReactInstanceManager.onHostDestroy(this); 88 | } 89 | } 90 | 91 | @Override 92 | public void onBackPressed() { 93 | if (mReactInstanceManager != null) { 94 | mReactInstanceManager.onBackPressed(); 95 | } else { 96 | super.onBackPressed(); 97 | } 98 | } 99 | 100 | @Override 101 | public boolean onKeyUp(int keyCode, KeyEvent event) { 102 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 103 | mReactInstanceManager.showDevOptionsDialog(); 104 | return true; 105 | } 106 | return super.onKeyUp(keyCode, event); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/service/test/TestIntentActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.service.test; 18 | 19 | import android.content.Intent; 20 | import android.os.Bundle; 21 | import butterknife.OnClick; 22 | import com.lighters.demos.R; 23 | import com.lighters.demos.app.base.BaseActivity; 24 | 25 | /** 26 | * Created by david on 16/9/14. 27 | * Email: huangdiv5@gmail.com 28 | * GitHub: https://github.com/alighters 29 | */ 30 | public class TestIntentActivity extends BaseActivity { 31 | 32 | @Override 33 | protected int getLayoutId() { 34 | return R.layout.activity_intent_service_test; 35 | } 36 | 37 | @Override 38 | protected void setView(Bundle savedInstanceState) { 39 | } 40 | 41 | @Override 42 | protected void initData() { 43 | startService(new Intent(this, TestIntentService.class)); 44 | } 45 | 46 | @OnClick(R.id.btn_stop_service) 47 | public void stopTheService() { 48 | stopService(new Intent(this, TestIntentService.class)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/service/test/TestIntentService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.service.test; 18 | 19 | import android.app.IntentService; 20 | import android.content.Intent; 21 | import android.util.Log; 22 | 23 | /** 24 | * Created by david on 16/9/14. 25 | * Email: huangdiv5@gmail.com 26 | * GitHub: https://github.com/alighters 27 | */ 28 | public class TestIntentService extends IntentService { 29 | 30 | Thread mThread = null; 31 | 32 | public TestIntentService() { 33 | this("TestIntentService"); 34 | } 35 | 36 | public TestIntentService(String name) { 37 | super(name); 38 | } 39 | 40 | @Override 41 | protected void onHandleIntent(Intent intent) { 42 | mThread = Thread.currentThread(); 43 | int i = 0; 44 | while (true) { 45 | i++; 46 | try { 47 | Thread.sleep(1000); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | Log.d("TestIntentService", i + ""); 52 | } 53 | } 54 | 55 | @Override 56 | public boolean stopService(Intent name) { 57 | boolean result = super.stopService(name); 58 | if (mThread != null) { 59 | mThread.interrupt(); 60 | } 61 | return result; 62 | } 63 | 64 | @Override 65 | public void onDestroy() { 66 | super.onDestroy(); 67 | if (mThread != null) { 68 | mThread.interrupt(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/TokenTestActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token; 18 | 19 | import android.os.Bundle; 20 | import android.text.TextUtils; 21 | import android.view.View; 22 | import butterknife.OnClick; 23 | import com.lighters.demos.R; 24 | import com.lighters.demos.app.base.BaseActivity; 25 | import com.lighters.demos.token.http.GlobalToken; 26 | import com.lighters.demos.token.http.RetrofitUtil; 27 | import com.lighters.demos.token.http.api.IApiService; 28 | import com.lighters.demos.token.http.api.ResultModel; 29 | import com.lighters.demos.token.http.api.TokenModel; 30 | import rx.Subscriber; 31 | import rx.android.schedulers.AndroidSchedulers; 32 | import rx.schedulers.Schedulers; 33 | 34 | /** 35 | * Created by david on 16/8/21. 36 | * Email: huangdiv5@gmail.com 37 | * GitHub: https://github.com/alighters 38 | */ 39 | public class TokenTestActivity extends BaseActivity { 40 | @Override 41 | protected int getLayoutId() { 42 | return R.layout.activity_token_test; 43 | } 44 | 45 | @Override 46 | protected void setView(Bundle savedInstanceState) { 47 | 48 | } 49 | 50 | @Override 51 | protected void initData() { 52 | } 53 | 54 | @OnClick(R.id.btn_token_get) 55 | public void onGetTokenClick(View v) { 56 | RetrofitUtil.getInstance() 57 | .get(IApiService.class) 58 | .getToken() 59 | .subscribeOn(Schedulers.io()) 60 | .observeOn(AndroidSchedulers.mainThread()) 61 | .subscribe(new Subscriber() { 62 | @Override 63 | public void onCompleted() { 64 | 65 | } 66 | 67 | @Override 68 | public void onError(Throwable e) { 69 | 70 | } 71 | 72 | @Override 73 | public void onNext(TokenModel model) { 74 | if (model != null && !TextUtils.isEmpty(model.token)) { 75 | GlobalToken.updateToken(model.token); 76 | } 77 | } 78 | }); 79 | } 80 | 81 | @OnClick(R.id.btn_request) 82 | public void onRequestClick(View v) { 83 | for (int i = 0; i < 5; i++) { 84 | RetrofitUtil.getInstance() 85 | .getProxy(IApiService.class) 86 | .getResult(GlobalToken.getToken()) 87 | .subscribeOn(Schedulers.io()) 88 | .observeOn(AndroidSchedulers.mainThread()) 89 | .subscribe(new Subscriber() { 90 | @Override 91 | public void onCompleted() { 92 | 93 | } 94 | 95 | @Override 96 | public void onError(Throwable e) { 97 | 98 | } 99 | 100 | @Override 101 | public void onNext(ResultModel model) { 102 | 103 | } 104 | }); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/GlobalToken.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http; 18 | 19 | /** 20 | * Created by david on 16/8/21. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class GlobalToken { 25 | private static String sToken; 26 | 27 | public static synchronized void updateToken(String token) { 28 | sToken = token; 29 | } 30 | 31 | public static String getToken() { 32 | return sToken; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/IGlobalManager.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.token.http; 2 | 3 | /** 4 | * Created by david on 16/11/24. 5 | * Email: huangdiv5@gmail.com 6 | * GitHub: https://github.com/alighters 7 | */ 8 | 9 | public interface IGlobalManager { 10 | /** 11 | * Exit the login state. 12 | */ 13 | void exitLogin(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/RetrofitUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http; 18 | 19 | import android.content.Intent; 20 | import android.os.Handler; 21 | import android.os.Looper; 22 | import android.widget.Toast; 23 | import com.lighters.demos.MainActivity; 24 | import com.lighters.demos.app.base.BaseApplication; 25 | import com.lighters.demos.token.http.converter.GsonConverterFactory; 26 | import com.lighters.demos.token.http.proxy.ProxyHandler; 27 | import java.lang.reflect.Proxy; 28 | import okhttp3.OkHttpClient; 29 | import okhttp3.logging.HttpLoggingInterceptor; 30 | import retrofit2.Retrofit; 31 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 32 | 33 | /** 34 | * Created by david on 16/8/19. 35 | * Email: huangdiv5@gmail.com 36 | * GitHub: https://github.com/alighters 37 | */ 38 | public class RetrofitUtil implements IGlobalManager { 39 | 40 | public static final String API = "http://192.168.56.1:8888/"; 41 | 42 | private static Retrofit sRetrofit; 43 | private static OkHttpClient sOkHttpClient; 44 | private static RetrofitUtil instance; 45 | 46 | private final static Object mRetrofitLock = new Object(); 47 | 48 | private static Retrofit getRetrofit() { 49 | if (sRetrofit == null) { 50 | synchronized (mRetrofitLock) { 51 | if (sRetrofit == null) { 52 | OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder(); 53 | 54 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 55 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 56 | clientBuilder.addInterceptor(httpLoggingInterceptor); 57 | sOkHttpClient = clientBuilder.build(); 58 | sRetrofit = new Retrofit.Builder().client(sOkHttpClient) 59 | .baseUrl(API) 60 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 61 | .addConverterFactory(GsonConverterFactory.create()) 62 | .build(); 63 | } 64 | } 65 | } 66 | return sRetrofit; 67 | } 68 | 69 | public static RetrofitUtil getInstance() { 70 | if (instance == null) { 71 | synchronized (RetrofitUtil.class) { 72 | if (instance == null) { 73 | instance = new RetrofitUtil(); 74 | } 75 | } 76 | } 77 | return instance; 78 | } 79 | 80 | public T get(Class tClass) { 81 | return getRetrofit().create(tClass); 82 | } 83 | 84 | @SuppressWarnings("unchecked") 85 | public T getProxy(Class tClass) { 86 | T t = getRetrofit().create(tClass); 87 | return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[] { tClass }, new ProxyHandler(t, this)); 88 | } 89 | 90 | @Override 91 | public void exitLogin() { 92 | // Cancel all the netWorkRequest 93 | sOkHttpClient.dispatcher().cancelAll(); 94 | 95 | // Goto the home page 96 | new Handler(Looper.getMainLooper()).post(new Runnable() { 97 | @Override 98 | public void run() { 99 | Intent intent = new Intent(BaseApplication.getContext(), MainActivity.class); 100 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 101 | BaseApplication.getContext().startActivity(intent); 102 | Toast.makeText(BaseApplication.getContext(), "Token is not existed!!", Toast.LENGTH_SHORT).show(); 103 | } 104 | }); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/api/ApiModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.api; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | 21 | /** 22 | * Created by david on 16/8/21. 23 | * Email: huangdiv5@gmail.com 24 | * GitHub: https://github.com/alighters 25 | */ 26 | public class ApiModel { 27 | 28 | public boolean success; 29 | @SerializedName("error_code") public int errorCode; 30 | 31 | public T data; 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/api/ErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.api; 18 | 19 | /** 20 | * Created by david on 16/8/21. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class ErrorCode { 25 | public static final int TOKEN_NOT_EXIST = 1000; 26 | public static final int TOKEN_INVALID = 1001; 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/api/IApiService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.api; 18 | 19 | import retrofit2.http.GET; 20 | import retrofit2.http.Query; 21 | import rx.Observable; 22 | 23 | /** 24 | * Created by david on 16/8/20. 25 | * Email: huangdiv5@gmail.com 26 | * GitHub: https://github.com/alighters 27 | */ 28 | public interface IApiService { 29 | 30 | @GET("get_token") 31 | Observable getToken(); 32 | 33 | @GET("refresh_token") 34 | Observable refreshToken(); 35 | 36 | @GET("request") 37 | Observable getResult(@Query("token") String token); 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/api/ResultModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.api; 18 | 19 | /** 20 | * Created by david on 16/8/20. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class ResultModel { 25 | 26 | /** 27 | * result : false 28 | */ 29 | 30 | public boolean result; 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/api/TokenModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.api; 18 | 19 | /** 20 | * Created by david on 16/8/20. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class TokenModel { 25 | 26 | public String token; 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/converter/GsonConverterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.converter; 18 | 19 | import com.google.gson.Gson; 20 | import com.google.gson.TypeAdapter; 21 | import com.google.gson.reflect.TypeToken; 22 | import com.lighters.demos.token.http.api.ApiModel; 23 | import java.lang.annotation.Annotation; 24 | import java.lang.reflect.ParameterizedType; 25 | import java.lang.reflect.Type; 26 | import okhttp3.RequestBody; 27 | import okhttp3.ResponseBody; 28 | import retrofit2.Converter; 29 | import retrofit2.Retrofit; 30 | 31 | /** 32 | * A {@linkplain Converter.Factory converter} which uses Gson for JSON. 33 | *

34 | * Because Gson is so flexible in the types it supports, this converter assumes that it can handle 35 | * all types. If you are mixing JSON serialization with something else (such as protocol buffers), 36 | * you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance} 37 | * last to allow the other converters a chance to see their types. 38 | */ 39 | public final class GsonConverterFactory extends Converter.Factory { 40 | /** 41 | * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and 42 | * decoding from JSON (when no charset is specified by a header) will use UTF-8. 43 | */ 44 | public static GsonConverterFactory create() { 45 | return create(new Gson()); 46 | } 47 | 48 | /** 49 | * Create an instance using {@code gson} for conversion. Encoding to JSON and 50 | * decoding from JSON (when no charset is specified by a header) will use UTF-8. 51 | */ 52 | public static GsonConverterFactory create(Gson gson) { 53 | return new GsonConverterFactory(gson); 54 | } 55 | 56 | private final Gson gson; 57 | 58 | private GsonConverterFactory(Gson gson) { 59 | if (gson == null) throw new NullPointerException("gson == null"); 60 | this.gson = gson; 61 | } 62 | 63 | @Override 64 | public Converter responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) { 65 | Type newType = new ParameterizedType() { 66 | @Override 67 | public Type[] getActualTypeArguments() { 68 | return new Type[] { type }; 69 | } 70 | 71 | @Override 72 | public Type getOwnerType() { 73 | return null; 74 | } 75 | 76 | @Override 77 | public Type getRawType() { 78 | return ApiModel.class; 79 | } 80 | }; 81 | TypeAdapter adapter = gson.getAdapter(TypeToken.get(newType)); 82 | return new GsonResponseBodyConverter<>(adapter); 83 | } 84 | 85 | @Override 86 | public Converter requestBodyConverter(Type type, Annotation[] parameterAnnotations, 87 | Annotation[] methodAnnotations, Retrofit retrofit) { 88 | TypeAdapter adapter = gson.getAdapter(TypeToken.get(type)); 89 | return new GsonRequestBodyConverter<>(gson, adapter); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/converter/GsonRequestBodyConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.converter; 18 | 19 | import com.google.gson.Gson; 20 | import com.google.gson.TypeAdapter; 21 | import com.google.gson.stream.JsonWriter; 22 | import java.io.IOException; 23 | import java.io.OutputStreamWriter; 24 | import java.io.Writer; 25 | import java.nio.charset.Charset; 26 | import okhttp3.MediaType; 27 | import okhttp3.RequestBody; 28 | import okio.Buffer; 29 | import retrofit2.Converter; 30 | 31 | final class GsonRequestBodyConverter implements Converter { 32 | private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); 33 | private static final Charset UTF_8 = Charset.forName("UTF-8"); 34 | 35 | private final Gson gson; 36 | private final TypeAdapter adapter; 37 | 38 | GsonRequestBodyConverter(Gson gson, TypeAdapter adapter) { 39 | this.gson = gson; 40 | this.adapter = adapter; 41 | } 42 | 43 | @Override 44 | public RequestBody convert(T value) throws IOException { 45 | Buffer buffer = new Buffer(); 46 | Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8); 47 | JsonWriter jsonWriter = gson.newJsonWriter(writer); 48 | adapter.write(jsonWriter, value); 49 | jsonWriter.close(); 50 | return RequestBody.create(MEDIA_TYPE, buffer.readByteString()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/converter/GsonResponseBodyConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Square, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.converter; 18 | 19 | import com.google.gson.TypeAdapter; 20 | import com.lighters.demos.token.http.api.ApiModel; 21 | import com.lighters.demos.token.http.api.ErrorCode; 22 | import com.lighters.demos.token.http.exception.ApiException; 23 | import com.lighters.demos.token.http.exception.TokenInvalidException; 24 | import com.lighters.demos.token.http.exception.TokenNotExistException; 25 | import java.io.IOException; 26 | import okhttp3.ResponseBody; 27 | import retrofit2.Converter; 28 | 29 | final class GsonResponseBodyConverter implements Converter { 30 | 31 | private final TypeAdapter adapter; 32 | 33 | GsonResponseBodyConverter(TypeAdapter adapter) { 34 | this.adapter = adapter; 35 | } 36 | 37 | @Override 38 | public Object convert(ResponseBody value) throws IOException { 39 | try { 40 | ApiModel apiModel = (ApiModel) adapter.fromJson(value.charStream()); 41 | if (apiModel.errorCode == ErrorCode.TOKEN_NOT_EXIST) { 42 | throw new TokenNotExistException(); 43 | } else if (apiModel.errorCode == ErrorCode.TOKEN_INVALID) { 44 | throw new TokenInvalidException(); 45 | } else if (!apiModel.success) { 46 | // 特定 API 的错误,在相应的 Subscriber 的 onError 的方法中进行处理 47 | throw new ApiException(); 48 | } else if (apiModel.success) { 49 | return apiModel.data; 50 | } 51 | } finally { 52 | value.close(); 53 | } 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/exception/ApiException.java: -------------------------------------------------------------------------------- 1 | package com.lighters.demos.token.http.exception; 2 | 3 | /** 4 | * Created by david on 16/11/24. 5 | * Email: huangdiv5@gmail.com 6 | * GitHub: https://github.com/alighters 7 | * 8 | * 指定 API 的通用错误 9 | */ 10 | 11 | public class ApiException extends RuntimeException{ 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/exception/TokenInvalidException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.exception; 18 | 19 | /** 20 | * Created by david on 16/8/21. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class TokenInvalidException extends RuntimeException { 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/exception/TokenNotExistException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.exception; 18 | 19 | /** 20 | * Created by david on 16/8/21. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class TokenNotExistException extends RuntimeException { 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/token/http/proxy/ProxyHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.token.http.proxy; 18 | 19 | import android.text.TextUtils; 20 | import android.util.Log; 21 | import android.widget.Toast; 22 | import com.lighters.demos.app.base.BaseApplication; 23 | import com.lighters.demos.token.http.GlobalToken; 24 | import com.lighters.demos.token.http.IGlobalManager; 25 | import com.lighters.demos.token.http.RetrofitUtil; 26 | import com.lighters.demos.token.http.api.IApiService; 27 | import com.lighters.demos.token.http.api.TokenModel; 28 | import com.lighters.demos.token.http.exception.TokenInvalidException; 29 | import com.lighters.demos.token.http.exception.TokenNotExistException; 30 | import java.lang.annotation.Annotation; 31 | import java.lang.reflect.InvocationHandler; 32 | import java.lang.reflect.InvocationTargetException; 33 | import java.lang.reflect.Method; 34 | import java.util.Date; 35 | import retrofit2.http.Query; 36 | import rx.Observable; 37 | import rx.Subscriber; 38 | import rx.functions.Func1; 39 | 40 | /** 41 | * Created by david on 16/8/21. 42 | * Email: huangdiv5@gmail.com 43 | * GitHub: https://github.com/alighters 44 | */ 45 | public class ProxyHandler implements InvocationHandler { 46 | 47 | private final static String TAG = "Token_Proxy"; 48 | 49 | private final static String TOKEN = "token"; 50 | 51 | private final static int REFRESH_TOKEN_VALID_TIME = 30; 52 | private static long tokenChangedTime = 0; 53 | private Throwable mRefreshTokenError = null; 54 | private boolean mIsTokenNeedRefresh; 55 | 56 | private Object mProxyObject; 57 | private IGlobalManager mGlobalManager; 58 | 59 | public ProxyHandler(Object proxyObject, IGlobalManager globalManager) { 60 | mProxyObject = proxyObject; 61 | mGlobalManager = globalManager; 62 | } 63 | 64 | @Override 65 | public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 66 | return Observable.just(null).flatMap(new Func1>() { 67 | @Override 68 | public Observable call(Object o) { 69 | try { 70 | try { 71 | if (mIsTokenNeedRefresh) { 72 | updateMethodToken(method, args); 73 | } 74 | return (Observable) method.invoke(mProxyObject, args); 75 | } catch (InvocationTargetException e) { 76 | e.printStackTrace(); 77 | } 78 | } catch (IllegalAccessException e) { 79 | e.printStackTrace(); 80 | } 81 | return null; 82 | } 83 | }).retryWhen(new Func1, Observable>() { 84 | @Override 85 | public Observable call(Observable observable) { 86 | return observable.flatMap(new Func1>() { 87 | @Override 88 | public Observable call(Throwable throwable) { 89 | if (throwable instanceof TokenInvalidException) { 90 | return refreshTokenWhenTokenInvalid(); 91 | } else if (throwable instanceof TokenNotExistException) { 92 | // Token 不存在,执行退出登录的操作。(为了防止多个请求,都出现 Token 不存在的问题, 93 | // 这里需要取消当前所有的网络请求) 94 | mGlobalManager.exitLogin(); 95 | return Observable.error(throwable); 96 | } 97 | return Observable.error(throwable); 98 | } 99 | }); 100 | } 101 | }); 102 | } 103 | 104 | /** 105 | * Refresh the token when the current token is invalid. 106 | * 107 | * @return Observable 108 | */ 109 | private Observable refreshTokenWhenTokenInvalid() { 110 | synchronized (ProxyHandler.class) { 111 | // Have refreshed the token successfully in the valid time. 112 | if (new Date().getTime() - tokenChangedTime < REFRESH_TOKEN_VALID_TIME) { 113 | mIsTokenNeedRefresh = true; 114 | return Observable.just(true); 115 | } else { 116 | // call the refresh token api. 117 | RetrofitUtil.getInstance().get(IApiService.class).refreshToken().subscribe(new Subscriber() { 118 | @Override 119 | public void onCompleted() { 120 | 121 | } 122 | 123 | @Override 124 | public void onError(Throwable e) { 125 | mRefreshTokenError = e; 126 | } 127 | 128 | @Override 129 | public void onNext(TokenModel model) { 130 | if (model != null) { 131 | mIsTokenNeedRefresh = true; 132 | tokenChangedTime = new Date().getTime(); 133 | GlobalToken.updateToken(model.token); 134 | Log.d(TAG, "Refresh token success, time = " + tokenChangedTime); 135 | } 136 | } 137 | }); 138 | if (mRefreshTokenError != null) { 139 | return Observable.error(mRefreshTokenError); 140 | } else { 141 | return Observable.just(true); 142 | } 143 | } 144 | } 145 | } 146 | 147 | /** 148 | * Update the token of the args in the method. 149 | * 150 | * PS: 因为这里使用的是 GET 请求,所以这里就需要对 Query 的参数名称为 token 的方法。 151 | * 若是 POST 请求,或者使用 Body ,自行替换。因为 参数数组已经知道,进行遍历找到相应的值,进行替换即可(更新为新的 token 值)。 152 | */ 153 | private void updateMethodToken(Method method, Object[] args) { 154 | if (mIsTokenNeedRefresh && !TextUtils.isEmpty(GlobalToken.getToken())) { 155 | Annotation[][] annotationsArray = method.getParameterAnnotations(); 156 | Annotation[] annotations; 157 | if (annotationsArray != null && annotationsArray.length > 0) { 158 | for (int i = 0; i < annotationsArray.length; i++) { 159 | annotations = annotationsArray[i]; 160 | for (Annotation annotation : annotations) { 161 | if (annotation instanceof Query) { 162 | if (TOKEN.equals(((Query) annotation).value())) { 163 | args[i] = GlobalToken.getToken(); 164 | } 165 | } 166 | } 167 | } 168 | } 169 | mIsTokenNeedRefresh = false; 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /app/src/main/java/com/lighters/demos/util/ColorUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lighters.demos.util; 18 | 19 | /** 20 | * Created by david on 16/7/27. 21 | * Email: huangdiv5@gmail.com 22 | * GitHub: https://github.com/alighters 23 | */ 24 | public class ColorUtil { 25 | 26 | /** 27 | * Get the percent color between the startColor and endColor 28 | * 29 | * @param startColor The start color. 30 | * @param endColor The end color. 31 | * @param percent The percent transform value which is between 0 and 1. 32 | * @return the result color value. 33 | */ 34 | public static int getInterColor(int startColor, int endColor, float percent) { 35 | int maskColor = (1 << 8) - 1; 36 | int index = 0; 37 | int interColor = 0; 38 | int startValue; 39 | int endValue; 40 | while (index < 4) { 41 | startValue = (startColor >> (index * 8)) & maskColor; 42 | endValue = (endColor >> (index * 8)) & maskColor; 43 | interColor = interColor | ((int) (startValue + (endValue - startValue) * percent) << (index * 8)); 44 | index++; 45 | } 46 | return interColor; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | LOCAL_PATH := $(call my-dir) 16 | 17 | include $(CLEAR_VARS) 18 | 19 | LOCAL_MODULE := hello-jni 20 | LOCAL_SRC_FILES := hello-jni.c 21 | 22 | include $(BUILD_SHARED_LIBRARY) 23 | -------------------------------------------------------------------------------- /app/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := all -------------------------------------------------------------------------------- /app/src/main/jni/hello-jni.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | #include 18 | #include 19 | 20 | /* This is a trivial JNI example where we use a native method 21 | * to return a new VM String. See the corresponding Java source 22 | * file located at: 23 | * 24 | * apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java 25 | */ 26 | jstring 27 | Java_com_lighters_demos_jni_JniTestActivity_stringFromJNI( JNIEnv* env, 28 | jobject thiz ) 29 | { 30 | #if defined(__arm__) 31 | #if defined(__ARM_ARCH_7A__) 32 | #if defined(__ARM_NEON__) 33 | #if defined(__ARM_PCS_VFP) 34 | #define ABI "armeabi-v7a/NEON (hard-float)" 35 | #else 36 | #define ABI "armeabi-v7a/NEON" 37 | #endif 38 | #else 39 | #if defined(__ARM_PCS_VFP) 40 | #define ABI "armeabi-v7a (hard-float)" 41 | #else 42 | #define ABI "armeabi-v7a" 43 | #endif 44 | #endif 45 | #else 46 | #define ABI "armeabi" 47 | #endif 48 | #elif defined(__i386__) 49 | #define ABI "x86" 50 | #elif defined(__x86_64__) 51 | #define ABI "x86_64" 52 | #elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ 53 | #define ABI "mips64" 54 | #elif defined(__mips__) 55 | #define ABI "mips" 56 | #elif defined(__aarch64__) 57 | #define ABI "arm64-v8a" 58 | #else 59 | #define ABI "unknown" 60 | #endif 61 | 62 | return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI "."); 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/libs/arm64-v8a/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/arm64-v8a/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/armeabi-v7a/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/armeabi-v7a/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/armeabi/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/armeabi/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/mips/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/mips/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/mips64/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/mips64/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/x86/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/x86/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/libs/x86_64/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alighters/AndroidDemos/8f535933c9e1cadf8adab83a829fa60f572f0f96/app/src/main/libs/x86_64/libhello-jni.so -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_aidl.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 32 | 33 |