Commit 9ca5a167a3f21818c5bd8e2cd4914ec59f0a4667
Merge branch 'master' of bj.gitlab.cnlive.com:cnlive-team/newModuleStrike
# Conflicts: # app/strike/src/main/AndroidManifest.xml # app/strike/src/main/java/com/cnlive/strike/MainActivity.java # app/strike/src/main/res/layout/activity_main.xml
Showing
27 changed files
with
2701 additions
and
2 deletions
app/strike/build.gradle
| ... | ... | @@ -158,6 +158,7 @@ dependencies { |
| 158 | 158 | implementation project(path: ':core:base') |
| 159 | 159 | implementation project(path: ':cloud:user') |
| 160 | 160 | |
| 161 | + implementation project(path: ':core:imageload') | |
| 161 | 162 | // implementation project(path: ':core:util') |
| 162 | 163 | // implementation project(path: ':core:encipher') |
| 163 | 164 | // implementation project(path: ':cloud:user') | ... | ... |
app/strike/src/main/java/com/cnlive/strike/imgutil/ImgActivity.java
0 → 100644
| 1 | +package com.cnlive.strike.imgutil; | |
| 2 | + | |
| 3 | +import androidx.appcompat.app.AppCompatActivity; | |
| 4 | + | |
| 5 | +import android.animation.ObjectAnimator; | |
| 6 | +import android.os.Bundle; | |
| 7 | +import android.view.View; | |
| 8 | +import android.view.ViewPropertyAnimator; | |
| 9 | +import android.widget.ImageView; | |
| 10 | + | |
| 11 | +import com.bumptech.glide.request.transition.ViewPropertyTransition; | |
| 12 | +import com.cnlive.core.imageload.loader.ImageLoader; | |
| 13 | +import com.cnlive.strike.R; | |
| 14 | + | |
| 15 | +public class ImgActivity extends AppCompatActivity { | |
| 16 | + | |
| 17 | + private ImageView iv_test1; | |
| 18 | + private ImageView iv_test2; | |
| 19 | + private ImageView iv_test02; | |
| 20 | + private ImageView iv_test3; | |
| 21 | + private ImageView iv_test4; | |
| 22 | + private ImageView iv_test5; | |
| 23 | + private ImageView iv_test6; | |
| 24 | + private ImageView iv_test7; | |
| 25 | + private ImageView iv_test8; | |
| 26 | + private ImageView iv_test9; | |
| 27 | + private ImageView iv_test10; | |
| 28 | + private ImageView iv_test11; | |
| 29 | + private ImageView iv_test12; | |
| 30 | + private ImageView iv_test13; | |
| 31 | + private ImageView iv_test14; | |
| 32 | + private ImageView iv_test15; | |
| 33 | + | |
| 34 | + String URL1 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574403931080&di=ea10bd1adb20025f02e296d8694f7bb4&imgtype=0&src=http%3A%2F%2Fimg3.duitang.com%2Fuploads%2Fitem%2F201506%2F23%2F20150623164841_jtvR3.thumb.700_0.jpeg"; | |
| 35 | + | |
| 36 | + @Override | |
| 37 | + protected void onCreate(Bundle savedInstanceState) { | |
| 38 | + super.onCreate(savedInstanceState); | |
| 39 | + setContentView(R.layout.activity_img); | |
| 40 | + ImageLoader.init(this); | |
| 41 | + findview(); | |
| 42 | + load(); | |
| 43 | + } | |
| 44 | + | |
| 45 | + private void findview() { | |
| 46 | + iv_test1 = findViewById(R.id.iv_test1); | |
| 47 | + iv_test2 = findViewById(R.id.iv_test2); | |
| 48 | + iv_test02 = findViewById(R.id.iv_test02); | |
| 49 | + iv_test3 = findViewById(R.id.iv_test3); | |
| 50 | + iv_test4 = findViewById(R.id.iv_test4); | |
| 51 | + iv_test5 = findViewById(R.id.iv_test5); | |
| 52 | + iv_test6 =findViewById(R.id.iv_test6); | |
| 53 | + iv_test7 = findViewById(R.id.iv_test7); | |
| 54 | + iv_test8 = findViewById(R.id.iv_test8); | |
| 55 | + iv_test9 = findViewById(R.id.iv_test9); | |
| 56 | + iv_test10 = findViewById(R.id.iv_test10); | |
| 57 | + iv_test11 = findViewById(R.id.iv_test11); | |
| 58 | + iv_test12 = findViewById(R.id.iv_test12); | |
| 59 | + iv_test13 = findViewById(R.id.iv_test13); | |
| 60 | + iv_test14 = findViewById(R.id.iv_test14); | |
| 61 | + iv_test15 = findViewById(R.id.iv_test15); | |
| 62 | + } | |
| 63 | + | |
| 64 | + | |
| 65 | + private void load(){ | |
| 66 | + ViewPropertyTransition.Animator animation = new ViewPropertyTransition.Animator(){ | |
| 67 | + | |
| 68 | + @Override | |
| 69 | + public void animate(View view) { | |
| 70 | + view.setAlpha( 0f ); | |
| 71 | + ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f ); | |
| 72 | + fadeAnim.setDuration( 2500 ); | |
| 73 | + fadeAnim.start(); | |
| 74 | + } | |
| 75 | + }; | |
| 76 | + | |
| 77 | + ImageLoader.with(this) | |
| 78 | + .url(URL1) | |
| 79 | + .animate(animation) | |
| 80 | + .into(iv_test1); | |
| 81 | + | |
| 82 | + ImageLoader.with(this) | |
| 83 | + .url(URL1) | |
| 84 | + .scale(1)//缩放几倍 | |
| 85 | + .into(iv_test02); | |
| 86 | + | |
| 87 | + ImageLoader.with(this) | |
| 88 | + .url(URL1) | |
| 89 | + .scale(3) | |
| 90 | + .into(iv_test2); | |
| 91 | + | |
| 92 | + | |
| 93 | + } | |
| 94 | +} | ... | ... |
app/strike/src/main/res/layout/activity_img.xml
0 → 100644
| 1 | +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" | |
| 2 | + android:layout_width="match_parent" | |
| 3 | + android:layout_height="match_parent" | |
| 4 | + xmlns:lb="http://schemas.android.com/apk/res-auto"> | |
| 5 | + | |
| 6 | + <LinearLayout | |
| 7 | + android:layout_width="match_parent" | |
| 8 | + android:layout_height="match_parent" | |
| 9 | + android:orientation="vertical"> | |
| 10 | + | |
| 11 | + <TextView | |
| 12 | + android:layout_width="wrap_content" | |
| 13 | + android:layout_height="wrap_content" | |
| 14 | + android:text="加载动效自定义:" | |
| 15 | + /> | |
| 16 | + <ImageView | |
| 17 | + android:id="@+id/iv_test1" | |
| 18 | + android:layout_width="300dp" | |
| 19 | + android:layout_height="300dp" | |
| 20 | + android:padding="10dp" /> | |
| 21 | + <TextView | |
| 22 | + android:layout_width="wrap_content" | |
| 23 | + android:layout_height="wrap_content" | |
| 24 | + android:text="放大缩小:" | |
| 25 | + /> | |
| 26 | + <LinearLayout | |
| 27 | + android:layout_width="wrap_content" | |
| 28 | + android:layout_height="wrap_content" | |
| 29 | + android:orientation="vertical"> | |
| 30 | + <ImageView | |
| 31 | + android:id="@+id/iv_test02" | |
| 32 | + android:layout_width="300dp" | |
| 33 | + android:layout_height="300dp" | |
| 34 | + android:padding="10dp" /> | |
| 35 | + <ImageView | |
| 36 | + android:id="@+id/iv_test2" | |
| 37 | + android:layout_width="300dp" | |
| 38 | + android:layout_height="300dp" | |
| 39 | + android:padding="10dp" /> | |
| 40 | + </LinearLayout> | |
| 41 | + | |
| 42 | + <ImageView | |
| 43 | + android:id="@+id/iv_test3" | |
| 44 | + android:layout_width="300dp" | |
| 45 | + android:layout_height="300dp" | |
| 46 | + android:padding="30dp" /> | |
| 47 | + | |
| 48 | + <ImageView | |
| 49 | + android:id="@+id/iv_test4" | |
| 50 | + android:layout_width="300dp" | |
| 51 | + android:layout_height="300dp" | |
| 52 | + android:padding="30dp" /> | |
| 53 | + | |
| 54 | + <ImageView | |
| 55 | + android:id="@+id/iv_test5" | |
| 56 | + android:layout_width="300dp" | |
| 57 | + android:layout_height="300dp" | |
| 58 | + android:padding="30dp" /> | |
| 59 | + | |
| 60 | + <ImageView | |
| 61 | + android:id="@+id/iv_test6" | |
| 62 | + android:layout_width="300dp" | |
| 63 | + android:layout_height="300dp" | |
| 64 | + android:padding="30dp" /> | |
| 65 | + | |
| 66 | + <ImageView | |
| 67 | + android:id="@+id/iv_test7" | |
| 68 | + android:layout_width="300dp" | |
| 69 | + android:layout_height="300dp" | |
| 70 | + android:padding="30dp" /> | |
| 71 | + | |
| 72 | + <ImageView | |
| 73 | + android:id="@+id/iv_test8" | |
| 74 | + android:layout_width="300dp" | |
| 75 | + android:layout_height="300dp" | |
| 76 | + android:padding="30dp" /> | |
| 77 | + | |
| 78 | + <ImageView | |
| 79 | + android:id="@+id/iv_test9" | |
| 80 | + android:layout_width="300dp" | |
| 81 | + android:layout_height="300dp" | |
| 82 | + android:padding="30dp" /> | |
| 83 | + | |
| 84 | + <ImageView | |
| 85 | + android:id="@+id/iv_test10" | |
| 86 | + android:layout_width="300dp" | |
| 87 | + android:layout_height="300dp" | |
| 88 | + android:padding="30dp" /> | |
| 89 | + | |
| 90 | + <ImageView | |
| 91 | + android:id="@+id/iv_test11" | |
| 92 | + android:layout_width="300dp" | |
| 93 | + android:layout_height="300dp" | |
| 94 | + android:padding="30dp" /> | |
| 95 | + | |
| 96 | + <ImageView | |
| 97 | + android:id="@+id/iv_test12" | |
| 98 | + android:layout_width="300dp" | |
| 99 | + android:layout_height="300dp" | |
| 100 | + android:padding="30dp" /> | |
| 101 | + | |
| 102 | + <ImageView | |
| 103 | + android:id="@+id/iv_test13" | |
| 104 | + android:layout_width="300dp" | |
| 105 | + android:layout_height="300dp" | |
| 106 | + android:padding="30dp" /> | |
| 107 | + | |
| 108 | + <ImageView | |
| 109 | + android:id="@+id/iv_test14" | |
| 110 | + android:layout_width="300dp" | |
| 111 | + android:layout_height="300dp" | |
| 112 | + android:padding="30dp" /> | |
| 113 | + | |
| 114 | + <ImageView | |
| 115 | + android:id="@+id/iv_test15" | |
| 116 | + android:layout_width="300dp" | |
| 117 | + android:layout_height="300dp" | |
| 118 | + android:padding="30dp" /> | |
| 119 | + | |
| 120 | + | |
| 121 | + <com.cnlive.core.imageload.util.MultiView | |
| 122 | + android:layout_width="300dp" | |
| 123 | + android:layout_height="300dp" | |
| 124 | + android:layout_margin="30dp" | |
| 125 | + lb:angleCount="5" | |
| 126 | + lb:type="multi" | |
| 127 | + /> | |
| 128 | + | |
| 129 | + <com.cnlive.core.imageload.util.MultiView | |
| 130 | + android:layout_width="200dp" | |
| 131 | + android:layout_height="200dp" | |
| 132 | + android:layout_margin="30dp" | |
| 133 | + android:layout_gravity="center" | |
| 134 | + lb:borderRadius="10dp" | |
| 135 | + lb:type="round" | |
| 136 | + /> | |
| 137 | + | |
| 138 | + <com.cnlive.core.imageload.util.MultiView | |
| 139 | + android:layout_margin="30dp" | |
| 140 | + android:layout_width="200dp" | |
| 141 | + android:layout_height="200dp" | |
| 142 | + android:layout_gravity="center" | |
| 143 | + lb:type="circle" | |
| 144 | + /> | |
| 145 | + | |
| 146 | + </LinearLayout> | |
| 147 | +</ScrollView> | ... | ... |
core/imageload/.gitignore
0 → 100644
| 1 | +/build | ... | ... |
core/imageload/build.gradle
0 → 100644
| 1 | +apply plugin: 'com.android.library' | |
| 2 | + | |
| 3 | +android { | |
| 4 | + compileSdkVersion 29 | |
| 5 | + buildToolsVersion "29.0.2" | |
| 6 | + | |
| 7 | + | |
| 8 | + defaultConfig { | |
| 9 | + minSdkVersion 16 | |
| 10 | + targetSdkVersion 29 | |
| 11 | + versionCode 1 | |
| 12 | + versionName "1.0" | |
| 13 | + | |
| 14 | + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | |
| 15 | + consumerProguardFiles 'consumer-rules.pro' | |
| 16 | + } | |
| 17 | + | |
| 18 | + buildTypes { | |
| 19 | + release { | |
| 20 | + minifyEnabled false | |
| 21 | + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |
| 22 | + } | |
| 23 | + } | |
| 24 | + | |
| 25 | +} | |
| 26 | + | |
| 27 | +dependencies { | |
| 28 | + implementation fileTree(dir: 'libs', include: ['*.jar']) | |
| 29 | + | |
| 30 | + implementation 'androidx.appcompat:appcompat:1.1.0' | |
| 31 | + testImplementation 'junit:junit:4.12' | |
| 32 | + androidTestImplementation 'androidx.test:runner:1.1.1' | |
| 33 | + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' | |
| 34 | + | |
| 35 | + implementation 'com.github.bumptech.glide:glide:4.10.0' | |
| 36 | + implementation 'com.squareup.okhttp3:okhttp:3.14.2' | |
| 37 | + implementation 'jp.wasabeef:glide-transformations:3.0.1' | |
| 38 | + //滤镜 | |
| 39 | + implementation 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1' | |
| 40 | +} | ... | ... |
core/imageload/consumer-rules.pro
0 → 100644
core/imageload/proguard-rules.pro
0 → 100644
| 1 | +# Add project specific ProGuard rules here. | |
| 2 | +# You can control the set of applied configuration files using the | |
| 3 | +# proguardFiles setting in build.gradle. | |
| 4 | +# | |
| 5 | +# For more details, see | |
| 6 | +# http://developer.android.com/guide/developing/tools/proguard.html | |
| 7 | + | |
| 8 | +# If your project uses WebView with JS, uncomment the following | |
| 9 | +# and specify the fully qualified class name to the JavaScript interface | |
| 10 | +# class: | |
| 11 | +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |
| 12 | +# public *; | |
| 13 | +#} | |
| 14 | + | |
| 15 | +# Uncomment this to preserve the line number information for | |
| 16 | +# debugging stack traces. | |
| 17 | +#-keepattributes SourceFile,LineNumberTable | |
| 18 | + | |
| 19 | +# If you keep the line number information, uncomment this to | |
| 20 | +# hide the original source file name. | |
| 21 | +#-renamesourcefileattribute SourceFile | ... | ... |
core/imageload/src/androidTest/java/com/mm999/imageload/ExampleInstrumentedTest.java
0 → 100644
| 1 | +package com.mm999.imageload; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | + | |
| 5 | +import androidx.test.platform.app.InstrumentationRegistry; | |
| 6 | +import androidx.test.ext.junit.runners.AndroidJUnit4; | |
| 7 | + | |
| 8 | +import org.junit.Test; | |
| 9 | +import org.junit.runner.RunWith; | |
| 10 | + | |
| 11 | +import static org.junit.Assert.*; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Instrumented test, which will execute on an Android device. | |
| 15 | + * | |
| 16 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| 17 | + */ | |
| 18 | +@RunWith(AndroidJUnit4.class) | |
| 19 | +public class ExampleInstrumentedTest { | |
| 20 | + @Test | |
| 21 | + public void useAppContext() { | |
| 22 | + // Context of the app under test. | |
| 23 | + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); | |
| 24 | + | |
| 25 | + assertEquals("com.mm999.imageload.test", appContext.getPackageName()); | |
| 26 | + } | |
| 27 | +} | ... | ... |
core/imageload/src/main/AndroidManifest.xml
0 → 100644
core/imageload/src/main/java/com/cnlive/core/imageload/callback/ImageDownLoadCallBack.java
0 → 100644
core/imageload/src/main/java/com/cnlive/core/imageload/config/AnimationMode.java
0 → 100644
core/imageload/src/main/java/com/cnlive/core/imageload/config/Contants.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.config; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * created by hanyayun | |
| 5 | + * on 2019/11/19 | |
| 6 | + */ | |
| 7 | +public interface Contants { | |
| 8 | + String FOREWARD_SLASH = "/"; | |
| 9 | + String ASSERTS_PATH ="file:///android_asset/" ; | |
| 10 | + String ANDROID_RESOURCE ="android.resource://" ; | |
| 11 | + String RAW ="/raw/" ; | |
| 12 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/config/GlobalConfig.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.config; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.content.res.Configuration; | |
| 5 | +import android.os.Handler; | |
| 6 | +import android.os.Looper; | |
| 7 | +import android.view.WindowManager; | |
| 8 | + | |
| 9 | +import com.bumptech.glide.MemoryCategory; | |
| 10 | +import com.cnlive.core.imageload.loader.GlideLoader; | |
| 11 | +import com.cnlive.core.imageload.loader.ILoader; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * created by hanyayun | |
| 15 | + * on 2019/11/19 | |
| 16 | + */ | |
| 17 | +public class GlobalConfig { | |
| 18 | + | |
| 19 | + public static String baseUrl; | |
| 20 | + public static Context context; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 屏幕高度 | |
| 24 | + */ | |
| 25 | + private static int winHeight; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 屏幕宽度 | |
| 29 | + */ | |
| 30 | + private static int winWidth; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * lrucache 最大值 | |
| 34 | + */ | |
| 35 | + public static int cacheMaxSize; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * https是否忽略校验,默认不忽略 | |
| 39 | + */ | |
| 40 | + public static boolean ignoreCertificateVerify = false; | |
| 41 | + | |
| 42 | + private static Handler mainHandler; | |
| 43 | + public static Handler getMainHandler() { | |
| 44 | + if (mainHandler == null) { | |
| 45 | + mainHandler = new Handler(Looper.getMainLooper()); | |
| 46 | + } | |
| 47 | + return mainHandler; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public static void init(Context context, int cacheSizeInM, MemoryCategory memoryCategory, boolean isInternalCD) { | |
| 51 | + | |
| 52 | + GlobalConfig.context = context; | |
| 53 | + GlobalConfig.cacheMaxSize = cacheSizeInM; | |
| 54 | + WindowManager wm = (WindowManager) context | |
| 55 | + .getSystemService(Context.WINDOW_SERVICE); | |
| 56 | + | |
| 57 | + GlobalConfig.winWidth = wm.getDefaultDisplay().getWidth(); | |
| 58 | + GlobalConfig.winHeight = wm.getDefaultDisplay().getHeight(); | |
| 59 | + getLoader().init(context, cacheSizeInM, memoryCategory, isInternalCD); | |
| 60 | + | |
| 61 | + } | |
| 62 | + | |
| 63 | + private static ILoader loader; | |
| 64 | + | |
| 65 | + public static ILoader getLoader() { | |
| 66 | + | |
| 67 | + if (loader == null) { | |
| 68 | + loader = new GlideLoader(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + return loader; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public static int getWinHeight() { | |
| 75 | + if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { | |
| 76 | + return winHeight < winWidth ? winHeight : winWidth; | |
| 77 | + } else if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { | |
| 78 | + return winHeight > winWidth ? winHeight : winWidth; | |
| 79 | + } | |
| 80 | + return winHeight; | |
| 81 | + } | |
| 82 | + | |
| 83 | + public static int getWinWidth() { | |
| 84 | + if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { | |
| 85 | + return winHeight > winWidth ? winHeight : winWidth; | |
| 86 | + } else if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { | |
| 87 | + return winHeight < winWidth ? winHeight : winWidth; | |
| 88 | + } | |
| 89 | + return winWidth; | |
| 90 | + } | |
| 91 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/config/PriorityMode.java
0 → 100644
core/imageload/src/main/java/com/cnlive/core/imageload/config/ScaleMode.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.config; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * created by hanyayun | |
| 5 | + * on 2019/11/20 | |
| 6 | + */ | |
| 7 | +public interface ScaleMode { | |
| 8 | + /** | |
| 9 | + * 等比例缩放图片,直到图片的狂高都大于等于ImageView的宽度,然后截取中间的显示 | |
| 10 | + */ | |
| 11 | + int CENTER_CROP = 1; | |
| 12 | + /** | |
| 13 | + * 等比例缩放图片,宽或者是高等于ImageView的宽或者是高 | |
| 14 | + */ | |
| 15 | + int FIT_CENTER = 2; | |
| 16 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/config/ShapeMode.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.config; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * created by hanyayun | |
| 5 | + * on 2019/11/19 | |
| 6 | + */ | |
| 7 | +public interface ShapeMode { | |
| 8 | + | |
| 9 | + /** | |
| 10 | + * 直角矩形 | |
| 11 | + */ | |
| 12 | + int RECT = 0; | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 圆角矩形 | |
| 16 | + */ | |
| 17 | + int RECT_ROUND = 1; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 椭圆/圆 | |
| 21 | + */ | |
| 22 | + int OVAL = 2; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + *正方形 | |
| 26 | + */ | |
| 27 | + int SQUARE = 3; | |
| 28 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/config/SingleConfig.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.config; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.Bitmap; | |
| 5 | +import android.util.Log; | |
| 6 | +import android.view.View; | |
| 7 | +import android.view.animation.Animation; | |
| 8 | + | |
| 9 | +import com.bumptech.glide.load.engine.DiskCacheStrategy; | |
| 10 | +import com.bumptech.glide.request.transition.ViewPropertyAnimationFactory; | |
| 11 | +import com.bumptech.glide.request.transition.ViewPropertyTransition; | |
| 12 | +import com.cnlive.core.imageload.util.ImageUtil; | |
| 13 | + | |
| 14 | +import java.io.File; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * created by hanyayun | |
| 18 | + * on 2019/11/19 | |
| 19 | + */ | |
| 20 | +public class SingleConfig { | |
| 21 | + private Context context; | |
| 22 | + private boolean ignoreCertificateVerify; //https是否忽略校验 | |
| 23 | + private String url; | |
| 24 | + | |
| 25 | + private float thumbnail; //缩略图缩放倍数 | |
| 26 | + private String filePath; //文件路径 | |
| 27 | + | |
| 28 | + private File file; //文件路径 | |
| 29 | + private int resId; //资源id | |
| 30 | + private String rawPath; //raw路径 | |
| 31 | + private String assertspath; //asserts路径 | |
| 32 | + private String contentProvider; //内容提供者 | |
| 33 | + private boolean isGif; //是否是GIF图 | |
| 34 | + private View target; | |
| 35 | + private int width; | |
| 36 | + private int height; | |
| 37 | + private int oWidth; | |
| 38 | + private int oHeight; | |
| 39 | + | |
| 40 | + //滤镜 | |
| 41 | + private boolean isNeedVignette; //是否需要晕映 | |
| 42 | + private boolean isNeedSketch; //是否需要素描 | |
| 43 | + private float pixelationLevel; //是否需要马赛克 | |
| 44 | + private boolean isNeedPixelation; //是否需要马赛克 | |
| 45 | + private boolean isNeedInvert; //是否需要胶片 | |
| 46 | + public float contrastLevel; //锐化等级 | |
| 47 | + private boolean isNeedContrast; //是否需要锐化 | |
| 48 | + private boolean isNeedSepia; //是否需要墨画 | |
| 49 | + private boolean isNeedToon; //是否需要油画 | |
| 50 | + private boolean isNeedSwirl; // 是否需要漩涡 | |
| 51 | + private boolean isNeedGrayscale; //是否需要黑色 | |
| 52 | + private boolean isNeedBrightness; //是否需要亮度 | |
| 53 | + private float brightnessLeve; //是否需要亮度 | |
| 54 | + private boolean needBlur;//是否需要模糊 | |
| 55 | + private boolean needFilteColor;//是否需要模糊 | |
| 56 | + | |
| 57 | + private int filteColor;//滤镜颜色 | |
| 58 | + private int priority;//请求优先级 | |
| 59 | + | |
| 60 | + private int animationType;//动画资源Type | |
| 61 | + private int animationId;//动画资源id | |
| 62 | + private ViewPropertyTransition.Animator animation;//动画资源 | |
| 63 | + | |
| 64 | + private ViewPropertyAnimationFactory animator;//动画资源id | |
| 65 | + | |
| 66 | + private int blurRadius;//是否需要高斯模糊 | |
| 67 | + private int placeHolderResId; //占位图 | |
| 68 | + private int errorResId; //error图 | |
| 69 | + | |
| 70 | + private int shapeMode;//默认矩形,可选直角矩形,圆形/椭圆 | |
| 71 | + private int rectRoundRadius;//圆角矩形时圆角的半径 | |
| 72 | + private DiskCacheStrategy diskCacheStrategy;//是否跳过磁盘存储 | |
| 73 | + private int scaleMode;//填充模式,默认centercrop,可选fitXY,centerInside... | |
| 74 | + | |
| 75 | + private BitmapListener bitmapListener; | |
| 76 | + private boolean asBitmap;//只获取bitmap | |
| 77 | + | |
| 78 | + public SingleConfig(ConfigBuilder builder) { | |
| 79 | + this.url = builder.url; | |
| 80 | + this.thumbnail = builder.thumbnail; | |
| 81 | + this.filePath = builder.filePath; | |
| 82 | + this.file = builder.file; | |
| 83 | + this.resId = builder.resId; | |
| 84 | + this.rawPath = builder.rawPath; | |
| 85 | + this.assertspath = builder.assertspath; | |
| 86 | + this.contentProvider = builder.contentProvider; | |
| 87 | + | |
| 88 | + this.ignoreCertificateVerify = builder.ignoreCertificateVerify; | |
| 89 | + | |
| 90 | + this.target = builder.target; | |
| 91 | + | |
| 92 | + this.width = builder.width; | |
| 93 | + this.height = builder.height; | |
| 94 | + | |
| 95 | + this.oWidth = builder.oWidth; | |
| 96 | + this.oHeight = builder.oHeight; | |
| 97 | + | |
| 98 | + this.shapeMode = builder.shapeMode; | |
| 99 | + if (shapeMode == ShapeMode.RECT_ROUND) { | |
| 100 | + this.rectRoundRadius = builder.rectRoundRadius; | |
| 101 | + } | |
| 102 | + this.scaleMode = builder.scaleMode; | |
| 103 | + | |
| 104 | + this.diskCacheStrategy = builder.diskCacheStrategy; | |
| 105 | + | |
| 106 | + this.animationId = builder.animationId; | |
| 107 | + this.animationType = builder.animationType; | |
| 108 | + this.animator = builder.animator; | |
| 109 | + this.animation = builder.animation; | |
| 110 | + | |
| 111 | + this.priority = builder.priority; | |
| 112 | + //滤镜 | |
| 113 | + this.isNeedVignette = builder.isNeedVignette; //是否需要晕映 | |
| 114 | + this.isNeedSketch = builder.isNeedSketch; //是否需要素描 | |
| 115 | + this.pixelationLevel = builder.pixelationLevel; //是否需要马赛克 | |
| 116 | + this.isNeedPixelation = builder.isNeedPixelation; //是否需要马赛克 | |
| 117 | + this.isNeedInvert = builder.isNeedInvert; //是否需要胶片 | |
| 118 | + this.contrastLevel = builder.contrastLevel; //锐化等级 | |
| 119 | + this.isNeedContrast = builder.isNeedContrast; //是否需要锐化 | |
| 120 | + this.isNeedSepia = builder.isNeedSepia; //是否需要亮度 | |
| 121 | + this.isNeedToon = builder.isNeedToon; //是否需要亮度 | |
| 122 | + this.isNeedSwirl = builder.isNeedSwirl; //是否需要亮度 | |
| 123 | + this.isNeedGrayscale = builder.isNeedGrayscale; //是否需要黑色 | |
| 124 | + this.isNeedBrightness = builder.isNeedBrightness; //是否需要亮度 | |
| 125 | + this.brightnessLeve = builder.brightnessLeve; //是否需要亮度 | |
| 126 | + this.filteColor = builder.filteColor; | |
| 127 | + this.needBlur = builder.needBlur; | |
| 128 | + this.needFilteColor = builder.needFilteColor; | |
| 129 | + this.placeHolderResId = builder.placeHolderResId; | |
| 130 | + | |
| 131 | + this.asBitmap = builder.asBitmap; | |
| 132 | + this.bitmapListener = builder.bitmapListener; | |
| 133 | + this.isGif = builder.isGif; | |
| 134 | + this.blurRadius = builder.blurRadius; | |
| 135 | + this.errorResId = builder.errorResId; | |
| 136 | + } | |
| 137 | + | |
| 138 | + | |
| 139 | + public Context getContext() { | |
| 140 | + if (context == null) { | |
| 141 | + context = GlobalConfig.context; | |
| 142 | + } | |
| 143 | + return context; | |
| 144 | + } | |
| 145 | + | |
| 146 | + public DiskCacheStrategy getDiskCacheStrategy() { | |
| 147 | + return diskCacheStrategy; | |
| 148 | + } | |
| 149 | + | |
| 150 | + public String getContentProvider() { | |
| 151 | + return contentProvider; | |
| 152 | + } | |
| 153 | + | |
| 154 | + public int getErrorResId() { | |
| 155 | + return errorResId; | |
| 156 | + } | |
| 157 | + | |
| 158 | + public String getFilePath() { | |
| 159 | + return filePath; | |
| 160 | + } | |
| 161 | + | |
| 162 | + public File getFile() { | |
| 163 | + return file; | |
| 164 | + } | |
| 165 | + | |
| 166 | + public boolean isIgnoreCertificateVerify() { | |
| 167 | + return ignoreCertificateVerify; | |
| 168 | + } | |
| 169 | + | |
| 170 | + public String getUrl() { | |
| 171 | + return url; | |
| 172 | + } | |
| 173 | + | |
| 174 | + public float getThumbnail() { | |
| 175 | + return thumbnail; | |
| 176 | + } | |
| 177 | + | |
| 178 | + public int getResId() { | |
| 179 | + return resId; | |
| 180 | + } | |
| 181 | + | |
| 182 | + public String getRawPath() { | |
| 183 | + return rawPath; | |
| 184 | + } | |
| 185 | + | |
| 186 | + public String getAssertspath() { | |
| 187 | + return assertspath; | |
| 188 | + } | |
| 189 | + | |
| 190 | + public boolean isGif() { | |
| 191 | + return isGif; | |
| 192 | + } | |
| 193 | + | |
| 194 | + public View getTarget() { | |
| 195 | + return target; | |
| 196 | + } | |
| 197 | + | |
| 198 | + public int getWidth() { | |
| 199 | + if (width <= 0) { | |
| 200 | + //先去imageview里取,如果为0,则赋值成matchparent | |
| 201 | + if (target != null) { | |
| 202 | + width = target.getMeasuredWidth(); | |
| 203 | + } | |
| 204 | + if (width <= 0) { | |
| 205 | + width = GlobalConfig.getWinWidth(); | |
| 206 | + } | |
| 207 | + } | |
| 208 | + return width; | |
| 209 | + } | |
| 210 | + | |
| 211 | + public int getHeight() { | |
| 212 | + if (height <= 0) { | |
| 213 | + //先去imageview里取,如果为0,则赋值成matchparent | |
| 214 | + if (target != null) { | |
| 215 | + height = target.getMeasuredWidth(); | |
| 216 | + } | |
| 217 | + if (height <= 0) { | |
| 218 | + height = GlobalConfig.getWinHeight(); | |
| 219 | + } | |
| 220 | + } | |
| 221 | + return height; | |
| 222 | + } | |
| 223 | + | |
| 224 | + public int getoWidth() { | |
| 225 | + return oWidth; | |
| 226 | + } | |
| 227 | + | |
| 228 | + public int getoHeight() { | |
| 229 | + return oHeight; | |
| 230 | + } | |
| 231 | + | |
| 232 | + public boolean isNeedVignette() { | |
| 233 | + return isNeedVignette; | |
| 234 | + } | |
| 235 | + | |
| 236 | + public boolean isNeedSketch() { | |
| 237 | + return isNeedSketch; | |
| 238 | + } | |
| 239 | + | |
| 240 | + public float getPixelationLevel() { | |
| 241 | + return pixelationLevel; | |
| 242 | + } | |
| 243 | + | |
| 244 | + public boolean isNeedPixelation() { | |
| 245 | + return isNeedPixelation; | |
| 246 | + } | |
| 247 | + | |
| 248 | + public boolean isNeedInvert() { | |
| 249 | + return isNeedInvert; | |
| 250 | + } | |
| 251 | + | |
| 252 | + public float getContrastLevel() { | |
| 253 | + return contrastLevel; | |
| 254 | + } | |
| 255 | + | |
| 256 | + public boolean isNeedContrast() { | |
| 257 | + return isNeedContrast; | |
| 258 | + } | |
| 259 | + | |
| 260 | + public boolean isNeedSepia() { | |
| 261 | + return isNeedSepia; | |
| 262 | + } | |
| 263 | + | |
| 264 | + public boolean isNeedToon() { | |
| 265 | + return isNeedToon; | |
| 266 | + } | |
| 267 | + | |
| 268 | + public boolean isNeedSwirl() { | |
| 269 | + return isNeedSwirl; | |
| 270 | + } | |
| 271 | + | |
| 272 | + public boolean isNeedGrayscale() { | |
| 273 | + return isNeedGrayscale; | |
| 274 | + } | |
| 275 | + | |
| 276 | + public boolean isNeedBrightness() { | |
| 277 | + return isNeedBrightness; | |
| 278 | + } | |
| 279 | + | |
| 280 | + public float getBrightnessLeve() { | |
| 281 | + return brightnessLeve; | |
| 282 | + } | |
| 283 | + | |
| 284 | + public boolean isNeedBlur() { | |
| 285 | + return needBlur; | |
| 286 | + } | |
| 287 | + | |
| 288 | + public boolean isNeedFilteColor() { | |
| 289 | + return needFilteColor; | |
| 290 | + } | |
| 291 | + | |
| 292 | + public int getFilteColor() { | |
| 293 | + return filteColor; | |
| 294 | + } | |
| 295 | + | |
| 296 | + public int getPriority() { | |
| 297 | + return priority; | |
| 298 | + } | |
| 299 | + | |
| 300 | + public int getAnimationType() { | |
| 301 | + return animationType; | |
| 302 | + } | |
| 303 | + | |
| 304 | + public int getAnimationId() { | |
| 305 | + return animationId; | |
| 306 | + } | |
| 307 | + | |
| 308 | + public ViewPropertyTransition.Animator getAnimation() { | |
| 309 | + return animation; | |
| 310 | + } | |
| 311 | + | |
| 312 | + public ViewPropertyAnimationFactory getAnimator() { | |
| 313 | + return animator; | |
| 314 | + } | |
| 315 | + | |
| 316 | + public int getBlurRadius() { | |
| 317 | + return blurRadius; | |
| 318 | + } | |
| 319 | + | |
| 320 | + public int getPlaceHolderResId() { | |
| 321 | + return placeHolderResId; | |
| 322 | + } | |
| 323 | + | |
| 324 | + public int getShapeMode() { | |
| 325 | + return shapeMode; | |
| 326 | + } | |
| 327 | + | |
| 328 | + public int getRectRoundRadius() { | |
| 329 | + return rectRoundRadius; | |
| 330 | + } | |
| 331 | + | |
| 332 | + public int getScaleMode() { | |
| 333 | + return scaleMode; | |
| 334 | + } | |
| 335 | + | |
| 336 | + public BitmapListener getBitmapListener() { | |
| 337 | + return bitmapListener; | |
| 338 | + } | |
| 339 | + | |
| 340 | + public boolean isAsBitmap() { | |
| 341 | + return asBitmap; | |
| 342 | + } | |
| 343 | + | |
| 344 | + public interface BitmapListener { | |
| 345 | + void onSuccess(Bitmap bitmap); | |
| 346 | + | |
| 347 | + void onFail(); | |
| 348 | + } | |
| 349 | + | |
| 350 | + public void setBitmapListener(BitmapListener bitmapListener) { | |
| 351 | + this.bitmapListener = ImageUtil.getBitmapListenerProxy(bitmapListener); | |
| 352 | + } | |
| 353 | + | |
| 354 | + private void show() { | |
| 355 | + GlobalConfig.getLoader().request(this); | |
| 356 | + } | |
| 357 | + | |
| 358 | + public static class ConfigBuilder { | |
| 359 | + private Context context; | |
| 360 | + | |
| 361 | + private boolean ignoreCertificateVerify = GlobalConfig.ignoreCertificateVerify; | |
| 362 | + | |
| 363 | + /** | |
| 364 | + * 图片源 | |
| 365 | + * 类型 SCHEME 示例 | |
| 366 | + * 远程图片 http://, https:// HttpURLConnection 或者参考 使用其他网络加载方案 | |
| 367 | + * 本地文件 file:// FileInputStream | |
| 368 | + * Content provider content:// ContentResolver | |
| 369 | + * asset目录下的资源 asset:// AssetManager | |
| 370 | + * res目录下的资源 res:// Resources.openRawResource | |
| 371 | + * Uri中指定图片数据 data:mime/type;base64, 数据类型必须符合 rfc2397规定 (仅支持 UTF-8) | |
| 372 | + * | |
| 373 | + * @param config | |
| 374 | + * @return | |
| 375 | + */ | |
| 376 | + private String url; | |
| 377 | + private float thumbnail; | |
| 378 | + private String filePath; | |
| 379 | + private File file; | |
| 380 | + private int resId; | |
| 381 | + private String rawPath; | |
| 382 | + private String assertspath; | |
| 383 | + private String contentProvider; | |
| 384 | + private boolean isGif = false; | |
| 385 | + | |
| 386 | + private View target; | |
| 387 | + private boolean asBitmap;//只获取bitmap | |
| 388 | + private BitmapListener bitmapListener; | |
| 389 | + | |
| 390 | + // TODO: 2017/4/24 宽高的获取 | |
| 391 | + private int width; | |
| 392 | + private int height; | |
| 393 | + | |
| 394 | + private int oWidth; //选择加载分辨率的宽 | |
| 395 | + private int oHeight; //选择加载分辨率的高 | |
| 396 | + | |
| 397 | + //滤镜 | |
| 398 | + private boolean isNeedVignette; //是否需要晕映 | |
| 399 | + private boolean isNeedSketch; //是否需要素描 | |
| 400 | + private float pixelationLevel; //是否需要马赛克 | |
| 401 | + private boolean isNeedPixelation; //是否需要马赛克 | |
| 402 | + private boolean isNeedInvert; //是否需要胶片 | |
| 403 | + private float contrastLevel; //是否需要墨画 | |
| 404 | + private boolean isNeedContrast = false; //是否需要墨画 | |
| 405 | + private boolean isNeedSepia = false; //是否需要墨画 | |
| 406 | + private boolean isNeedToon = false; //是否需要油画 | |
| 407 | + private boolean isNeedSwirl = false; //是否需要漩涡 | |
| 408 | + private boolean isNeedGrayscale = false; //是否需要亮度 | |
| 409 | + private boolean isNeedBrightness = false; //是否需要亮度 | |
| 410 | + private float brightnessLeve; //亮度等级 | |
| 411 | + private boolean needBlur = false;//是否需要模糊 | |
| 412 | + private boolean needFilteColor = false;//是否需要滤镜颜色 | |
| 413 | + private int blurRadius; | |
| 414 | + | |
| 415 | + //UI: | |
| 416 | + private int placeHolderResId; | |
| 417 | + | |
| 418 | + private int errorResId; | |
| 419 | + | |
| 420 | + private int shapeMode;//默认矩形,可选直角矩形,圆形/椭圆 | |
| 421 | + private int rectRoundRadius;//圆角矩形时圆角的半径 | |
| 422 | + | |
| 423 | + private DiskCacheStrategy diskCacheStrategy; | |
| 424 | + | |
| 425 | + private int scaleMode;//填充模式,默认centercrop,可选fitXY,centerInside... | |
| 426 | + | |
| 427 | + private int priority; //请求优先级 | |
| 428 | + | |
| 429 | + private int filteColor; //滤镜颜色 | |
| 430 | + | |
| 431 | + public int animationId; //动画资源id | |
| 432 | + public int animationType; //动画资源Type | |
| 433 | + public ViewPropertyTransition.Animator animation; //动画资源 | |
| 434 | + public ViewPropertyAnimationFactory animator; //动画资源id | |
| 435 | + | |
| 436 | + public ConfigBuilder(Context context) { | |
| 437 | + this.context = context; | |
| 438 | + } | |
| 439 | + | |
| 440 | + public ConfigBuilder ignoreCertificateVerify(boolean ignoreCertificateVerify) { | |
| 441 | + this.ignoreCertificateVerify = ignoreCertificateVerify; | |
| 442 | + return this; | |
| 443 | + } | |
| 444 | + | |
| 445 | + /** | |
| 446 | + * 缩略图 | |
| 447 | + * | |
| 448 | + * @param thumbnail | |
| 449 | + * @return | |
| 450 | + */ | |
| 451 | + public ConfigBuilder thumbnail(float thumbnail) { | |
| 452 | + this.thumbnail = thumbnail; | |
| 453 | + return this; | |
| 454 | + } | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * error图 | |
| 458 | + * | |
| 459 | + * @param errorResId | |
| 460 | + * @return | |
| 461 | + */ | |
| 462 | + public ConfigBuilder error(int errorResId) { | |
| 463 | + this.errorResId = errorResId; | |
| 464 | + return this; | |
| 465 | + } | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * 设置网络路径 | |
| 469 | + * | |
| 470 | + * @param url | |
| 471 | + * @return | |
| 472 | + */ | |
| 473 | + public ConfigBuilder url(String url) { | |
| 474 | + this.url = url; | |
| 475 | + if (url.contains("gif")) { | |
| 476 | + isGif = true; | |
| 477 | + } | |
| 478 | + return this; | |
| 479 | + } | |
| 480 | + | |
| 481 | + /** | |
| 482 | + * 加载SD卡资源 | |
| 483 | + * | |
| 484 | + * @param filePath | |
| 485 | + * @return | |
| 486 | + */ | |
| 487 | + public ConfigBuilder file(String filePath) { | |
| 488 | + if (filePath.startsWith("file:")) { | |
| 489 | + this.filePath = filePath; | |
| 490 | + return this; | |
| 491 | + } | |
| 492 | + | |
| 493 | + if (!new File(filePath).exists()) { | |
| 494 | + //throw new RuntimeException("文件不存在"); | |
| 495 | + Log.e("imageloader", "文件不存在"); | |
| 496 | + return this; | |
| 497 | + } | |
| 498 | + | |
| 499 | + this.filePath = filePath; | |
| 500 | + if (filePath.contains("gif")) { | |
| 501 | + isGif = true; | |
| 502 | + } | |
| 503 | + return this; | |
| 504 | + } | |
| 505 | + | |
| 506 | + /** | |
| 507 | + * 加载SD卡资源 | |
| 508 | + * | |
| 509 | + * @param file | |
| 510 | + * @return | |
| 511 | + */ | |
| 512 | + public ConfigBuilder file(File file) { | |
| 513 | + this.file = file; | |
| 514 | + | |
| 515 | + return this; | |
| 516 | + } | |
| 517 | + | |
| 518 | + /** | |
| 519 | + * 加载drawable资源 | |
| 520 | + * | |
| 521 | + * @param resId | |
| 522 | + * @return | |
| 523 | + */ | |
| 524 | + public ConfigBuilder res(int resId) { | |
| 525 | + this.resId = resId; | |
| 526 | + return this; | |
| 527 | + } | |
| 528 | + | |
| 529 | + /** | |
| 530 | + * 加载ContentProvider资源 | |
| 531 | + * | |
| 532 | + * @param contentProvider | |
| 533 | + * @return | |
| 534 | + */ | |
| 535 | + public ConfigBuilder content(String contentProvider) { | |
| 536 | + if (contentProvider.startsWith("content:")) { | |
| 537 | + this.contentProvider = contentProvider; | |
| 538 | + return this; | |
| 539 | + } | |
| 540 | + | |
| 541 | + if (contentProvider.contains("gif")) { | |
| 542 | + isGif = true; | |
| 543 | + } | |
| 544 | + | |
| 545 | + return this; | |
| 546 | + } | |
| 547 | + | |
| 548 | + /** | |
| 549 | + * 加载raw资源 | |
| 550 | + * | |
| 551 | + * @param rawPath | |
| 552 | + * @return | |
| 553 | + */ | |
| 554 | + public ConfigBuilder raw(String rawPath) { | |
| 555 | + | |
| 556 | + this.rawPath = rawPath; | |
| 557 | + | |
| 558 | + if (rawPath.contains("gif")) { | |
| 559 | + isGif = true; | |
| 560 | + } | |
| 561 | + | |
| 562 | + return this; | |
| 563 | + } | |
| 564 | + | |
| 565 | + /** | |
| 566 | + * 加载asserts资源 | |
| 567 | + * | |
| 568 | + * @param assertspath | |
| 569 | + * @return | |
| 570 | + */ | |
| 571 | + public ConfigBuilder asserts(String assertspath) { | |
| 572 | + this.assertspath = assertspath; | |
| 573 | + | |
| 574 | + if (assertspath.contains("gif")) { | |
| 575 | + isGif = true; | |
| 576 | + } | |
| 577 | + | |
| 578 | + return this; | |
| 579 | + } | |
| 580 | + | |
| 581 | + public void into(View targetView) { | |
| 582 | + this.target = targetView; | |
| 583 | + new SingleConfig(this).show(); | |
| 584 | + } | |
| 585 | + | |
| 586 | + public void asBitmap(BitmapListener bitmapListener) { | |
| 587 | + this.bitmapListener = ImageUtil.getBitmapListenerProxy(bitmapListener); | |
| 588 | + this.asBitmap = true; | |
| 589 | + new SingleConfig(this).show(); | |
| 590 | + } | |
| 591 | + | |
| 592 | + /** | |
| 593 | + * 加载图片的分辨率 | |
| 594 | + * | |
| 595 | + * @param oWidth | |
| 596 | + * @param oHeight | |
| 597 | + * @return | |
| 598 | + */ | |
| 599 | + public ConfigBuilder override(int oWidth, int oHeight) { | |
| 600 | + this.oWidth = ImageUtil.dip2px(oWidth); | |
| 601 | + this.oHeight = ImageUtil.dip2px(oHeight); | |
| 602 | + return this; | |
| 603 | + } | |
| 604 | + | |
| 605 | + /** | |
| 606 | + * 占位图 | |
| 607 | + * | |
| 608 | + * @param placeHolderResId | |
| 609 | + * @return | |
| 610 | + */ | |
| 611 | + public ConfigBuilder placeHolder(int placeHolderResId) { | |
| 612 | + this.placeHolderResId = placeHolderResId; | |
| 613 | + return this; | |
| 614 | + } | |
| 615 | + | |
| 616 | + | |
| 617 | + /** | |
| 618 | + * 是否需要高斯模糊 | |
| 619 | + * | |
| 620 | + * @return | |
| 621 | + */ | |
| 622 | + public ConfigBuilder blur(int blurRadius) { | |
| 623 | + this.needBlur = true; | |
| 624 | + this.blurRadius = blurRadius; | |
| 625 | + return this; | |
| 626 | + } | |
| 627 | + | |
| 628 | + /** | |
| 629 | + * 圆角 | |
| 630 | + | |
| 631 | + * @return | |
| 632 | + */ | |
| 633 | + public ConfigBuilder asCircle() { | |
| 634 | + this.shapeMode = ShapeMode.OVAL; | |
| 635 | + return this; | |
| 636 | + } | |
| 637 | + | |
| 638 | + /** | |
| 639 | + * 形状为圆角矩形时的圆角半径 | |
| 640 | + * | |
| 641 | + * @param rectRoundRadius | |
| 642 | + * @return | |
| 643 | + */ | |
| 644 | + public ConfigBuilder rectRoundCorner(int rectRoundRadius) { | |
| 645 | + this.rectRoundRadius = ImageUtil.dip2px(rectRoundRadius); | |
| 646 | + this.shapeMode = ShapeMode.RECT_ROUND; | |
| 647 | + return this; | |
| 648 | + } | |
| 649 | + | |
| 650 | + | |
| 651 | + /** | |
| 652 | + * 正方形 | |
| 653 | + * | |
| 654 | + * @return | |
| 655 | + */ | |
| 656 | + public ConfigBuilder asSquare() { | |
| 657 | + this.shapeMode = ShapeMode.SQUARE; | |
| 658 | + return this; | |
| 659 | + } | |
| 660 | + | |
| 661 | + | |
| 662 | + /** | |
| 663 | + * 磁盘缓存 | |
| 664 | + */ | |
| 665 | + public ConfigBuilder diskCacheStrategy(DiskCacheStrategy diskCacheStrategy) { | |
| 666 | + this.diskCacheStrategy = diskCacheStrategy; | |
| 667 | + return this; | |
| 668 | + } | |
| 669 | + | |
| 670 | + /** | |
| 671 | + * 拉伸/裁剪模式 | |
| 672 | + * | |
| 673 | + * @param scaleMode 取值ScaleMode | |
| 674 | + * @return | |
| 675 | + */ | |
| 676 | + public ConfigBuilder scale(int scaleMode) { | |
| 677 | + this.scaleMode = scaleMode; | |
| 678 | + return this; | |
| 679 | + } | |
| 680 | + | |
| 681 | + | |
| 682 | + public ConfigBuilder animate(int animationId) { | |
| 683 | + this.animationType = AnimationMode.ANIMATIONID; | |
| 684 | + this.animationId = animationId; | |
| 685 | + return this; | |
| 686 | + } | |
| 687 | + | |
| 688 | + public ConfigBuilder animate(ViewPropertyAnimationFactory animator) { | |
| 689 | + this.animationType = AnimationMode.ANIMATOR; | |
| 690 | + this.animator = animator; | |
| 691 | + return this; | |
| 692 | + } | |
| 693 | + | |
| 694 | + public ConfigBuilder animate(ViewPropertyTransition.Animator animation) { | |
| 695 | + this.animationType = AnimationMode.ANIMATION; | |
| 696 | + this.animation = animation; | |
| 697 | + return this; | |
| 698 | + } | |
| 699 | + | |
| 700 | + public ConfigBuilder priority(int priority) { | |
| 701 | + this.priority = priority; | |
| 702 | + | |
| 703 | + return this; | |
| 704 | + } | |
| 705 | + | |
| 706 | + public ConfigBuilder colorFilter(int filteColor) { | |
| 707 | + this.filteColor = filteColor; | |
| 708 | + this.needFilteColor = true; | |
| 709 | + return this; | |
| 710 | + } | |
| 711 | + | |
| 712 | + public ConfigBuilder brightnessFilter(float level) { | |
| 713 | + this.isNeedBrightness = true; | |
| 714 | + this.brightnessLeve = level; | |
| 715 | + return this; | |
| 716 | + } | |
| 717 | + | |
| 718 | + public ConfigBuilder grayscaleFilter() { | |
| 719 | + this.isNeedGrayscale = true; | |
| 720 | + return this; | |
| 721 | + } | |
| 722 | + | |
| 723 | + public ConfigBuilder swirlFilter() { | |
| 724 | + this.isNeedSwirl = true; | |
| 725 | + return this; | |
| 726 | + } | |
| 727 | + | |
| 728 | + public ConfigBuilder toonFilter() { | |
| 729 | + this.isNeedToon = true; | |
| 730 | + return this; | |
| 731 | + } | |
| 732 | + | |
| 733 | + public ConfigBuilder sepiaFilter() { | |
| 734 | + this.isNeedSepia = true; | |
| 735 | + return this; | |
| 736 | + } | |
| 737 | + | |
| 738 | + public ConfigBuilder contrastFilter(float constrasrLevel) { | |
| 739 | + this.contrastLevel = constrasrLevel; | |
| 740 | + this.isNeedContrast = true; | |
| 741 | + return this; | |
| 742 | + } | |
| 743 | + | |
| 744 | + public ConfigBuilder invertFilter() { | |
| 745 | + this.isNeedInvert = true; | |
| 746 | + return this; | |
| 747 | + } | |
| 748 | + | |
| 749 | + public ConfigBuilder pixelationFilter(float pixelationLevel) { | |
| 750 | + this.pixelationLevel = pixelationLevel; | |
| 751 | + this.isNeedPixelation = true; | |
| 752 | + return this; | |
| 753 | + } | |
| 754 | + | |
| 755 | + public ConfigBuilder sketchFilter() { | |
| 756 | + this.isNeedSketch = true; | |
| 757 | + return this; | |
| 758 | + } | |
| 759 | + | |
| 760 | + public ConfigBuilder vignetteFilter() { | |
| 761 | + this.isNeedVignette = true; | |
| 762 | + return this; | |
| 763 | + } | |
| 764 | + | |
| 765 | + | |
| 766 | + } | |
| 767 | + | |
| 768 | + | |
| 769 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/loader/GlideLoader.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.loader; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.Bitmap; | |
| 5 | +import android.graphics.PointF; | |
| 6 | +import android.graphics.drawable.Drawable; | |
| 7 | +import android.net.Uri; | |
| 8 | +import android.text.TextUtils; | |
| 9 | +import android.util.Log; | |
| 10 | +import android.view.View; | |
| 11 | +import android.widget.ImageView; | |
| 12 | + | |
| 13 | +import com.bumptech.glide.GenericTransitionOptions; | |
| 14 | +import com.bumptech.glide.Glide; | |
| 15 | +import com.bumptech.glide.GlideBuilder; | |
| 16 | +import com.bumptech.glide.MemoryCategory; | |
| 17 | +import com.bumptech.glide.Priority; | |
| 18 | +import com.bumptech.glide.RequestBuilder; | |
| 19 | +import com.bumptech.glide.RequestManager; | |
| 20 | +import com.bumptech.glide.load.Transformation; | |
| 21 | +import com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory; | |
| 22 | +import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory; | |
| 23 | +import com.bumptech.glide.request.RequestOptions; | |
| 24 | +import com.bumptech.glide.request.target.SimpleTarget; | |
| 25 | +import com.bumptech.glide.request.transition.Transition; | |
| 26 | +import com.bumptech.glide.request.transition.ViewPropertyTransition; | |
| 27 | +import com.cnlive.core.imageload.R; | |
| 28 | +import com.cnlive.core.imageload.config.AnimationMode; | |
| 29 | +import com.cnlive.core.imageload.config.GlobalConfig; | |
| 30 | +import com.cnlive.core.imageload.config.PriorityMode; | |
| 31 | +import com.cnlive.core.imageload.config.ScaleMode; | |
| 32 | +import com.cnlive.core.imageload.config.ShapeMode; | |
| 33 | +import com.cnlive.core.imageload.config.SingleConfig; | |
| 34 | +import com.cnlive.core.imageload.util.DownLoadImageService; | |
| 35 | +import com.cnlive.core.imageload.util.ImageUtil; | |
| 36 | +import com.cnlive.libs.base.application.GlideApp; | |
| 37 | + | |
| 38 | +import androidx.annotation.Nullable; | |
| 39 | +import jp.wasabeef.glide.transformations.BlurTransformation; | |
| 40 | +import jp.wasabeef.glide.transformations.ColorFilterTransformation; | |
| 41 | +import jp.wasabeef.glide.transformations.CropCircleTransformation; | |
| 42 | +import jp.wasabeef.glide.transformations.CropSquareTransformation; | |
| 43 | +import jp.wasabeef.glide.transformations.GrayscaleTransformation; | |
| 44 | +import jp.wasabeef.glide.transformations.RoundedCornersTransformation; | |
| 45 | +import jp.wasabeef.glide.transformations.gpu.BrightnessFilterTransformation; | |
| 46 | +import jp.wasabeef.glide.transformations.gpu.ContrastFilterTransformation; | |
| 47 | +import jp.wasabeef.glide.transformations.gpu.InvertFilterTransformation; | |
| 48 | +import jp.wasabeef.glide.transformations.gpu.PixelationFilterTransformation; | |
| 49 | +import jp.wasabeef.glide.transformations.gpu.SepiaFilterTransformation; | |
| 50 | +import jp.wasabeef.glide.transformations.gpu.SketchFilterTransformation; | |
| 51 | +import jp.wasabeef.glide.transformations.gpu.SwirlFilterTransformation; | |
| 52 | +import jp.wasabeef.glide.transformations.gpu.ToonFilterTransformation; | |
| 53 | +import jp.wasabeef.glide.transformations.gpu.VignetteFilterTransformation; | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * created by hanyayun | |
| 57 | + * on 2019/11/19 | |
| 58 | + */ | |
| 59 | +public class GlideLoader implements ILoader{ | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * @param context 上下文 | |
| 63 | + * @param cacheSizeInM Glide默认磁盘缓存最大容量250MB | |
| 64 | + * @param memoryCategory 调整内存缓存的大小 LOW(0.5f) / NORMAL(1f) / HIGH(1.5f); | |
| 65 | + * @param isInternalCD true 磁盘缓存到应用的内部目录 / false 磁盘缓存到外部存 | |
| 66 | + */ | |
| 67 | + @Override | |
| 68 | + public void init(Context context, int cacheSizeInM, MemoryCategory memoryCategory, boolean isInternalCD) { | |
| 69 | + Glide.get(context).setMemoryCategory(memoryCategory); //如果在应用当中想要调整内存缓存的大小,开发者可以通过如下方式: | |
| 70 | + GlideBuilder builder = new GlideBuilder(); | |
| 71 | + if (isInternalCD) { | |
| 72 | + builder.setDiskCache(new InternalCacheDiskCacheFactory(context, cacheSizeInM * 1024 * 1024)); | |
| 73 | + } else { | |
| 74 | + builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, cacheSizeInM * 1024 * 1024)); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Override | |
| 79 | + public void request(SingleConfig config) { | |
| 80 | + RequestManager requestManager = Glide.with(config.getContext()); | |
| 81 | + RequestBuilder<Drawable> request = getDrawableTypeRequest(config, requestManager); | |
| 82 | + | |
| 83 | + if (config.isAsBitmap()) { | |
| 84 | + SimpleTarget target = new SimpleTarget<Bitmap>(config.getWidth(), config.getHeight()) { | |
| 85 | + @Override | |
| 86 | + public void onResourceReady(Bitmap bitmap, Transition glideAnimation) { | |
| 87 | + config.getBitmapListener().onSuccess(bitmap); | |
| 88 | + } | |
| 89 | + }; | |
| 90 | + | |
| 91 | + setShapeModeAndBlur(config, request); | |
| 92 | + | |
| 93 | + if (config.getDiskCacheStrategy() != null) { | |
| 94 | + request.diskCacheStrategy(config.getDiskCacheStrategy()); | |
| 95 | + } | |
| 96 | + | |
| 97 | + request.into(target); | |
| 98 | + | |
| 99 | + } else { | |
| 100 | + | |
| 101 | + if (request == null) { | |
| 102 | + return; | |
| 103 | + } | |
| 104 | + | |
| 105 | + if (ImageUtil.shouldSetPlaceHolder(config)) { | |
| 106 | + request.placeholder(config.getPlaceHolderResId()); | |
| 107 | + } | |
| 108 | + | |
| 109 | + int scaleMode = config.getScaleMode(); | |
| 110 | + | |
| 111 | + switch (scaleMode) { | |
| 112 | + case ScaleMode.CENTER_CROP: | |
| 113 | + request.centerCrop(); | |
| 114 | + break; | |
| 115 | + case ScaleMode.FIT_CENTER: | |
| 116 | + request.fitCenter(); | |
| 117 | + break; | |
| 118 | + default: | |
| 119 | + request.fitCenter(); | |
| 120 | + break; | |
| 121 | + } | |
| 122 | + | |
| 123 | + setShapeModeAndBlur(config, request); | |
| 124 | + | |
| 125 | + //设置缩略图 | |
| 126 | + if (config.getThumbnail() != 0) { | |
| 127 | + request.thumbnail(config.getThumbnail()); | |
| 128 | + } | |
| 129 | + | |
| 130 | + //设置图片加载的分辨 sp | |
| 131 | + if (config.getoWidth() != 0 && config.getoHeight() != 0) { | |
| 132 | + request.override(config.getoWidth(), config.getoHeight()); | |
| 133 | + } | |
| 134 | + | |
| 135 | + //是否跳过磁盘存储 | |
| 136 | + if (config.getDiskCacheStrategy() != null) { | |
| 137 | + request.diskCacheStrategy(config.getDiskCacheStrategy()); | |
| 138 | + } | |
| 139 | + | |
| 140 | + //设置图片加载动画 | |
| 141 | + setAnimator(config, request); | |
| 142 | + | |
| 143 | + //设置图片加载优先级 | |
| 144 | + setPriority(config, request); | |
| 145 | + | |
| 146 | + if (config.getErrorResId() > 0) { | |
| 147 | + request.error(config.getErrorResId()); | |
| 148 | + } | |
| 149 | + | |
| 150 | +// if(config.isGif()){ | |
| 151 | +// request.asGif(); | |
| 152 | +// } | |
| 153 | + | |
| 154 | + if (config.getTarget() instanceof ImageView) { | |
| 155 | + request.into((ImageView) config.getTarget()); | |
| 156 | + | |
| 157 | + } | |
| 158 | + } | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * 设置加载优先级 | |
| 163 | + * | |
| 164 | + * @param config | |
| 165 | + * @param request | |
| 166 | + */ | |
| 167 | + private void setPriority(SingleConfig config, RequestBuilder<Drawable> request) { | |
| 168 | + switch (config.getPriority()) { | |
| 169 | + case PriorityMode.PRIORITY_LOW: | |
| 170 | + request.priority(Priority.LOW); | |
| 171 | + break; | |
| 172 | + case PriorityMode.PRIORITY_NORMAL: | |
| 173 | + request.priority(Priority.NORMAL); | |
| 174 | + break; | |
| 175 | + case PriorityMode.PRIORITY_HIGH: | |
| 176 | + request.priority(Priority.HIGH); | |
| 177 | + break; | |
| 178 | + case PriorityMode.PRIORITY_IMMEDIATE: | |
| 179 | + request.priority(Priority.IMMEDIATE); | |
| 180 | + break; | |
| 181 | + default: | |
| 182 | + request.priority(Priority.IMMEDIATE); | |
| 183 | + break; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * 设置加载进入动画 | |
| 189 | + * | |
| 190 | + * @param config | |
| 191 | + * @param request | |
| 192 | + */ | |
| 193 | + private void setAnimator(SingleConfig config, RequestBuilder<Drawable> request) { | |
| 194 | + if (config.getAnimationType() == AnimationMode.ANIMATIONID) { | |
| 195 | + request.transition(GenericTransitionOptions.with(config.getAnimationId())); | |
| 196 | +// request.anaimate(config.getAnimationId()); | |
| 197 | + } else if (config.getAnimationType() == AnimationMode.ANIMATOR) { | |
| 198 | + request.transition(GenericTransitionOptions.with(config.getAnimator())); | |
| 199 | +// request.animate(config.getAnimator()); | |
| 200 | + } else if (config.getAnimationType() == AnimationMode.ANIMATION) { | |
| 201 | + request.transition(GenericTransitionOptions.with(config.getAnimation())); | |
| 202 | +// request.animate(config.getAnimation()); | |
| 203 | + } | |
| 204 | + } | |
| 205 | + | |
| 206 | + @Nullable | |
| 207 | + private RequestBuilder<Drawable> getDrawableTypeRequest(SingleConfig config, RequestManager requestManager) { | |
| 208 | + RequestBuilder<Drawable> request = null; | |
| 209 | + if (!TextUtils.isEmpty(config.getUrl())) { | |
| 210 | + request = requestManager.load(ImageUtil.appendUrl(config.getUrl())); | |
| 211 | + Log.e("TAG","getUrl : "+config.getUrl()); | |
| 212 | + } else if (!TextUtils.isEmpty(config.getFilePath())) { | |
| 213 | + request = requestManager.load(ImageUtil.appendUrl(config.getFilePath())); | |
| 214 | + Log.e("TAG","getFilePath : "+config.getFilePath()); | |
| 215 | + } else if (!TextUtils.isEmpty(config.getContentProvider())) { | |
| 216 | + request = requestManager.load(Uri.parse(config.getContentProvider())); | |
| 217 | + Log.e("TAG","getContentProvider : "+config.getContentProvider()); | |
| 218 | + } else if (config.getResId() > 0) { | |
| 219 | + request = requestManager.load(config.getResId()); | |
| 220 | + Log.e("TAG","getResId : "+config.getResId()); | |
| 221 | + } else if(config.getFile() != null){ | |
| 222 | + request = requestManager.load(config.getFile()); | |
| 223 | + Log.e("TAG","getFile : "+config.getFile()); | |
| 224 | + } else if(!TextUtils.isEmpty(config.getAssertspath())){ | |
| 225 | + request = requestManager.load(config.getAssertspath()); | |
| 226 | + Log.e("TAG","getAssertspath : "+config.getAssertspath()); | |
| 227 | + } else if(!TextUtils.isEmpty(config.getRawPath())){ | |
| 228 | + request = requestManager.load(config.getRawPath()); | |
| 229 | + Log.e("TAG","getRawPath : "+config.getRawPath()); | |
| 230 | + } | |
| 231 | + return request; | |
| 232 | + } | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * 设置图片滤镜和形状 | |
| 236 | + * | |
| 237 | + * @param config | |
| 238 | + * @param request | |
| 239 | + */ | |
| 240 | + private void setShapeModeAndBlur(SingleConfig config, RequestBuilder<Drawable> request) { | |
| 241 | + | |
| 242 | + int count = 0; | |
| 243 | + | |
| 244 | + Transformation[] transformation = new Transformation[statisticsCount(config)]; | |
| 245 | + | |
| 246 | + if (config.isNeedBlur()) { | |
| 247 | + transformation[count] = new BlurTransformation(config.getBlurRadius()); | |
| 248 | + count++; | |
| 249 | + } | |
| 250 | + | |
| 251 | + if (config.isNeedBrightness()) { | |
| 252 | + transformation[count] = new BrightnessFilterTransformation(config.getBrightnessLeve()); //亮度 | |
| 253 | + count++; | |
| 254 | + } | |
| 255 | + | |
| 256 | + if (config.isNeedGrayscale()) { | |
| 257 | + transformation[count] = new GrayscaleTransformation(); //黑白效果 | |
| 258 | + count++; | |
| 259 | + } | |
| 260 | + | |
| 261 | + if (config.isNeedFilteColor()) { | |
| 262 | + transformation[count] = new ColorFilterTransformation(config.getFilteColor()); | |
| 263 | + count++; | |
| 264 | + } | |
| 265 | + | |
| 266 | + if (config.isNeedSwirl()) { | |
| 267 | + transformation[count] = new SwirlFilterTransformation( 0.5f, 1.0f, new PointF(0.5f, 0.5f)); //漩涡 | |
| 268 | + count++; | |
| 269 | + } | |
| 270 | + | |
| 271 | + if (config.isNeedToon()) { | |
| 272 | + transformation[count] = new ToonFilterTransformation(); //油画 | |
| 273 | + count++; | |
| 274 | + } | |
| 275 | + | |
| 276 | + if (config.isNeedSepia()) { | |
| 277 | + transformation[count] = new SepiaFilterTransformation(); //墨画 | |
| 278 | + count++; | |
| 279 | + } | |
| 280 | + | |
| 281 | + if (config.isNeedContrast()) { | |
| 282 | + transformation[count] = new ContrastFilterTransformation( config.getContrastLevel()); //锐化 | |
| 283 | + count++; | |
| 284 | + } | |
| 285 | + | |
| 286 | + if (config.isNeedInvert()) { | |
| 287 | + transformation[count] = new InvertFilterTransformation(); //胶片 | |
| 288 | + count++; | |
| 289 | + } | |
| 290 | + | |
| 291 | + if (config.isNeedPixelation()) { | |
| 292 | + transformation[count] =new PixelationFilterTransformation(config.getPixelationLevel()); //马赛克 | |
| 293 | + count++; | |
| 294 | + } | |
| 295 | + | |
| 296 | + if (config.isNeedSketch()) { | |
| 297 | + transformation[count] =new SketchFilterTransformation(); //素描 | |
| 298 | + count++; | |
| 299 | + } | |
| 300 | + | |
| 301 | + if (config.isNeedVignette()) { | |
| 302 | + transformation[count] =new VignetteFilterTransformation(new PointF(0.5f, 0.5f), | |
| 303 | + new float[] { 0.0f, 0.0f, 0.0f }, 0f, 0.75f);//晕映 | |
| 304 | + count++; | |
| 305 | + } | |
| 306 | + | |
| 307 | + switch (config.getShapeMode()) { | |
| 308 | + case ShapeMode.RECT: | |
| 309 | + | |
| 310 | + break; | |
| 311 | + case ShapeMode.RECT_ROUND: | |
| 312 | + transformation[count] = new RoundedCornersTransformation | |
| 313 | + (config.getRectRoundRadius(), 0, RoundedCornersTransformation.CornerType.ALL); | |
| 314 | + count++; | |
| 315 | + break; | |
| 316 | + case ShapeMode.OVAL: | |
| 317 | + transformation[count] = new CropCircleTransformation(); | |
| 318 | + count++; | |
| 319 | + break; | |
| 320 | + | |
| 321 | + case ShapeMode.SQUARE: | |
| 322 | + transformation[count] = new CropSquareTransformation(); | |
| 323 | + count++; | |
| 324 | + break; | |
| 325 | + } | |
| 326 | + | |
| 327 | + if (transformation.length != 0) { | |
| 328 | + request.transform(transformation); | |
| 329 | + | |
| 330 | + } | |
| 331 | + | |
| 332 | + } | |
| 333 | + | |
| 334 | + | |
| 335 | + private int statisticsCount(SingleConfig config) { | |
| 336 | + int count = 0; | |
| 337 | + | |
| 338 | + if (config.getShapeMode() == ShapeMode.OVAL || config.getShapeMode() == ShapeMode.RECT_ROUND || config.getShapeMode() == ShapeMode.SQUARE) { | |
| 339 | + count++; | |
| 340 | + } | |
| 341 | + | |
| 342 | + if (config.isNeedBlur()) { | |
| 343 | + count++; | |
| 344 | + } | |
| 345 | + | |
| 346 | + if (config.isNeedFilteColor()) { | |
| 347 | + count++; | |
| 348 | + } | |
| 349 | + | |
| 350 | + if (config.isNeedBrightness()) { | |
| 351 | + count++; | |
| 352 | + } | |
| 353 | + | |
| 354 | + if (config.isNeedGrayscale()) { | |
| 355 | + count++; | |
| 356 | + } | |
| 357 | + | |
| 358 | + if (config.isNeedSwirl()) { | |
| 359 | + count++; | |
| 360 | + } | |
| 361 | + | |
| 362 | + if (config.isNeedToon()) { | |
| 363 | + count++; | |
| 364 | + } | |
| 365 | + | |
| 366 | + if (config.isNeedSepia()) { | |
| 367 | + count++; | |
| 368 | + } | |
| 369 | + | |
| 370 | + if (config.isNeedContrast()) { | |
| 371 | + count++; | |
| 372 | + } | |
| 373 | + | |
| 374 | + if (config.isNeedInvert()) { | |
| 375 | + count++; | |
| 376 | + } | |
| 377 | + | |
| 378 | + if (config.isNeedPixelation()) { | |
| 379 | + count++; | |
| 380 | + } | |
| 381 | + | |
| 382 | + if (config.isNeedSketch()) { | |
| 383 | + count++; | |
| 384 | + } | |
| 385 | + | |
| 386 | + if (config.isNeedVignette()) { | |
| 387 | + count++; | |
| 388 | + } | |
| 389 | + | |
| 390 | + return count; | |
| 391 | + } | |
| 392 | + | |
| 393 | + @Override | |
| 394 | + public void pause() { | |
| 395 | + Glide.with(GlobalConfig.context).pauseRequestsRecursive(); | |
| 396 | + } | |
| 397 | + | |
| 398 | + @Override | |
| 399 | + public void resume() { | |
| 400 | + Glide.with(GlobalConfig.context).resumeRequestsRecursive(); | |
| 401 | + } | |
| 402 | + | |
| 403 | + @Override | |
| 404 | + public void clearDiskCache() { | |
| 405 | + Glide.get(GlobalConfig.context).clearDiskCache(); | |
| 406 | + } | |
| 407 | + | |
| 408 | + @Override | |
| 409 | + public void clearMomoryCache(Context context,View view) { | |
| 410 | + Glide.with(context).clear(view); | |
| 411 | + } | |
| 412 | + | |
| 413 | + @Override | |
| 414 | + public void clearMomory() { | |
| 415 | + Glide.get(GlobalConfig.context).clearMemory(); | |
| 416 | + } | |
| 417 | + | |
| 418 | + @Override | |
| 419 | + public boolean isCached(String url) { | |
| 420 | + return false; | |
| 421 | + } | |
| 422 | + | |
| 423 | + @Override | |
| 424 | + public void trimMemory(int level) { | |
| 425 | + Glide.with(GlobalConfig.context).onTrimMemory(level); | |
| 426 | + } | |
| 427 | + | |
| 428 | + @Override | |
| 429 | + public void clearAllMemoryCaches() { | |
| 430 | + Glide.with(GlobalConfig.context).onLowMemory(); | |
| 431 | + } | |
| 432 | + | |
| 433 | + @Override | |
| 434 | + public void saveImageIntoGallery(DownLoadImageService downLoadImageService) { | |
| 435 | + new Thread(downLoadImageService).start(); | |
| 436 | + } | |
| 437 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/loader/ILoader.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.loader; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.view.View; | |
| 5 | + | |
| 6 | +import com.bumptech.glide.MemoryCategory; | |
| 7 | +import com.cnlive.core.imageload.config.SingleConfig; | |
| 8 | +import com.cnlive.core.imageload.util.DownLoadImageService; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * created by hanyayun | |
| 12 | + * on 2019/11/19 | |
| 13 | + */ | |
| 14 | +public interface ILoader { | |
| 15 | + | |
| 16 | + void init(Context context, int cacheSizeInM, MemoryCategory memoryCategory, boolean isInternalCD); | |
| 17 | + | |
| 18 | + void request(SingleConfig config); | |
| 19 | + | |
| 20 | + void pause(); | |
| 21 | + | |
| 22 | + void resume(); | |
| 23 | + | |
| 24 | + void clearDiskCache(); | |
| 25 | + | |
| 26 | + void clearMomoryCache(Context context,View view); | |
| 27 | + | |
| 28 | + void clearMomory(); | |
| 29 | + | |
| 30 | + boolean isCached(String url); | |
| 31 | + | |
| 32 | + void trimMemory(int level); | |
| 33 | + | |
| 34 | + void clearAllMemoryCaches(); | |
| 35 | + | |
| 36 | + void saveImageIntoGallery(DownLoadImageService downLoadImageService); | |
| 37 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/loader/ImageLoader.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.loader; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.view.View; | |
| 5 | + | |
| 6 | +import com.bumptech.glide.MemoryCategory; | |
| 7 | +import com.cnlive.core.imageload.config.GlobalConfig; | |
| 8 | +import com.cnlive.core.imageload.config.SingleConfig; | |
| 9 | +import com.cnlive.core.imageload.util.DownLoadImageService; | |
| 10 | + | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * created by hanyayun | |
| 14 | + * on 2019/11/22 | |
| 15 | + */ | |
| 16 | +public class ImageLoader { | |
| 17 | + | |
| 18 | + public static Context context; | |
| 19 | + /** | |
| 20 | + * 默认最大缓存 | |
| 21 | + */ | |
| 22 | + public static int CACHE_IMAGE_SIZE = 250; | |
| 23 | + | |
| 24 | + public static void init(final Context context) { | |
| 25 | + init(context, CACHE_IMAGE_SIZE); | |
| 26 | + } | |
| 27 | + | |
| 28 | + public static void init(final Context context, int cacheSizeInM) { | |
| 29 | + init(context, cacheSizeInM, MemoryCategory.NORMAL); | |
| 30 | + } | |
| 31 | + | |
| 32 | + public static void init(final Context context, int cacheSizeInM, MemoryCategory memoryCategory) { | |
| 33 | + init(context, cacheSizeInM, memoryCategory, true); | |
| 34 | + } | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * @param context 上下文 | |
| 38 | + * @param cacheSizeInM Glide默认磁盘缓存最大容量250MB | |
| 39 | + * @param memoryCategory 调整内存缓存的大小 LOW(0.5f) / NORMAL(1f) / HIGH(1.5f); | |
| 40 | + * @param isInternalCD true 磁盘缓存到应用的内部目录 / false 磁盘缓存到外部存 | |
| 41 | + */ | |
| 42 | + public static void init(final Context context, int cacheSizeInM, MemoryCategory memoryCategory, boolean isInternalCD) { | |
| 43 | + ImageLoader.context = context; | |
| 44 | + GlobalConfig.init(context, cacheSizeInM, memoryCategory, isInternalCD); | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 获取当前的Loader | |
| 49 | + * @return | |
| 50 | + */ | |
| 51 | + public static ILoader getActualLoader() { | |
| 52 | + return GlobalConfig.getLoader(); | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * 加载普通图片 | |
| 57 | + * | |
| 58 | + * @param context | |
| 59 | + * @return | |
| 60 | + */ | |
| 61 | + public static SingleConfig.ConfigBuilder with(Context context) { | |
| 62 | + return new SingleConfig.ConfigBuilder(context); | |
| 63 | + } | |
| 64 | + | |
| 65 | + public static void trimMemory(int level) { | |
| 66 | + getActualLoader().trimMemory(level); | |
| 67 | + } | |
| 68 | + | |
| 69 | + public static void clearAllMemoryCaches() { | |
| 70 | + getActualLoader().clearAllMemoryCaches(); | |
| 71 | + } | |
| 72 | + | |
| 73 | + public static void pauseRequests() { | |
| 74 | + getActualLoader().pause(); | |
| 75 | + | |
| 76 | + } | |
| 77 | + | |
| 78 | + public static void resumeRequests() { | |
| 79 | + getActualLoader().resume(); | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + *Cancel any pending loads Glide may have for the view and free any resources that may have been loaded for the view. | |
| 84 | + * @param view | |
| 85 | + */ | |
| 86 | + public static void clearMomoryCache(Context context,View view) { | |
| 87 | + getActualLoader().clearMomoryCache(context,view); | |
| 88 | + } | |
| 89 | + | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Clears disk cache. | |
| 93 | + * | |
| 94 | + * <p> | |
| 95 | + * This method should always be called on a background thread, since it is a blocking call. | |
| 96 | + * </p> | |
| 97 | + */ | |
| 98 | + public static void clearDiskCache() { | |
| 99 | + getActualLoader().clearDiskCache(); | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Clears as much memory as possible. | |
| 104 | + */ | |
| 105 | + public static void clearMomory() { | |
| 106 | + getActualLoader().clearMomory(); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * 图片保存到相册 | |
| 111 | + * | |
| 112 | + * @param downLoadImageService | |
| 113 | + */ | |
| 114 | + public static void saveImageIntoGallery(DownLoadImageService downLoadImageService) { | |
| 115 | + getActualLoader().saveImageIntoGallery(downLoadImageService); | |
| 116 | + } | |
| 117 | + | |
| 118 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/util/DownLoadImageService.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.util; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.content.Intent; | |
| 5 | +import android.graphics.Bitmap; | |
| 6 | +import android.net.Uri; | |
| 7 | +import android.os.Build; | |
| 8 | +import android.os.Environment; | |
| 9 | +import android.provider.MediaStore; | |
| 10 | + | |
| 11 | +import com.bumptech.glide.Glide; | |
| 12 | +import com.bumptech.glide.request.target.Target; | |
| 13 | +import com.cnlive.core.imageload.callback.ImageDownLoadCallBack; | |
| 14 | + | |
| 15 | +import java.io.File; | |
| 16 | +import java.io.FileNotFoundException; | |
| 17 | +import java.io.FileOutputStream; | |
| 18 | +import java.io.IOException; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * 图片下载 | |
| 22 | + * created by hanyayun | |
| 23 | + * on 2019/11/19 | |
| 24 | + */ | |
| 25 | +public class DownLoadImageService implements Runnable{ | |
| 26 | + | |
| 27 | + private String url; | |
| 28 | + private Context context; | |
| 29 | + private ImageDownLoadCallBack callBack; | |
| 30 | + private File currentFile; | |
| 31 | + private String fileName; | |
| 32 | + | |
| 33 | + private boolean isSetMediaStore; | |
| 34 | + | |
| 35 | + public DownLoadImageService(Context context, String url,boolean isSetMediaStore , String fileName, ImageDownLoadCallBack callBack) { | |
| 36 | + this.url = url; | |
| 37 | + this.callBack = callBack; | |
| 38 | + this.context = context; | |
| 39 | + this.isSetMediaStore = isSetMediaStore; | |
| 40 | + this.fileName = fileName; | |
| 41 | + } | |
| 42 | + | |
| 43 | + @Override | |
| 44 | + public void run() { | |
| 45 | + | |
| 46 | + Bitmap bitmap = null; | |
| 47 | + try { | |
| 48 | + bitmap = Glide.with(context) | |
| 49 | + .asBitmap() | |
| 50 | + .load(url) | |
| 51 | + .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) | |
| 52 | + .get(); | |
| 53 | + if (bitmap != null){ | |
| 54 | + // 在这里执行图片保存方法 | |
| 55 | + saveImageToGallery(context,bitmap); | |
| 56 | + } | |
| 57 | + } catch (Exception e) { | |
| 58 | + e.printStackTrace(); | |
| 59 | + } finally { | |
| 60 | + if (bitmap != null && currentFile.exists()) { | |
| 61 | + callBack.onDownLoadSuccess(bitmap); | |
| 62 | + } else { | |
| 63 | + callBack.onDownLoadFailed(); | |
| 64 | + } | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + public void saveImageToGallery(Context context, Bitmap bmp) { | |
| 69 | + // 首先保存图片 | |
| 70 | + | |
| 71 | + File file = Build.VERSION.SDK_INT > 28?context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsoluteFile():Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsoluteFile();//注意小米手机必须这样获得public绝对路径 | |
| 72 | + | |
| 73 | + File appDir = new File(file ,fileName); | |
| 74 | + if (!appDir.exists()) { | |
| 75 | + appDir.mkdirs(); | |
| 76 | + } | |
| 77 | + fileName = System.currentTimeMillis() + ".jpg"; | |
| 78 | + currentFile = new File(appDir, fileName); | |
| 79 | + | |
| 80 | + FileOutputStream fos = null; | |
| 81 | + try { | |
| 82 | + fos = new FileOutputStream(currentFile); | |
| 83 | + bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos); | |
| 84 | + fos.flush(); | |
| 85 | + } catch (FileNotFoundException e) { | |
| 86 | + e.printStackTrace(); | |
| 87 | + } catch (IOException e) { | |
| 88 | + e.printStackTrace(); | |
| 89 | + } finally { | |
| 90 | + try { | |
| 91 | + if (fos != null) { | |
| 92 | + fos.close(); | |
| 93 | + } | |
| 94 | + } catch (IOException e) { | |
| 95 | + e.printStackTrace(); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + | |
| 99 | + if(isSetMediaStore){ | |
| 100 | + setMediaDtore(fileName); | |
| 101 | + } | |
| 102 | + | |
| 103 | + // 最后通知图库更新 | |
| 104 | + context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, | |
| 105 | + Uri.fromFile(new File(currentFile.getPath())))); | |
| 106 | + } | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * 加入到系统图库 | |
| 110 | + * @param fileName | |
| 111 | + */ | |
| 112 | + public void setMediaDtore(String fileName){ | |
| 113 | + try { | |
| 114 | + MediaStore.Images.Media.insertImage(context.getContentResolver(), | |
| 115 | + currentFile.getAbsolutePath(), fileName, null); | |
| 116 | + } catch (FileNotFoundException e) { | |
| 117 | + e.printStackTrace(); | |
| 118 | + } | |
| 119 | + } | |
| 120 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/util/ImageUtil.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.util; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.Bitmap; | |
| 5 | +import android.graphics.Matrix; | |
| 6 | +import android.net.Uri; | |
| 7 | +import android.text.TextUtils; | |
| 8 | +import android.util.Log; | |
| 9 | + | |
| 10 | +import com.cnlive.core.imageload.config.GlobalConfig; | |
| 11 | +import com.cnlive.core.imageload.config.SingleConfig; | |
| 12 | + | |
| 13 | +import java.io.File; | |
| 14 | +import java.io.FileInputStream; | |
| 15 | +import java.io.IOException; | |
| 16 | +import java.lang.reflect.InvocationHandler; | |
| 17 | +import java.lang.reflect.InvocationTargetException; | |
| 18 | +import java.lang.reflect.Method; | |
| 19 | +import java.lang.reflect.Proxy; | |
| 20 | +import java.security.KeyManagementException; | |
| 21 | +import java.security.NoSuchAlgorithmException; | |
| 22 | +import java.security.SecureRandom; | |
| 23 | +import java.security.cert.X509Certificate; | |
| 24 | +import java.util.concurrent.TimeUnit; | |
| 25 | + | |
| 26 | +import javax.net.ssl.HostnameVerifier; | |
| 27 | +import javax.net.ssl.SSLContext; | |
| 28 | +import javax.net.ssl.SSLSession; | |
| 29 | +import javax.net.ssl.TrustManager; | |
| 30 | +import javax.net.ssl.X509TrustManager; | |
| 31 | + | |
| 32 | +import okhttp3.OkHttpClient; | |
| 33 | + | |
| 34 | +import static com.cnlive.core.imageload.config.Contants.ANDROID_RESOURCE; | |
| 35 | +import static com.cnlive.core.imageload.config.Contants.FOREWARD_SLASH; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * created by hanyayun | |
| 39 | + * on 2019/11/19 | |
| 40 | + */ | |
| 41 | +public class ImageUtil { | |
| 42 | + | |
| 43 | + public static SingleConfig.BitmapListener getBitmapListenerProxy(final SingleConfig.BitmapListener listener) { | |
| 44 | + return (SingleConfig.BitmapListener) Proxy.newProxyInstance(SingleConfig.class.getClassLoader(), | |
| 45 | + listener.getClass().getInterfaces(), new InvocationHandler() { | |
| 46 | + @Override | |
| 47 | + public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable { | |
| 48 | + | |
| 49 | + runOnUIThread(new Runnable() { | |
| 50 | + @Override | |
| 51 | + public void run() { | |
| 52 | + try { | |
| 53 | + Object object = method.invoke(listener, args); | |
| 54 | + } catch (IllegalAccessException e) { | |
| 55 | + e.printStackTrace(); | |
| 56 | + } catch (InvocationTargetException e) { | |
| 57 | + e.printStackTrace(); | |
| 58 | + } | |
| 59 | + } | |
| 60 | + }); | |
| 61 | + return null; | |
| 62 | + } | |
| 63 | + }); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public static void runOnUIThread(Runnable runnable) { | |
| 67 | + GlobalConfig.getMainHandler().post(runnable); | |
| 68 | + } | |
| 69 | + | |
| 70 | + public static boolean shouldSetPlaceHolder(SingleConfig config) { | |
| 71 | + if (config.getPlaceHolderResId() <= 0) { | |
| 72 | + return false; | |
| 73 | + } | |
| 74 | + | |
| 75 | + if (config.getResId() > 0 || !TextUtils.isEmpty(config.getFilePath()) || GlobalConfig.getLoader().isCached(config.getUrl())) { | |
| 76 | + return false; | |
| 77 | + } else {//只有在图片源为网络图片,并且图片没有缓存到本地时,才给显示placeholder | |
| 78 | + return true; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + public static int dip2px(float dipValue) { | |
| 83 | + final float scale = GlobalConfig.context.getResources().getDisplayMetrics().density; | |
| 84 | + return (int) (dipValue * scale + 0.5f); | |
| 85 | + } | |
| 86 | + | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * 等比压缩(宽高等比缩放) | |
| 90 | + * | |
| 91 | + * @param bitmap | |
| 92 | + * @param needRecycle | |
| 93 | + * @param targetWidth | |
| 94 | + * @param targeHeight | |
| 95 | + * @return | |
| 96 | + */ | |
| 97 | + public static Bitmap compressBitmap(Bitmap bitmap, boolean needRecycle, int targetWidth, int targeHeight) { | |
| 98 | + float sourceWidth = bitmap.getWidth(); | |
| 99 | + float sourceHeight = bitmap.getHeight(); | |
| 100 | + | |
| 101 | + float scaleWidth = targetWidth / sourceWidth; | |
| 102 | + float scaleHeight = targeHeight / sourceHeight; | |
| 103 | + | |
| 104 | + Matrix matrix = new Matrix(); | |
| 105 | + matrix.postScale(scaleWidth, scaleHeight); //长和宽放大缩小的比例 | |
| 106 | + Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); | |
| 107 | + if (needRecycle) { | |
| 108 | + bitmap.recycle(); | |
| 109 | + } | |
| 110 | + bitmap = bm; | |
| 111 | + return bitmap; | |
| 112 | + } | |
| 113 | + | |
| 114 | + public static String getRealType(File file) { | |
| 115 | + FileInputStream is = null; | |
| 116 | + try { | |
| 117 | + is = new FileInputStream(file); | |
| 118 | + byte[] b = new byte[4]; | |
| 119 | + try { | |
| 120 | + is.read(b, 0, b.length); | |
| 121 | + } catch (IOException e) { | |
| 122 | + e.printStackTrace(); | |
| 123 | + return ""; | |
| 124 | + } | |
| 125 | + String type = bytesToHexString(b).toUpperCase(); | |
| 126 | + if (type.contains("FFD8FF")) { | |
| 127 | + return "jpg"; | |
| 128 | + } else if (type.contains("89504E47")) { | |
| 129 | + return "png"; | |
| 130 | + } else if (type.contains("47494638")) { | |
| 131 | + return "gif"; | |
| 132 | + } else if (type.contains("49492A00")) { | |
| 133 | + return "tif"; | |
| 134 | + } else if (type.contains("424D")) { | |
| 135 | + return "bmp"; | |
| 136 | + } | |
| 137 | + return type; | |
| 138 | + } catch (Exception e) { | |
| 139 | + e.printStackTrace(); | |
| 140 | + return ""; | |
| 141 | + } finally { | |
| 142 | + try { | |
| 143 | + is.close(); | |
| 144 | + } catch (IOException e) { | |
| 145 | + e.printStackTrace(); | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + } | |
| 150 | + | |
| 151 | + public static String bytesToHexString(byte[] src) { | |
| 152 | + StringBuilder stringBuilder = new StringBuilder(); | |
| 153 | + if (src == null || src.length <= 0) { | |
| 154 | + return null; | |
| 155 | + } | |
| 156 | + for (int i = 0; i < src.length; i++) { | |
| 157 | + int v = src[i] & 0xFF; | |
| 158 | + String hv = Integer.toHexString(v); | |
| 159 | + if (hv.length() < 2) { | |
| 160 | + stringBuilder.append(0); | |
| 161 | + } | |
| 162 | + stringBuilder.append(hv); | |
| 163 | + } | |
| 164 | + return stringBuilder.toString(); | |
| 165 | + } | |
| 166 | + | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * 类型 SCHEME 示例 | |
| 170 | + * 远程图片 http://, https:// HttpURLConnection 或者参考 使用其他网络加载方案 | |
| 171 | + * 本地文件 file:// FileInputStream | |
| 172 | + * Content provider content:// ContentResolver | |
| 173 | + * asset目录下的资源 asset:// AssetManager | |
| 174 | + * res目录下的资源 res:// Resources.openRawResource | |
| 175 | + * Uri中指定图片数据 data:mime/type;base64, 数据类型必须符合 rfc2397规定 (仅支持 UTF-8) | |
| 176 | + * | |
| 177 | + * @param config | |
| 178 | + * @return | |
| 179 | + */ | |
| 180 | + public static Uri buildUriByType(SingleConfig config) { | |
| 181 | + | |
| 182 | + Log.e("builduri:", "url: " + config.getUrl() + " ---filepath:" + config.getFilePath() + "--content:" + config.getContentProvider()); | |
| 183 | + | |
| 184 | + if (!TextUtils.isEmpty(config.getUrl())) { | |
| 185 | + String url = ImageUtil.appendUrl(config.getUrl()); | |
| 186 | + return Uri.parse(url); | |
| 187 | + } | |
| 188 | + | |
| 189 | + if (config.getResId() > 0) { | |
| 190 | + return Uri.parse("res://imageloader/" + config.getResId()); | |
| 191 | + } | |
| 192 | + | |
| 193 | + if (!TextUtils.isEmpty(config.getFilePath())) { | |
| 194 | + | |
| 195 | + File file = new File(config.getFilePath()); | |
| 196 | + if (file.exists()) { | |
| 197 | + return Uri.fromFile(file); | |
| 198 | + } | |
| 199 | + } | |
| 200 | + | |
| 201 | + if (!TextUtils.isEmpty(config.getContentProvider())) { | |
| 202 | + String content = config.getContentProvider(); | |
| 203 | + if (!content.startsWith("content")) { | |
| 204 | + content = "content://" + content; | |
| 205 | + } | |
| 206 | + return Uri.parse(content); | |
| 207 | + } | |
| 208 | + | |
| 209 | + | |
| 210 | + return null; | |
| 211 | + } | |
| 212 | + | |
| 213 | + | |
| 214 | + public static String appendUrl(String url) { | |
| 215 | + String newUrl = url; | |
| 216 | + if (TextUtils.isEmpty(newUrl)) { | |
| 217 | + return newUrl; | |
| 218 | + } | |
| 219 | + boolean hasHost = url.contains("http:") || url.contains("https:"); | |
| 220 | + if (!hasHost) { | |
| 221 | + if (!TextUtils.isEmpty(GlobalConfig.baseUrl)) { | |
| 222 | + newUrl = GlobalConfig.baseUrl + url; | |
| 223 | + } | |
| 224 | + } | |
| 225 | + | |
| 226 | + return newUrl; | |
| 227 | + } | |
| 228 | + | |
| 229 | + public static OkHttpClient getClient(boolean ignoreCertificateVerify) { | |
| 230 | + if (ignoreCertificateVerify) { | |
| 231 | + return getAllPassClient(); | |
| 232 | + } else { | |
| 233 | + return getNormalClient(); | |
| 234 | + } | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** | |
| 238 | + * 不校验证书 | |
| 239 | + * | |
| 240 | + * @return | |
| 241 | + */ | |
| 242 | + private static OkHttpClient getAllPassClient() { | |
| 243 | + | |
| 244 | + X509TrustManager xtm = new X509TrustManager() { | |
| 245 | + @Override | |
| 246 | + public void checkClientTrusted(X509Certificate[] chain, String authType) { | |
| 247 | + } | |
| 248 | + | |
| 249 | + @Override | |
| 250 | + public void checkServerTrusted(X509Certificate[] chain, String authType) { | |
| 251 | + } | |
| 252 | + | |
| 253 | + @Override | |
| 254 | + public X509Certificate[] getAcceptedIssuers() { | |
| 255 | + X509Certificate[] x509Certificates = new X509Certificate[]{}; | |
| 256 | + return x509Certificates; | |
| 257 | + // return null; | |
| 258 | + } | |
| 259 | + }; | |
| 260 | + | |
| 261 | + SSLContext sslContext = null; | |
| 262 | + try { | |
| 263 | + sslContext = SSLContext.getInstance("SSL"); | |
| 264 | + | |
| 265 | + sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom()); | |
| 266 | + | |
| 267 | + } catch (NoSuchAlgorithmException e) { | |
| 268 | + e.printStackTrace(); | |
| 269 | + } catch (KeyManagementException e) { | |
| 270 | + e.printStackTrace(); | |
| 271 | + } | |
| 272 | + | |
| 273 | + | |
| 274 | + HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { | |
| 275 | + @Override | |
| 276 | + public boolean verify(String hostname, SSLSession session) { | |
| 277 | + return true; | |
| 278 | + } | |
| 279 | + }; | |
| 280 | + | |
| 281 | + OkHttpClient client = new OkHttpClient.Builder() | |
| 282 | + .sslSocketFactory(sslContext.getSocketFactory()) | |
| 283 | + .hostnameVerifier(DO_NOT_VERIFY) | |
| 284 | + .readTimeout(0, TimeUnit.SECONDS) | |
| 285 | + .connectTimeout(30, TimeUnit.SECONDS).writeTimeout(0, TimeUnit.SECONDS) //设置超时 | |
| 286 | + .build(); | |
| 287 | + | |
| 288 | + return client; | |
| 289 | + } | |
| 290 | + | |
| 291 | + private static OkHttpClient getNormalClient() { | |
| 292 | + OkHttpClient client = new OkHttpClient.Builder() | |
| 293 | + //.sslSocketFactory(sslContext.getSocketFactory()) | |
| 294 | + //.hostnameVerifier(DO_NOT_VERIFY) | |
| 295 | + .readTimeout(0, TimeUnit.SECONDS) | |
| 296 | + .connectTimeout(30, TimeUnit.SECONDS).writeTimeout(0, TimeUnit.SECONDS) //设置超时 | |
| 297 | + .build(); | |
| 298 | + return client; | |
| 299 | + } | |
| 300 | + | |
| 301 | + private static Uri resourceIdToUri(Context context, int resourceId) { | |
| 302 | + return Uri.parse(ANDROID_RESOURCE + context.getPackageName() + FOREWARD_SLASH + resourceId); | |
| 303 | + } | |
| 304 | + | |
| 305 | +} | ... | ... |
core/imageload/src/main/java/com/cnlive/core/imageload/util/MultiView.java
0 → 100644
| 1 | +package com.cnlive.core.imageload.util; | |
| 2 | + | |
| 3 | +import android.annotation.SuppressLint; | |
| 4 | +import android.content.Context; | |
| 5 | +import android.content.res.TypedArray; | |
| 6 | +import android.graphics.Bitmap; | |
| 7 | +import android.graphics.BitmapShader; | |
| 8 | +import android.graphics.Canvas; | |
| 9 | +import android.graphics.Matrix; | |
| 10 | +import android.graphics.Paint; | |
| 11 | +import android.graphics.Path; | |
| 12 | +import android.graphics.PointF; | |
| 13 | +import android.graphics.RectF; | |
| 14 | +import android.graphics.Shader; | |
| 15 | +import android.graphics.drawable.BitmapDrawable; | |
| 16 | +import android.graphics.drawable.Drawable; | |
| 17 | +import android.os.Bundle; | |
| 18 | +import android.os.Parcelable; | |
| 19 | +import android.util.AttributeSet; | |
| 20 | +import android.util.TypedValue; | |
| 21 | +import android.widget.ImageView; | |
| 22 | + | |
| 23 | +import com.cnlive.core.imageload.R; | |
| 24 | + | |
| 25 | +import java.util.ArrayList; | |
| 26 | +import java.util.List; | |
| 27 | + | |
| 28 | +import androidx.annotation.Nullable; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * created by hanyayun | |
| 32 | + * on 2019/11/22 | |
| 33 | + */ | |
| 34 | +public class MultiView extends ImageView { | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 图片的类型,圆形or圆角or多边形 | |
| 38 | + */ | |
| 39 | + private Context mContext; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 传输类型 | |
| 43 | + */ | |
| 44 | + private int type; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 圆形 | |
| 48 | + */ | |
| 49 | + public static final int TYPE_CIRCLE = 0; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 圆角 | |
| 53 | + */ | |
| 54 | + public static final int TYPE_ROUND = 1; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 多边形 | |
| 58 | + */ | |
| 59 | + public static final int TYPE_MULTI = 3; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + *默认多边形角的个数 | |
| 63 | + */ | |
| 64 | + public static final int ANGLECOUNT = 5; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * 默认开始绘制的角度 | |
| 68 | + */ | |
| 69 | + public static final int CURRENTANGLE = 180; | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 多边形的半径 | |
| 73 | + */ | |
| 74 | + private int startRadius; | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 多边形角的个数 | |
| 78 | + */ | |
| 79 | + private int angleCount ; | |
| 80 | + | |
| 81 | + private int[] angles; | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * 开始绘制的角度 | |
| 85 | + */ | |
| 86 | + private int currentAngle; | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * 存储角位置的集合 | |
| 90 | + */ | |
| 91 | + private List<PointF> pointFList = new ArrayList<>(); | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * 圆角大小的默认值 | |
| 95 | + */ | |
| 96 | + private static final int BODER_RADIUS_DEFAULT = 10; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * 圆角的大小 | |
| 100 | + */ | |
| 101 | + private int mBorderRadius; | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * 绘图的Paint | |
| 105 | + */ | |
| 106 | + private Paint mBitmapPaint; | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * 圆角的半径 | |
| 110 | + */ | |
| 111 | + private int mRadius; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * 3x3 矩阵,主要用于缩小放大 | |
| 115 | + */ | |
| 116 | + private Matrix mMatrix; | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * 渲染图像,使用图像为绘制图形着色 | |
| 120 | + */ | |
| 121 | + private BitmapShader mBitmapShader; | |
| 122 | + | |
| 123 | + /** | |
| 124 | + * view的宽度 | |
| 125 | + */ | |
| 126 | + private int mWidth; | |
| 127 | + private RectF mRoundRect; | |
| 128 | + | |
| 129 | + public MultiView(Context context) { | |
| 130 | + this(context, null); | |
| 131 | + } | |
| 132 | + | |
| 133 | + public MultiView(Context context, AttributeSet attrs) { | |
| 134 | + | |
| 135 | + this(context, attrs, 0); | |
| 136 | + | |
| 137 | + } | |
| 138 | + | |
| 139 | + public MultiView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | |
| 140 | + super(context, attrs, defStyleAttr); | |
| 141 | + | |
| 142 | + this.mContext = context; | |
| 143 | + | |
| 144 | + init(context, attrs); | |
| 145 | + | |
| 146 | + } | |
| 147 | + | |
| 148 | + public void init(Context context, AttributeSet attrs) { | |
| 149 | + mMatrix = new Matrix(); | |
| 150 | + mBitmapPaint = new Paint(); | |
| 151 | + mBitmapPaint.setAntiAlias(true); | |
| 152 | + | |
| 153 | + TypedArray typedArray = context.obtainStyledAttributes(attrs, | |
| 154 | + R.styleable.RoundImageView); | |
| 155 | + | |
| 156 | + mBorderRadius = typedArray.getDimensionPixelSize( | |
| 157 | + R.styleable.RoundImageView_borderRadius, (int) TypedValue | |
| 158 | + .applyDimension(TypedValue.COMPLEX_UNIT_DIP, | |
| 159 | + BODER_RADIUS_DEFAULT, getResources() | |
| 160 | + .getDisplayMetrics()));// 默认为10dp | |
| 161 | + type = typedArray.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);// 默认为Circle | |
| 162 | + angleCount = typedArray.getInt(R.styleable.RoundImageView_angleCount, ANGLECOUNT); | |
| 163 | + currentAngle = typedArray.getInt(R.styleable.RoundImageView_currentAngle, currentAngle); | |
| 164 | + | |
| 165 | + typedArray.recycle(); //回收之后对象可以重用 | |
| 166 | + } | |
| 167 | + @Override | |
| 168 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
| 169 | + super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * 如果类型是圆形或多边形,则强制改变view的宽高一致,以小值为准 | |
| 173 | + */ | |
| 174 | + if (type == TYPE_CIRCLE) { | |
| 175 | + mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight()); | |
| 176 | + mRadius = mWidth / 2; | |
| 177 | + setMeasuredDimension(mWidth, mWidth); | |
| 178 | + } | |
| 179 | + | |
| 180 | + if (type == TYPE_MULTI) { | |
| 181 | + mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight()); | |
| 182 | + | |
| 183 | + setMeasuredDimension(mWidth, mWidth); | |
| 184 | + | |
| 185 | + angles = new int[angleCount]; | |
| 186 | + | |
| 187 | + for (int i = 0; i < angleCount; i++) { | |
| 188 | + int partOfAngle = 360 / angleCount; //每个顶点的角度 | |
| 189 | + angles[i] = currentAngle + partOfAngle * i; | |
| 190 | + | |
| 191 | + startRadius = mWidth / 2; | |
| 192 | + float x = (float) (Math.sin(Math.toRadians(angles[i])) * startRadius); | |
| 193 | + float y = (float) (Math.cos(Math.toRadians(angles[i])) * startRadius); | |
| 194 | + pointFList.add(new PointF(x, y)); | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * 初始化BitmapShader | |
| 202 | + */ | |
| 203 | + private void setUpShader() { | |
| 204 | + Drawable drawable = getDrawable(); | |
| 205 | + if (drawable == null) { | |
| 206 | + return; | |
| 207 | + } | |
| 208 | + | |
| 209 | + Bitmap bmp = drawableToBitamp(drawable); | |
| 210 | + // 将bmp作为着色器,就是在指定区域内绘制bmp | |
| 211 | + mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); | |
| 212 | + float scale = 1.0f; | |
| 213 | + if (type == TYPE_CIRCLE) { | |
| 214 | + // 拿到bitmap宽或高的小值 | |
| 215 | + int bSize = Math.min(bmp.getWidth(), bmp.getHeight()); | |
| 216 | + scale = mWidth * 1.0f / bSize; | |
| 217 | + | |
| 218 | + } else if (type == TYPE_ROUND) { | |
| 219 | + if (!(bmp.getWidth() == getWidth() && bmp.getHeight() == getHeight())) { | |
| 220 | + // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值; | |
| 221 | + scale = Math.max(getWidth() * 1.0f / bmp.getWidth(), getHeight() * 1.0f / bmp.getHeight()); | |
| 222 | + } | |
| 223 | + | |
| 224 | + } else if (type == TYPE_MULTI) { | |
| 225 | + // 拿到bitmap宽或高的小值 | |
| 226 | + int bSize = Math.min(bmp.getWidth(), bmp.getHeight()); | |
| 227 | + scale = mWidth * 1.0f / bSize; | |
| 228 | + } | |
| 229 | + // shader的变换矩阵,我们这里主要用于放大或者缩小 | |
| 230 | + mMatrix.setScale(scale, scale); | |
| 231 | + | |
| 232 | + // 设置变换矩阵 | |
| 233 | + mBitmapShader.setLocalMatrix(mMatrix); | |
| 234 | + // 设置shader | |
| 235 | + mBitmapPaint.setShader(mBitmapShader); | |
| 236 | + } | |
| 237 | + | |
| 238 | + @Override | |
| 239 | + protected void onDraw(Canvas canvas) { | |
| 240 | + if (getDrawable() == null) { | |
| 241 | + return; | |
| 242 | + } | |
| 243 | + setUpShader(); | |
| 244 | + | |
| 245 | + if (type == TYPE_ROUND) { | |
| 246 | + canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius, | |
| 247 | + mBitmapPaint); | |
| 248 | + } else if (type == TYPE_MULTI) { | |
| 249 | + //canvas.translate(startRadius,startRadius); | |
| 250 | + | |
| 251 | + Path mPath = drawPath(); | |
| 252 | + | |
| 253 | + canvas.drawPath(mPath, mBitmapPaint); | |
| 254 | + } else { | |
| 255 | + canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint); | |
| 256 | + } | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * @return 多边形路径 | |
| 261 | + */ | |
| 262 | + private Path drawPath() { | |
| 263 | + Path mPath = new Path(); | |
| 264 | + mPath.moveTo(pointFList.get(0).x, pointFList.get(0).y); | |
| 265 | + for (int i = 2; i < angleCount; i++) { | |
| 266 | + if (i % 2 == 0) {// 除以二取余数,余数为0则为偶数,否则奇数 | |
| 267 | + mPath.lineTo(pointFList.get(i).x, pointFList.get(i).y); | |
| 268 | + } | |
| 269 | + | |
| 270 | + } | |
| 271 | + | |
| 272 | + if (angleCount % 2 == 0) { //偶数,moveTo | |
| 273 | + mPath.moveTo(pointFList.get(1).x, pointFList.get(1).y); | |
| 274 | + } else { //奇数,lineTo | |
| 275 | + mPath.lineTo(pointFList.get(1).x, pointFList.get(1).y); | |
| 276 | + } | |
| 277 | + | |
| 278 | + for (int i = 3; i < angleCount; i++) { | |
| 279 | + if (i % 2 != 0) { | |
| 280 | + mPath.lineTo(pointFList.get(i).x, pointFList.get(i).y); | |
| 281 | + } | |
| 282 | + } | |
| 283 | + | |
| 284 | + mPath.offset(startRadius, startRadius); | |
| 285 | + return mPath; | |
| 286 | + } | |
| 287 | + | |
| 288 | + @Override | |
| 289 | + protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
| 290 | + super.onSizeChanged(w, h, oldw, oldh); | |
| 291 | + | |
| 292 | + // 圆角图片的范围 | |
| 293 | + if (type == TYPE_ROUND) | |
| 294 | + mRoundRect = new RectF(0, 0, w, h); | |
| 295 | + } | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * drawable转bitmap | |
| 299 | + * | |
| 300 | + * @param drawable | |
| 301 | + * @return | |
| 302 | + */ | |
| 303 | + private Bitmap drawableToBitamp(Drawable drawable) { | |
| 304 | + if (drawable instanceof BitmapDrawable) { | |
| 305 | + BitmapDrawable bd = (BitmapDrawable) drawable; | |
| 306 | + return bd.getBitmap(); | |
| 307 | + } | |
| 308 | + int w = drawable.getIntrinsicWidth(); | |
| 309 | + int h = drawable.getIntrinsicHeight(); | |
| 310 | + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); | |
| 311 | + Canvas canvas = new Canvas(bitmap); | |
| 312 | + drawable.setBounds(0, 0, w, h); | |
| 313 | + drawable.draw(canvas); | |
| 314 | + return bitmap; | |
| 315 | + } | |
| 316 | + | |
| 317 | + private static final String STATE_INSTANCE = "state_instance"; | |
| 318 | + private static final String STATE_TYPE = "state_type"; | |
| 319 | + private static final String STATE_BORDER_RADIUS = "state_border_radius"; | |
| 320 | + | |
| 321 | + @Override | |
| 322 | + protected Parcelable onSaveInstanceState() { | |
| 323 | + Bundle bundle = new Bundle(); | |
| 324 | + bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState()); | |
| 325 | + bundle.putInt(STATE_TYPE, type); | |
| 326 | + bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius); | |
| 327 | + return bundle; | |
| 328 | + } | |
| 329 | + | |
| 330 | + @Override | |
| 331 | + protected void onRestoreInstanceState(Parcelable state) { | |
| 332 | + if (state instanceof Bundle) { | |
| 333 | + Bundle bundle = (Bundle) state; | |
| 334 | + super.onRestoreInstanceState(((Bundle) state) | |
| 335 | + .getParcelable(STATE_INSTANCE)); | |
| 336 | + this.type = bundle.getInt(STATE_TYPE); | |
| 337 | + this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS); | |
| 338 | + } else { | |
| 339 | + super.onRestoreInstanceState(state); | |
| 340 | + } | |
| 341 | + | |
| 342 | + } | |
| 343 | + | |
| 344 | + public void setType(int type) { | |
| 345 | + if (this.type != type) { | |
| 346 | + this.type = type; | |
| 347 | + if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE && this.type != TYPE_MULTI) { | |
| 348 | + this.type = TYPE_CIRCLE; | |
| 349 | + } | |
| 350 | + requestLayout(); | |
| 351 | + } | |
| 352 | + | |
| 353 | + } | |
| 354 | + | |
| 355 | +} | |
| 356 | + | ... | ... |
core/imageload/src/main/res/values/strings.xml
0 → 100644
core/imageload/src/main/res/values/style.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<resources> | |
| 3 | + <declare-styleable name="RoundImageView"> | |
| 4 | + <attr name="borderRadius" format="dimension" /> | |
| 5 | + <attr name="type"> | |
| 6 | + <enum name="circle" value="0" /> | |
| 7 | + <enum name="round" value="1" /> | |
| 8 | + <enum name="multi" value="3" /> | |
| 9 | + </attr> | |
| 10 | + <attr name="angleCount" format="integer" /> | |
| 11 | + <attr name="currentAngle" format="integer" /> | |
| 12 | + </declare-styleable> | |
| 13 | + | |
| 14 | +</resources> | |
| 0 | 15 | \ No newline at end of file | ... | ... |
core/imageload/src/test/java/com/mm999/imageload/ExampleUnitTest.java
0 → 100644
| 1 | +package com.mm999.imageload; | |
| 2 | + | |
| 3 | +import org.junit.Test; | |
| 4 | + | |
| 5 | +import static org.junit.Assert.*; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Example local unit test, which will execute on the development machine (host). | |
| 9 | + * | |
| 10 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| 11 | + */ | |
| 12 | +public class ExampleUnitTest { | |
| 13 | + @Test | |
| 14 | + public void addition_isCorrect() { | |
| 15 | + assertEquals(4, 2 + 2); | |
| 16 | + } | |
| 17 | +} | |
| 0 | 18 | \ No newline at end of file | ... | ... |