Commit eb844dc5 by 郑鹏

把Glide修改成本地

parent 2eafb4a9
//apply plugin: 'com.android.application'
/*apply plugin: 'com.android.application'*/
apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'kotlin-android'
......@@ -16,7 +16,7 @@ android {
compileSdkVersion 30
defaultConfig {
/* multiDexEnabled true
/* multiDexEnabled true
applicationId "com.mhq.smartorder"*/
minSdkVersion 26
......@@ -55,21 +55,21 @@ android {
}
*/
signingConfigs {
/* signingConfigs {
def appStoreFilePath = System.getProperty('StoreFilePath')
def appStorePassword = System.getProperty('StorePassword')
def appKeyAlias = System.getProperty('KeyAlias')
def appKeyPassword = System.getProperty('KeyPassword')
/* Properties properties = new Properties()
Properties properties = new Properties()
if (rootProject.file("local.properties").exists()) {
properties.load(rootProject.file("local.properties").newDataInputStream())
storeFilePath= properties.get("STOREFILE")
storePassword= properties.get("STOREPASSWORD")
keyAlias= properties.get("KEYALIAS")
keyPassword= properties.get("KEYPASSWORD")
}*/
}
if (!appStoreFilePath || !appStorePassword || !appKeyAlias || !appKeyPassword) {
//将.android下的debug.keystore放到app目录下
......@@ -88,9 +88,9 @@ android {
v2SigningEnabled true
}
}
}*/
buildTypes {
/* buildTypes {
debug {
// buildConfigField 'String','NAME','value'
zipAlignEnabled true
......@@ -113,7 +113,7 @@ android {
signingConfig signingConfigs.jenkins
}
}
}*/
sourceSets.main {
jniLibs.srcDirs = ['libs']
java.srcDirs += 'src/support/java'
......@@ -127,8 +127,8 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
//DomainObjectCollection集合
/* applicationVariants.all { variant ->
/* //DomainObjectCollection集合
applicationVariants.all { variant ->
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')
&& 'release'.equals(variant.buildType.name)) {
......@@ -145,7 +145,6 @@ android {
}
}*/
}
def buildTime() {
def date = new Date();
def formattedDate = date.format("yyyyMMdd");
......@@ -211,9 +210,13 @@ dependencies {
api 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
api 'com.yanzhenjie:permission:2.0.0-rc12'
api 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'
api 'com.github.bumptech.glide:glide:4.7.1'
api 'com.github.bumptech.glide:okhttp3-integration:4.7.1'
//api 'com.github.bumptech.glide:glide:4.7.1'
// api 'com.github.bumptech.glide:okhttp3-integration:4.7.1'
/* annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
kapt 'com.github.bumptech.glide:compiler:4.7.1'*/
api 'com.github.chrisbanes.photoview:library:1.2.4'
//api 'com.jakewharton:butterknife:8.4.0'
api 'com.alibaba:arouter-api:1.3.1'
api "com.alibaba:fastjson:1.1.67.android"
......@@ -221,14 +224,14 @@ dependencies {
api 'com.squareup.retrofit2:retrofit:2.3.0'
api 'com.facebook.stetho:stetho:1.5.0'
api "com.facebook.stetho:stetho-okhttp3:1.5.0"
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
//annotationProcessor deps.butterknife.butterknife_compiler
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
kapt 'com.github.bumptech.glide:compiler:4.7.1'
//kapt deps.butterknife.butterknife_compiler
kapt 'com.alibaba:arouter-compiler:1.1.4'
api 'com.qq.mta:mta:3.4.7-release'
api 'com.tencent.mid:mid:4.06-release'
/* api 'com.qq.mta:mta:3.4.7-release'
api 'com.tencent.mid:mid:4.06-release'*/
// api project(':component-easeui')
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
implementation 'org.aspectj:aspectjrt:1.8.9'
......@@ -245,16 +248,16 @@ dependencies {
api 'com.github.anzaizai:EasySwipeMenuLayout:1.1.4'
api 'org.greenrobot:eventbus:3.1.1'
//api 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-25'
api 'com.google.android.gms:play-services-wallet:16.0.1'
//api 'com.google.android.gms:play-services-wallet:16.0.1'
api 'com.tencent.qcloud:cosxml:5.4.25'
api 'com.sunfusheng:marqueeview:1.3.3'
api 'com.google.firebase:firebase-core:16.0.8'
api 'com.google.firebase:firebase-messaging:17.6.0'
api 'com.tencent.bugly:crashreport:latest.release'
api 'com.tencent.bugly:nativecrashreport:latest.release'
/* api 'com.google.firebase:firebase-core:16.0.8'
api 'com.google.firebase:firebase-messaging:17.6.0'*/
/* api 'com.tencent.bugly:crashreport:latest.release'
api 'com.tencent.bugly:nativecrashreport:latest.release'*/
//MTA主包
api 'com.qq.mta:mta:3.4.7-Release'
api 'com.tencent.mid:mid:4.06-Release'
/* api 'com.qq.mta:mta:3.4.7-Release'
api 'com.tencent.mid:mid:4.06-Release'*/
api 'com.github.liys666666:DoubleClick:V2.0.4'
api 'com.readystatesoftware.chuck:library:1.1.0'
......
{
"project_info": {
"project_number": "636998814874",
"firebase_url": "https://smartorder-7e6e7.firebaseio.com",
"project_id": "smartorder-7e6e7",
"storage_bucket": "smartorder-7e6e7.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:636998814874:android:f8d6327180b9267d",
"android_client_info": {
"package_name": "com.mhq.smartorder"
}
},
"oauth_client": [
{
"client_id": "636998814874-i8lu56hg21pee1qvvnqrikj37pdprqp2.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDwJv9yhHjoVEczxUngI33HgYtyi5ZtrXA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "636998814874-i8lu56hg21pee1qvvnqrikj37pdprqp2.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
......@@ -337,12 +337,15 @@ public void xxxxxx(**);
#glide 4.x
#由* chenyongta*贡献混淆代码
#作者Github地址:https://github.com/yourtion
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
-keep public class * implements com.sdk.glide.module.GlideModule
-keep public class * extends com.sdk.glide.module.AppGlideModule
-keep public enum com.sdk.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.sdk.glide.GeneratedAppGlideModuleImpl {
*;
}
# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
......
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API key.
To get one, follow this link, follow the directions and press "Create" at the end:
https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&r=50:E6:E4:3A:D5:D7:C6:9B:BC:1E:28:F7:89:0B:9F:D7:3D:F5:97:D8%3Bcn.dankal.templates.ui.home.map
You can also add your credentials to an existing key, using these values:
Package name:
50:E6:E4:3A:D5:D7:C6:9B:BC:1E:28:F7:89:0B:9F:D7:3D:F5:97:D8
SHA-1 certificate fingerprint:
50:E6:E4:3A:D5:D7:C6:9B:BC:1E:28:F7:89:0B:9F:D7:3D:F5:97:D8
Alternatively, follow the directions here:
https://developers.google.com/maps/documentation/android/start#get-key
Once you have your key (it starts with "AIza"), replace the "google_maps_key"
string in this file.
-->
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">AIzaSyDwJv9yhHjoVEczxUngI33HgYtyi5ZtrXA</string>
</resources>
......@@ -293,25 +293,25 @@
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>--> <!-- [END firebase_service] -->
<service
<!-- <service
android:name=".ui.service.MyJobService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
</service>-->
<activity android:name="cn.dankal.basiclib.base.activity.BaseListActivity"></activity>
<activity
android:name="cn.dankal.basiclib.base.activity.BigPhotoActivity"
android:screenOrientation="portrait" />
<meta-data
<!-- <meta-data
android:name="firebase_messaging_auto_init_enabled"
android:value="false" />
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="false" />
android:value="false" />-->
<activity
android:name="com.yzq.zxinglibrary.android.CaptureActivity"
......
......@@ -2,16 +2,16 @@ package cn.dankal.basiclib;
import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.cache.ExternalPreferredCacheDiskCacheFactory;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.GlideBuilder;
import com.sdk.glide.Registry;
import com.sdk.glide.annotation.GlideModule;
import com.sdk.glide.integration.okhttp3.OkHttpUrlLoader;
import com.sdk.glide.load.DecodeFormat;
import com.sdk.glide.load.engine.cache.ExternalPreferredCacheDiskCacheFactory;
import com.sdk.glide.load.model.GlideUrl;
import com.sdk.glide.module.AppGlideModule;
import com.sdk.glide.request.RequestOptions;
import java.io.InputStream;
......
package cn.dankal.basiclib;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import com.sdk.glide.Glide;
import com.sdk.glide.GlideBuilder;
import com.sdk.glide.RequestManager;
import java.io.File;
import java.lang.Deprecated;
import java.lang.String;
/**
* The entry point for interacting with Glide for Applications
*
* <p>Includes all generated APIs from all
* {@link com.sdk.glide.annotation.GlideExtension}s in source and dependent libraries.
*
* <p>This class is generated and should not be modified
* @see Glide
*/
public final class GlideApp {
private GlideApp() {
}
/**
* @see Glide#getPhotoCacheDir(Context)
*/
@Nullable
public static File getPhotoCacheDir(@NonNull Context context) {
return Glide.getPhotoCacheDir(context);
}
/**
* @see Glide#getPhotoCacheDir(Context, String)
*/
@Nullable
public static File getPhotoCacheDir(@NonNull Context context, @NonNull String string) {
return Glide.getPhotoCacheDir(context, string);
}
/**
* @see Glide#get(Context)
*/
@NonNull
public static Glide get(@NonNull Context context) {
return Glide.get(context);
}
/**
* @see Glide#init(Glide)
*/
@Deprecated
@VisibleForTesting
@SuppressLint("VisibleForTests")
public static void init(Glide glide) {
Glide.init(glide);
}
/**
* @see Glide#init(Context, GlideBuilder)
*/
@VisibleForTesting
@SuppressLint("VisibleForTests")
public static void init(@NonNull Context context, @NonNull GlideBuilder builder) {
Glide.init(context, builder);
}
/**
* @see Glide#tearDown()
*/
@VisibleForTesting
@SuppressLint("VisibleForTests")
public static void tearDown() {
Glide.tearDown();
}
/**
* @see Glide#with(Context)
*/
@NonNull
public static RequestManager with(@NonNull Context context) {
return (RequestManager) Glide.with(context);
}
/**
* @see Glide#with(Activity)
*/
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return (RequestManager) Glide.with(activity);
}
/**
* @see Glide#with(FragmentActivity)
*/
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return (RequestManager) Glide.with(activity);
}
/**
* @see Glide#with(Fragment)
*/
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return (RequestManager) Glide.with(fragment);
}
/**
* @see Glide#with(Fragment)
*/
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return (RequestManager) Glide.with(fragment);
}
/**
* @see Glide#with(View)
*/
@NonNull
public static RequestManager with(@NonNull View view) {
return (RequestManager) Glide.with(view);
}
}
package cn.dankal.basiclib;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.CheckResult;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RawRes;
import com.sdk.glide.Glide;
import com.sdk.glide.RequestManager;
import com.sdk.glide.load.resource.gif.GifDrawable;
import com.sdk.glide.manager.Lifecycle;
import com.sdk.glide.manager.RequestManagerTreeNode;
import com.sdk.glide.request.RequestOptions;
import java.io.File;
import java.net.URL;
/**
* Includes all additions from methods in {@link com.sdk.glide.annotation.GlideExtension}s
* annotated with {@link com.sdk.glide.annotation.GlideType}
*
* <p>Generated code, do not modify
*/
@SuppressWarnings("deprecation")
public class GlideRequests extends RequestManager {
public GlideRequests(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
super(glide, lifecycle, treeNode, context);
}
@Override
@CheckResult
@NonNull
public <ResourceType> GlideRequest<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
return new GlideRequest<>(glide, this, resourceClass, context);
}
@Override
@NonNull
public GlideRequests applyDefaultRequestOptions(@NonNull RequestOptions options) {
return (GlideRequests) super.applyDefaultRequestOptions(options);
}
@Override
@NonNull
public GlideRequests setDefaultRequestOptions(@NonNull RequestOptions options) {
return (GlideRequests) super.setDefaultRequestOptions(options);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Bitmap> asBitmap() {
return (GlideRequest<Bitmap>) super.asBitmap();
}
@Override
@NonNull
@CheckResult
public GlideRequest<GifDrawable> asGif() {
return (GlideRequest<GifDrawable>) super.asGif();
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> asDrawable() {
return (GlideRequest<Drawable>) super.asDrawable();
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable Bitmap bitmap) {
return (GlideRequest<Drawable>) super.load(bitmap);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable Drawable drawable) {
return (GlideRequest<Drawable>) super.load(drawable);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable String string) {
return (GlideRequest<Drawable>) super.load(string);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable Uri uri) {
return (GlideRequest<Drawable>) super.load(uri);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable File file) {
return (GlideRequest<Drawable>) super.load(file);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@RawRes @DrawableRes @Nullable Integer id) {
return (GlideRequest<Drawable>) super.load(id);
}
@Override
@Deprecated
@CheckResult
public GlideRequest<Drawable> load(@Nullable URL url) {
return (GlideRequest<Drawable>) super.load(url);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable byte[] bytes) {
return (GlideRequest<Drawable>) super.load(bytes);
}
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable Object o) {
return (GlideRequest<Drawable>) super.load(o);
}
@Override
@NonNull
@CheckResult
public GlideRequest<File> downloadOnly() {
return (GlideRequest<File>) super.downloadOnly();
}
@Override
@NonNull
@CheckResult
public GlideRequest<File> download(@Nullable Object o) {
return (GlideRequest<File>) super.download(o);
}
@Override
@NonNull
@CheckResult
public GlideRequest<File> asFile() {
return (GlideRequest<File>) super.asFile();
}
@Override
protected void setRequestOptions(@NonNull RequestOptions toSet) {
if (toSet instanceof GlideOptions) {
super.setRequestOptions(toSet);
} else {
super.setRequestOptions(new GlideOptions().apply(toSet));
}
}
}
......@@ -10,11 +10,8 @@ import com.alibaba.android.arouter.launcher.ARouter;
import com.facebook.stetho.Stetho;
import com.liys.doubleclicklibrary.helper.ViewDoubleHelper;
import com.mhq.smartorder.wxapi.WxConstants;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.stat.StatConfig;
import com.tencent.stat.StatService;
import org.litepal.LitePal;
......@@ -26,6 +23,7 @@ import cn.dankal.basiclib.util.StringUtil;
import cn.dankal.basiclib.util.language.LanguageLocalListener;
import cn.dankal.basiclib.util.language.LocalManageUtil;
import cn.dankal.basiclib.util.language.MultiLanguage;
import cn.dankal.basiclib.util.language.SPUtil;
import cn.dankal.basiclib.widget.loadsir.EmptyCallback;
import cn.dankal.basiclib.widget.loadsir.LoadingCallback;
import cn.dankal.basiclib.widget.loadsir.RetryCallback;
......@@ -58,7 +56,7 @@ public class ModooApplication extends Application {
LitePal.initialize(this);
//bugly
CrashReport.initCrashReport(getApplicationContext(), "74a2fc949e", isDev);
//CrashReport.initCrashReport(getApplicationContext(), "74a2fc949e", isDev);
/* String language = (String) SPUtils.get(Constant.EVENT_REFRESH_LANGUAGE, "");
......@@ -66,30 +64,45 @@ public class ModooApplication extends Application {
language = Locale.getDefault().getLanguage();
}
LanguageUtil.setApplicationLanguage(this,language);*/
MultiLanguage.init(new LanguageLocalListener() {
/* MultiLanguage.init(new LanguageLocalListener() {
@Override
public Locale getSetLanguageLocale(Context context) {
//선택 한 언어 설정 을 로 컬 로 되 돌려 줍 니 다.
return LocalManageUtil.getSetLanguageLocale(context);
}
});
MultiLanguage.setApplicationLanguage(this);
MultiLanguage.setApplicationLanguage(this);*/
// [선택 가능] debug 출력 여 부 를 설정 합 니 다. 로그 인 할 때 닫 으 십시오. Logcat 레이 블 은 "MTasDK" 입 니 다.
StatConfig.setDebugEnable(isDev);
//StatConfig.setDebugEnable(isDev);
// 기초 통계 API
StatService.registerActivityLifecycleCallbacks(this);
// StatService.registerActivityLifecycleCallbacks(this);
String appkey = "AIAF8SC17A3L";
// MTA 초기 화 및 시작
try {
StatService.startStatService(this, appkey,
com.tencent.stat.common.StatConstants.VERSION);
/* StatService.startStatService(this, appkey,
com.tencent.stat.common.StatConstants.VERSION);*/
} catch (Exception e) {
}
//처리 버튼 여러 번 클릭 방지, 기본 1s,https://www.jianshu.com/p/7f3e5c8b8643
ViewDoubleHelper.init(this);
Locale locale = context.getResources().getConfiguration().locale;
String language = locale.getLanguage();
if ("en".equals(language)){
SPUtil.getInstance(ModooApplication.getContext()).saveLanguage(2);
}else if ("ja".equals(language)){
SPUtil.getInstance(ModooApplication.getContext()).saveLanguage(3);
}else if ("ko".equals(language)){
SPUtil.getInstance(ModooApplication.getContext()).saveLanguage(1);
}else if ("zh".equals(language)){
SPUtil.getInstance(ModooApplication.getContext()).saveLanguage(0);
}
}
/**
......@@ -128,7 +141,7 @@ public class ModooApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
LocalManageUtil.saveSystemCurrentLanguage(base);
//LocalManageUtil.saveSystemCurrentLanguage(base);
MultiDex.install(MultiLanguage.setLocal(base));
}
......@@ -162,8 +175,8 @@ public class ModooApplication extends Application {
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//사용자 가 시스템 설정 페이지 전환 언어 를 설정 할 때 시스템 선택 언어 를 저장 합 니 다 (시스템 언어 를 선택 할 때 사용 합 니 다. 저장 하지 않 으 면 언어 전환 후 사용 할 수 없습니다)
LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig);
MultiLanguage.onConfigurationChanged(getApplicationContext());
/* LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig);
MultiLanguage.onConfigurationChanged(getApplicationContext());*/
}
/**
......
......@@ -25,7 +25,8 @@ public class BaseApi {
/*public static final String BASE_URL = isDev ? "https://api-koreadc.dankal.cn/v1/"
: "https://modoo-api.mhqglobal.com/v1/";*/
public static final String BASE_URL = "https://api-koreadc.dankal.cn/v1/";
//public static final String BASE_URL = "https://api-koreadc.dankal.cn/v1/";
public static final String BASE_URL = "https://modoo-api.mhqglobal.com/v1/";
public static final String BASE_EXPRESS_URL = "https://info.sweettracker.co.kr/";
......
......@@ -3,6 +3,7 @@ package cn.dankal.basiclib.api;
import java.util.Map;
import cn.dankal.entities.car.PayParameterEntity;
import cn.dankal.entities.car.PayTestEntity;
import cn.dankal.entities.car.ShopCarEntity;
import cn.dankal.entities.home.BusinessTimeEntity;
import cn.dankal.entities.home.CommitHotelEntity;
......@@ -95,6 +96,7 @@ public interface RestaurantService {
/**
* 사용자가 지정한 매장에서 예약대기 여부
*
*
* @return
*/
@GET("app/hotel/is_user_queue/{hotelUuid}")
......@@ -122,7 +124,7 @@ public interface RestaurantService {
* @return
*/
@POST("app/hotel/user_pay")
Observable<PayParameterEntity> userPay(@Body Map<String, Object> map);
Observable<PayTestEntity> userPay(@Body Map<String, Object> map);
/**
* 사용자 클릭하여 구매하기
......
......@@ -4,6 +4,7 @@ import java.util.Map;
import cn.dankal.basiclib.rx.RefreshTokenHelper;
import cn.dankal.entities.car.PayParameterEntity;
import cn.dankal.entities.car.PayTestEntity;
import cn.dankal.entities.car.ShopCarEntity;
import cn.dankal.entities.home.BusinessTimeEntity;
import cn.dankal.entities.home.CommitHotelEntity;
......@@ -168,8 +169,8 @@ public final class RestaurantServiceFactory {
.unsubscribeOn(Schedulers.io());
}
public static Observable<PayParameterEntity> userPay(Map<String, Object> map) {
Observable<PayParameterEntity> observable =
public static Observable<PayTestEntity> userPay(Map<String, Object> map) {
Observable<PayTestEntity> observable =
BaseApi.getRetrofit()
.create(RestaurantService.class)
.userPay(map);
......
......@@ -11,8 +11,8 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.request.RequestOptions;
import cn.dankal.basiclib.util.TitleBarUtils;
......
......@@ -240,17 +240,19 @@ public class ToastUtils {
Activity activity = ActivityManager.getInstance().getLastActivity();
sToast = Toast.makeText((activity==null)?AppUtils.getApp():activity, null, duration);
sToast.setText(text);
final TextView tvMessage = sToast.getView().findViewById(android.R.id.message);
if (sMsgColor != COLOR_DEFAULT) {
tvMessage.setTextColor(sMsgColor);
if (sToast.getView()!=null){
final TextView tvMessage = sToast.getView().findViewById(android.R.id.message);
if (sMsgColor != COLOR_DEFAULT) {
tvMessage.setTextColor(sMsgColor);
}
if (sMsgTextSize != -1) {
tvMessage.setTextSize(sMsgTextSize);
}
if (sGravity != -1 || sXOffset != -1 || sYOffset != -1) {
sToast.setGravity(sGravity, sXOffset, sYOffset);
}
setBg(tvMessage);
}
if (sMsgTextSize != -1) {
tvMessage.setTextSize(sMsgTextSize);
}
if (sGravity != -1 || sXOffset != -1 || sYOffset != -1) {
sToast.setGravity(sGravity, sXOffset, sYOffset);
}
setBg(tvMessage);
showToast();
}
});
......
......@@ -8,8 +8,8 @@ import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.sdk.glide.load.engine.bitmap_recycle.BitmapPool;
import com.sdk.glide.load.resource.bitmap.BitmapTransformation;
import java.security.MessageDigest;
......
......@@ -9,11 +9,13 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.widget.ImageView;
import com.sdk.glide.RequestBuilder;
import com.sdk.glide.RequestManager;
import java.io.File;
import cn.dankal.basiclib.ModooApplication;
import cn.dankal.basiclib.GlideApp;
import cn.dankal.basiclib.GlideRequest;
import cn.dankal.client.R;
/**
......@@ -155,7 +157,7 @@ public class PicUtils {
transform.init();
}
GlideRequest<Drawable> request;
RequestBuilder<Drawable> request;
if (o instanceof Uri) {
request = GlideApp.with(context)
......@@ -174,9 +176,9 @@ public class PicUtils {
.load(o);
}
if (placeHolder != 0) request = request.placeholder(placeHolder);
/* if (placeHolder != 0) request = request.placeholder(placeHolder);
if (errorHolder != 0) request = request.error(errorHolder);
if (type != -1) request = request.transform(transform);
if (type != -1) request = request.transform(transform);*/
request.into(iv);
}
......
......@@ -27,7 +27,7 @@ public class GradeStarView extends LinearLayout {
private int mMargin = 5; //图片之间默认的margin
private int mStarNum = 5; //星星默认的个数
private int mStarChoose = 0; //默认选中三颗星
private boolean isClick = true;
private boolean isClick = false;
private OnStarItemClickListener mStarItemClickListener;
......@@ -129,11 +129,11 @@ public class GradeStarView extends LinearLayout {
* @param i
*/
private void setStarOnClick(final ImageView imageView, final int i) {
if (isClick) {
if (imageView != null) {
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (imageView != null) {
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (isClick) {
resetDefaultImage();
mStarChoose = i + 1;
setCurrentChoose(i + 1);
......@@ -141,8 +141,8 @@ public class GradeStarView extends LinearLayout {
mStarItemClickListener.onItemClick(imageView, i);
}
}
});
}
}
});
}
}
......
......@@ -37,7 +37,6 @@ import cn.dankal.client.ui.shop.ShopFragment
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.iid.FirebaseInstanceId
import com.google.gson.Gson
import com.yanzhenjie.permission.Permission
import com.yzq.zxinglibrary.common.Constant
......@@ -315,7 +314,7 @@ class MainActivity : BaseActivity(), OnMapReadyCallback {
}
private fun uploadFireBaseToken() {
FirebaseInstanceId.getInstance().instanceId
/* FirebaseInstanceId.getInstance().instanceId
.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w("FirebaseInstanceId", "getInstanceId failed", task.getException());
......@@ -335,7 +334,7 @@ class MainActivity : BaseActivity(), OnMapReadyCallback {
override fun onNext(t: ResponseBody) {
}
})
})
})*/
}
}
......@@ -4,9 +4,6 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
......
......@@ -12,6 +12,7 @@ import cn.dankal.client.adapter.shop.CommentImageAdapter
import cn.dankal.entities.home.EvaluateListEntity
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import kotlinx.android.synthetic.main.activity_food_all_evaluate.*
/**
* Author: roczheng
......@@ -28,6 +29,7 @@ class FoodAllEvaluateAdapter(layoutResId: Int, data: List<EvaluateListEntity.Dat
val starView = holder?.getView<GradeStarView>(R.id.sv_store_star)
starView?.setCurrentChoose(item.star_level)
starView?.isClick(false)
val recyclerView = holder?.getView<RecyclerView>(R.id.rv_list_image)
if (img_list_temp != null && img_list_temp.size > 0) {
recyclerView?.visibility = View.VISIBLE
......
......@@ -12,9 +12,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.request.RequestOptions;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
......
......@@ -12,9 +12,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.request.RequestOptions;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
......
......@@ -35,6 +35,7 @@ class FoodAllEvaluateActivity : BaseActivity(), OnRefreshLoadMoreListener, View.
val currentIndex = mStarLevel.toInt()
sv_store_star.setCurrentChoose(currentIndex)
sv_store_star.isClick(false)
tv_grade.text = mStarLevel.toString()
mParams.put("create_time_sort", "desc")
......
......@@ -399,6 +399,7 @@ public class MerchantDetailsActivity extends BaseActivity {
int currentIndex = (int) (entity.getStar_level());
svStoreStar.setCurrentChoose(currentIndex);
svStoreStar.isClick(false);
tvGrade.setText(String.valueOf(entity.getStar_level()));
......
......@@ -24,6 +24,7 @@ import cn.dankal.entities.shop.PlayStatusEntity
import cn.dankal.entities.shop.QueueEntity
import cn.dankal.client.ui.home.ScanResultActivity
import cn.dankal.client.util.UIUtile
import cn.dankal.entities.car.PayTestEntity
import cn.dankal.entities.event.ShopCarRefreshEvent
import com.google.gson.Gson
import com.yzq.zxinglibrary.android.CaptureActivity
......@@ -98,8 +99,8 @@ class OrderResultActivity : BaseActivity(), View.OnClickListener {
}
private fun callPayment() {
RestaurantServiceFactory.userPay(map).subscribe(object : AbstractDialogSubscriber<PayParameterEntity>(this) {
override fun onNext(t: PayParameterEntity) {
RestaurantServiceFactory.userPay(map).subscribe(object : AbstractDialogSubscriber<PayTestEntity>(this) {
override fun onNext(t: PayTestEntity) {
/*t.apply {
orderId = order_uuid
stampNumber = stamp_number
......@@ -120,7 +121,7 @@ class OrderResultActivity : BaseActivity(), View.OnClickListener {
}
EventBus.getDefault().post(ShopCarRefreshEvent())
}
orderId=t.order_uuid
ToastUtils.showShort(getString(R.string.successful_payment))
val intent = Intent(this@OrderResultActivity, ResultPageActivity::class.java)
var bundle = Bundle()
......@@ -137,7 +138,7 @@ class OrderResultActivity : BaseActivity(), View.OnClickListener {
private fun stampPayment() {
RestaurantServiceFactory.userPay(map).subscribe(object : AbstractDialogSubscriber<PayParameterEntity>(this) {
/* RestaurantServiceFactory.userPay(map).subscribe(object : AbstractDialogSubscriber<PayParameterEntity>(this) {
override fun onNext(t: PayParameterEntity) {
t.apply {
orderId = order_uuid
......@@ -153,7 +154,7 @@ class OrderResultActivity : BaseActivity(), View.OnClickListener {
finish()
}
}
})
})*/
}
......
......@@ -23,10 +23,10 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.sdk.glide.Glide;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.SimpleTarget;
import com.sdk.glide.request.transition.Transition;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
......
......@@ -21,9 +21,9 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.RequestBuilder;
import com.sdk.glide.request.RequestOptions;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
......
......@@ -23,10 +23,10 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.sdk.glide.Glide;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.SimpleTarget;
import com.sdk.glide.request.transition.Transition;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
......
......@@ -19,7 +19,7 @@ import cn.dankal.entities.event.PersonUpdateEvent
import cn.dankal.entities.user.UserInfoEntity
import cn.dankal.client.R
import com.alibaba.android.arouter.launcher.ARouter
import com.bumptech.glide.request.target.BitmapImageViewTarget
import com.sdk.glide.request.target.BitmapImageViewTarget
import com.luck.picture.lib.PictureSelector
import com.luck.picture.lib.config.PictureConfig
import com.luck.picture.lib.config.PictureMimeType
......@@ -196,13 +196,13 @@ class PersonalInfoActivity : BaseActivity(), View.OnClickListener {
if (path == "") {
return
}
GlideApp.with(ModooApplication.getContext()).asBitmap().centerCrop().error(R.mipmap.pic_my_home_head).load(path).into(object : BitmapImageViewTarget(iv_personal_user_head) {
/* GlideApp.with(ModooApplication.getContext()).asBitmap().centerCrop().error(R.mipmap.pic_my_home_head).load(path).into(object : BitmapImageViewTarget(iv_personal_user_head) {
override fun setResource(resource: Bitmap?) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, resource)
circularBitmapDrawable.isCircular = true
iv_personal_user_head.setImageDrawable(circularBitmapDrawable)
}
})
})*/
showLoadingDialog()
val listPath = listOf<String>(path)
......
package cn.dankal.client.ui.service;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import cn.dankal.basiclib.api.UserServiceFactory;
import cn.dankal.basiclib.rx.AbstractDialogSubscriber;
import cn.dankal.client.MainActivity;
import cn.dankal.client.R;
import cn.dankal.client.constants.ConstantsRestaurantType;
import cn.dankal.client.ui.home.HomeActivity;
import cn.dankal.client.ui.home.details.MerchantDetailsActivity;
import cn.dankal.client.ui.personal.order.food.OrderDetailsActivity;
import cn.dankal.client.ui.personal.order.mall.MallOrderDetailsActivity;
import okhttp3.ResponseBody;
/**
* Created by zhengpeng on 2019/6/18.
*/
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
remoteMessage.getNotification().getTag();
remoteMessage.getNotification().getClickAction();
sendNotification(remoteMessage.getNotification());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]
/**
* Schedule a job using FirebaseJobDispatcher.
*/
private void scheduleJob() {
/* // [START dispatch_job]
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
Job myJob = dispatcher.newJobBuilder()
.setService(MyJobService.class)
.setTag("my-job-tag")
.build();
dispatcher.schedule(myJob);*/
// [END dispatch_job]
}
@Override
public void onNewToken(String s) {
super.onNewToken(s);
//上传到服务器
Map map = new HashMap<String, Object>();
map.put("fcm_token", s);
map.put("type", 0);
UserServiceFactory.fcmToken(map).subscribe(new AbstractDialogSubscriber<ResponseBody>(null) {
@Override
public void onNext(ResponseBody responseBody) {
}
});
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Create and show a simple notification containing the received FCM message.
*/
private void sendNotification(RemoteMessage.Notification notification) {
String jsonData;
if (notification != null) {
jsonData = notification.getClickAction();
} else {
jsonData = "";
}
try {
JSONObject jsonObject = new JSONObject(jsonData);
Intent intent = null;
switch (notification.getTag()) {
case "userHotelDetails"://打开指定餐馆详情
String hotelUUID = jsonObject.getString("hotelUuid");
intent = new Intent(this, MerchantDetailsActivity.class).putExtra(MerchantDetailsActivity.HOTELUUID, hotelUUID);
break;
case "userStoreOrderDetails"://打开指定商城订单详情:
String orderStoreUuid = jsonObject.getString("orderUuid");
intent = new Intent(this, OrderDetailsActivity.class).putExtra(ConstantsRestaurantType.UUID, orderStoreUuid);
break;
case "userHotelOrderDetails":
String orderHotelUuid = jsonObject.getString("orderUuid");
intent = new Intent(this, MallOrderDetailsActivity.class).putExtra(ConstantsRestaurantType.UUID, orderHotelUuid);
break;
default:
intent = new Intent(this, HomeActivity.class);
break;
}
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(notification.getTitle())
.setContentText(notification.getBody())
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
package cn.dankal.client.ui.service;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;
/**
* Created by zhengpeng on 2019/6/18.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
private static final String TAG = "MyJobService";
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, "Performing long running task in scheduled job");
// TODO(developer): add long running task here.
return false;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
}
package cn.dankal.entities.car;
/**
* Author: roczheng
* Date: 2021/3/5
* Time: 21:20
* Description:
*/
public class PayTestEntity {
private String order_uuid;
private String order_code;
public String getOrder_uuid() {
return order_uuid;
}
public void setOrder_uuid(String order_uuid) {
this.order_uuid = order_uuid;
}
public String getOrder_code() {
return order_code;
}
public void setOrder_code(String order_code) {
this.order_code = order_code;
}
}
......@@ -17,7 +17,6 @@ import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.iid.FirebaseInstanceId
import kotlinx.android.synthetic.main.activity_find_email_tow.*
import okhttp3.ResponseBody
......@@ -79,7 +78,7 @@ class FindEmailTowActivity : BaseActivity() {
}
private fun uploadFireBaseToken() {
FirebaseInstanceId.getInstance().instanceId
/* FirebaseInstanceId.getInstance().instanceId
.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
return@OnCompleteListener
......@@ -96,6 +95,6 @@ class FindEmailTowActivity : BaseActivity() {
override fun onNext(t: ResponseBody) {
}
})
})
})*/
}
}
......@@ -5,7 +5,7 @@ import cn.dankal.client.R
class LockStateActivity : BaseActivity() {
override fun initComponents() {
addSingleTitleBar(getString(R.string.login))
addSingleTitleBar(getString(R.string.login_sdk))
}
override fun getLayoutId(): Int {
......
......@@ -25,7 +25,6 @@ import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import kotlinx.android.synthetic.main.activity_login_sdk.*
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.iid.FirebaseInstanceId
import com.mhq.smartorder.wxapi.WXEntryActivity
import cn.dankal.basiclib.util.rx.RxPermissions
import com.tencent.mm.opensdk.modelmsg.SendAuth
......@@ -58,7 +57,7 @@ class LoginActivity : BaseActivity() {
private var mRxPermissions: RxPermissions? = null
override fun initComponents() {
addSingleTitleBar(getString(R.string.login))
addSingleTitleBar(getString(R.string.login_sdk))
mRxPermissions = RxPermissions(this)
......@@ -220,7 +219,7 @@ class LoginActivity : BaseActivity() {
}
private fun uploadFireBaseToken() {
FirebaseInstanceId.getInstance().instanceId
/* FirebaseInstanceId.getInstance().instanceId
.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w("FirebaseInstanceId", "getInstanceId failed", task.getException());
......@@ -244,7 +243,7 @@ class LoginActivity : BaseActivity() {
override fun onNext(t: ResponseBody) {
}
})
})
})*/
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
......
......@@ -17,17 +17,17 @@ import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.sdk.glide.Glide;
import com.sdk.glide.Priority;
import com.sdk.glide.load.DataSource;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.load.engine.GlideException;
import com.sdk.glide.load.resource.gif.GifDrawable;
import com.sdk.glide.request.RequestListener;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.SimpleTarget;
import com.sdk.glide.request.target.Target;
import com.sdk.glide.request.transition.Transition;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.dialog.CustomDialog;
......
......@@ -243,7 +243,7 @@ public class PictureSelectionModel {
/**
* @param sizeMultiplier The multiplier to apply to the
* {@link com.bumptech.glide.request.target.Target}'s dimensions when
* {@link com.sdk.glide.request.target.Target}'s dimensions when
* loading the resource.
* @return
*/
......
......@@ -11,10 +11,10 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import com.sdk.glide.Glide;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.BitmapImageViewTarget;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.entity.LocalMediaFolder;
......
......@@ -16,9 +16,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.sdk.glide.Glide;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.request.RequestOptions;
import com.luck.picture.lib.anim.OptAnimationLoader;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
......
......@@ -11,12 +11,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.sdk.glide.Glide;
import com.sdk.glide.Priority;
import com.sdk.glide.load.engine.DiskCacheStrategy;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.SimpleTarget;
import com.sdk.glide.request.transition.Transition;
import com.luck.picture.lib.PictureVideoPlayActivity;
import cn.dankal.client.R;
import com.luck.picture.lib.config.PictureConfig;
......
package com.sdk.glide;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sdk.glide.manager.RequestManagerRetriever;
import com.sdk.glide.module.AppGlideModule;
import java.util.Set;
/**
* Allows {@link AppGlideModule}s to exclude {@link com.sdk.glide.annotation.GlideModule}s to
* ease the migration from {@link com.sdk.glide.annotation.GlideModule}s to Glide's annotation
* processing system and optionally provides a
* {@link com.sdk.glide.manager.RequestManagerRetriever.RequestManagerFactory} impl.
*/
abstract class GeneratedAppGlideModule extends AppGlideModule {
/**
* This method can be removed when manifest parsing is no longer supported.
*/
@NonNull
abstract Set<Class<?>> getExcludedModuleClasses();
@Nullable
RequestManagerRetriever.RequestManagerFactory getRequestManagerFactory() {
return null;
}
}
package com.sdk.glide;
import android.support.annotation.NonNull;
import com.sdk.glide.request.transition.TransitionFactory;
import com.sdk.glide.request.transition.ViewPropertyTransition;
/**
* Implementation of {@link TransitionOptions} that exposes only generic methods that can be applied
* to any resource type.
*
* @param <TranscodeType> The type of the resource that will be displayed.
*/
// Public API.
@SuppressWarnings({"PMD.UseUtilityClass", "unused"})
public final class GenericTransitionOptions<TranscodeType> extends
TransitionOptions<GenericTransitionOptions<TranscodeType>, TranscodeType> {
/**
* Removes any existing animation put on the builder.
*
* @see GenericTransitionOptions#dontTransition()
*/
@NonNull
public static <TranscodeType> GenericTransitionOptions<TranscodeType> withNoTransition() {
return new GenericTransitionOptions<TranscodeType>().dontTransition();
}
/**
* Returns a typed {@link GenericTransitionOptions} object that uses the given view animation.
*
* @see GenericTransitionOptions#transition(int)
*/
@NonNull
public static <TranscodeType> GenericTransitionOptions<TranscodeType> with(
int viewAnimationId) {
return new GenericTransitionOptions<TranscodeType>().transition(viewAnimationId);
}
/**
* Returns a typed {@link GenericTransitionOptions} object that uses the given animator.
*
* @see GenericTransitionOptions#transition(ViewPropertyTransition.Animator)
*/
@NonNull
public static <TranscodeType> GenericTransitionOptions<TranscodeType> with(
@NonNull ViewPropertyTransition.Animator animator) {
return new GenericTransitionOptions<TranscodeType>().transition(animator);
}
/**
* Returns a typed {@link GenericTransitionOptions} object that uses the given transition factory.
*
* @see GenericTransitionOptions#transition(TransitionFactory)
*/
@NonNull
public static <TranscodeType> GenericTransitionOptions<TranscodeType> with(
@NonNull TransitionFactory<? super TranscodeType> transitionFactory) {
return new GenericTransitionOptions<TranscodeType>().transition(transitionFactory);
}
}
package com.sdk.glide;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.widget.ImageView;
import com.sdk.glide.load.engine.Engine;
import com.sdk.glide.load.engine.bitmap_recycle.ArrayPool;
import com.sdk.glide.request.RequestOptions;
import com.sdk.glide.request.target.ImageViewTargetFactory;
import com.sdk.glide.request.target.ViewTarget;
import java.util.Map;
import java.util.Map.Entry;
/**
* Global context for all loads in Glide containing and exposing the various registries and classes
* required to load resources.
*/
public class GlideContext extends ContextWrapper {
@VisibleForTesting
static final TransitionOptions<?, ?> DEFAULT_TRANSITION_OPTIONS =
new GenericTransitionOptions<>();
private final Handler mainHandler;
private final ArrayPool arrayPool;
private final Registry registry;
private final ImageViewTargetFactory imageViewTargetFactory;
private final RequestOptions defaultRequestOptions;
private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions;
private final Engine engine;
private final int logLevel;
public GlideContext(
@NonNull Context context,
@NonNull ArrayPool arrayPool,
@NonNull Registry registry,
@NonNull ImageViewTargetFactory imageViewTargetFactory,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull Engine engine,
int logLevel) {
super(context.getApplicationContext());
this.arrayPool = arrayPool;
this.registry = registry;
this.imageViewTargetFactory = imageViewTargetFactory;
this.defaultRequestOptions = defaultRequestOptions;
this.defaultTransitionOptions = defaultTransitionOptions;
this.engine = engine;
this.logLevel = logLevel;
mainHandler = new Handler(Looper.getMainLooper());
}
public RequestOptions getDefaultRequestOptions() {
return defaultRequestOptions;
}
@SuppressWarnings("unchecked")
@NonNull
public <T> TransitionOptions<?, T> getDefaultTransitionOptions(@NonNull Class<T> transcodeClass) {
TransitionOptions<?, ?> result = defaultTransitionOptions.get(transcodeClass);
if (result == null) {
for (Entry<Class<?>, TransitionOptions<?, ?>> value : defaultTransitionOptions.entrySet()) {
if (value.getKey().isAssignableFrom(transcodeClass)) {
result = value.getValue();
}
}
}
if (result == null) {
result = DEFAULT_TRANSITION_OPTIONS;
}
return (TransitionOptions<?, T>) result;
}
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
@NonNull
public Handler getMainHandler() {
return mainHandler;
}
@NonNull
public Engine getEngine() {
return engine;
}
@NonNull
public Registry getRegistry() {
return registry;
}
public int getLogLevel() {
return logLevel;
}
@NonNull
public ArrayPool getArrayPool() {
return arrayPool;
}
}
package com.sdk.glide;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.AbsListView;
import com.sdk.glide.request.target.BaseTarget;
import com.sdk.glide.request.target.SizeReadyCallback;
import com.sdk.glide.request.transition.Transition;
import com.sdk.glide.util.Synthetic;
import com.sdk.glide.util.Util;
import java.util.List;
import java.util.Queue;
/**
* Loads a few resources ahead in the direction of scrolling in any {@link AbsListView} so that
* images are in the memory cache just before the corresponding view in created in the list. Gives
* the appearance of an infinitely large image cache, depending on scrolling speed, cpu speed, and
* cache size.
*
* <p> Must be put using
* {@link AbsListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}, or have its
* corresponding methods called from another {@link android.widget.AbsListView.OnScrollListener} to
* function. </p>
*
* @param <T> The type of the model being displayed in the list.
*/
public class ListPreloader<T> implements AbsListView.OnScrollListener {
private final int maxPreload;
private final PreloadTargetQueue preloadTargetQueue;
private final RequestManager requestManager;
private final PreloadModelProvider<T> preloadModelProvider;
private final PreloadSizeProvider<T> preloadDimensionProvider;
private int lastEnd;
private int lastStart;
private int lastFirstVisible = -1;
private int totalItemCount;
private boolean isIncreasing = true;
/**
* An implementation of PreloadModelProvider should provide all the models that should be
* preloaded.
*
* @param <U> The type of the model being preloaded.
*/
public interface PreloadModelProvider<U> {
/**
* Returns a {@link List} of models that need to be loaded for the list to display adapter items
* in positions between {@code start} and {@code end}.
*
* <p>A list of any size can be returned so there can be multiple models per adapter position.
*
* <p>Every model returned by this method is expected to produce a valid {@link RequestBuilder}
* in {@link #getPreloadRequestBuilder(Object)}. If that's not possible for any set of models,
* avoid including them in the {@link List} returned by this method.
*
* <p>Although it's acceptable for the returned {@link List} to contain {@code null} models,
* it's best to filter them from the list instead of adding {@code null} to avoid unnecessary
* logic and expanding the size of the {@link List}
*
* @param position The adapter position.
*/
@NonNull
List<U> getPreloadItems(int position);
/**
* Returns a {@link RequestBuilder} for a given item on which
* {@link RequestBuilder#load(Object)}} has been called or {@code null} if no valid load can be
* started.
*
* <p>For the preloader to be effective, the {@link RequestBuilder} returned here must use
* exactly the same size and set of options as the {@link RequestBuilder} used when the ``View``
* is bound. You may need to specify a size in both places to ensure that the width and height
* match exactly. If so, you can use
* {@link com.sdk.glide.request.RequestOptions#override(int, int)} to do so.
*
* <p>The target and context will be provided by the preloader.
*
* <p>If {@link RequestBuilder#load(Object)} is not called by this method, the preloader will
* trigger a {@link RuntimeException}. If you don't want to load a particular item or position,
* filter it from the list returned by {@link #getPreloadItems(int)}.
*
* @param item The model to load.
*/
@Nullable
RequestBuilder<?> getPreloadRequestBuilder(@NonNull U item);
}
/**
* An implementation of PreloadSizeProvider should provide the size of the view in the list where
* the resources will be displayed.
*
* @param <T> The type of the model the size should be provided for.
*/
public interface PreloadSizeProvider<T> {
/**
* Returns the size of the view in the list where the resources will be displayed in pixels in
* the format [x, y], or {@code null} if no size is currently available.
*
* <p>Note - The dimensions returned here must precisely match those of the view in the list.
*
* <p>If this method returns {@code null}, then no request will be started for the given item.
*
* @param item A model
*/
@Nullable
int[] getPreloadSize(@NonNull T item, int adapterPosition, int perItemPosition);
}
/**
* Constructor for {@link com.sdk.glide.ListPreloader} that accepts interfaces for providing
* the dimensions of images to preload, the list of models to preload for a given position, and
* the request to use to load images.
*
* @param preloadModelProvider Provides models to load and requests capable of loading them.
* @param preloadDimensionProvider Provides the dimensions of images to load.
* @param maxPreload Maximum number of items to preload.
*/
public ListPreloader(@NonNull RequestManager requestManager,
@NonNull PreloadModelProvider<T> preloadModelProvider,
@NonNull PreloadSizeProvider<T> preloadDimensionProvider, int maxPreload) {
this.requestManager = requestManager;
this.preloadModelProvider = preloadModelProvider;
this.preloadDimensionProvider = preloadDimensionProvider;
this.maxPreload = maxPreload;
preloadTargetQueue = new PreloadTargetQueue(maxPreload + 1);
}
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
// Do nothing.
}
@Override
public void onScroll(AbsListView absListView, int firstVisible, int visibleCount,
int totalCount) {
totalItemCount = totalCount;
if (firstVisible > lastFirstVisible) {
preload(firstVisible + visibleCount, true);
} else if (firstVisible < lastFirstVisible) {
preload(firstVisible, false);
}
lastFirstVisible = firstVisible;
}
private void preload(int start, boolean increasing) {
if (isIncreasing != increasing) {
isIncreasing = increasing;
cancelAll();
}
preload(start, start + (increasing ? maxPreload : -maxPreload));
}
private void preload(int from, int to) {
int start;
int end;
if (from < to) {
start = Math.max(lastEnd, from);
end = to;
} else {
start = to;
end = Math.min(lastStart, from);
}
end = Math.min(totalItemCount, end);
start = Math.min(totalItemCount, Math.max(0, start));
if (from < to) {
// Increasing
for (int i = start; i < end; i++) {
preloadAdapterPosition(preloadModelProvider.getPreloadItems(i), i, true);
}
} else {
// Decreasing
for (int i = end - 1; i >= start; i--) {
preloadAdapterPosition(preloadModelProvider.getPreloadItems(i), i, false);
}
}
lastStart = start;
lastEnd = end;
}
private void preloadAdapterPosition(List<T> items, int position, boolean isIncreasing) {
final int numItems = items.size();
if (isIncreasing) {
for (int i = 0; i < numItems; ++i) {
preloadItem(items.get(i), position, i);
}
} else {
for (int i = numItems - 1; i >= 0; --i) {
preloadItem(items.get(i), position, i);
}
}
}
@SuppressWarnings("unchecked")
private void preloadItem(@Nullable T item, int position, int perItemPosition) {
if (item == null) {
return;
}
int[] dimensions =
preloadDimensionProvider.getPreloadSize(item, position, perItemPosition);
if (dimensions == null) {
return;
}
RequestBuilder<Object> preloadRequestBuilder =
(RequestBuilder<Object>) preloadModelProvider.getPreloadRequestBuilder(item);
if (preloadRequestBuilder == null) {
return;
}
preloadRequestBuilder.into(preloadTargetQueue.next(dimensions[0], dimensions[1]));
}
private void cancelAll() {
for (int i = 0; i < maxPreload; i++) {
requestManager.clear(preloadTargetQueue.next(0, 0));
}
}
private static final class PreloadTargetQueue {
private final Queue<PreloadTarget> queue;
// The loop is short and the only point is to create the objects.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
PreloadTargetQueue(int size) {
queue = Util.createQueue(size);
for (int i = 0; i < size; i++) {
queue.offer(new PreloadTarget());
}
}
public PreloadTarget next(int width, int height) {
final PreloadTarget result = queue.poll();
queue.offer(result);
result.photoWidth = width;
result.photoHeight = height;
return result;
}
}
private static final class PreloadTarget extends BaseTarget<Object> {
@Synthetic int photoHeight;
@Synthetic int photoWidth;
@Synthetic
PreloadTarget() { }
@Override
public void onResourceReady(@NonNull Object resource,
@Nullable Transition<? super Object> transition) {
// Do nothing.
}
@Override
public void getSize(@NonNull SizeReadyCallback cb) {
cb.onSizeReady(photoWidth, photoHeight);
}
@Override
public void removeCallback(@NonNull SizeReadyCallback cb) {
// Do nothing because we don't retain references to SizeReadyCallbacks.
}
}
}
package com.sdk.glide;
/**
* An enum for dynamically modifying the amount of memory Glide is able to use.
*/
public enum MemoryCategory {
/**
* Tells Glide's memory cache and bitmap pool to use at most half of their initial maximum size.
*/
LOW(0.5f),
/**
* Tells Glide's memory cache and bitmap pool to use at most their initial maximum size.
*/
NORMAL(1f),
/**
* Tells Glide's memory cache and bitmap pool to use at most one and a half times their initial
* maximum size.
*/
HIGH(1.5f);
private final float multiplier;
MemoryCategory(float multiplier) {
this.multiplier = multiplier;
}
/**
* Returns the multiplier that should be applied to the initial maximum size of Glide's memory
* cache and bitmap pool.
*/
public float getMultiplier() {
return multiplier;
}
}
package com.sdk.glide;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.CheckResult;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RawRes;
import java.io.File;
import java.net.URL;
/**
* Ensures that the set of explicitly supported model types remains consistent across Glide's
* API surface.
*/
interface ModelTypes<T> {
@NonNull
@CheckResult
T load(@Nullable Bitmap bitmap);
@NonNull
@CheckResult
T load(@Nullable Drawable drawable);
@NonNull
@CheckResult
T load(@Nullable String string);
@NonNull
@CheckResult
T load(@Nullable Uri uri);
@NonNull
@CheckResult
T load(@Nullable File file);
@NonNull
@CheckResult
T load(@RawRes @DrawableRes @Nullable Integer resourceId);
@Deprecated
@CheckResult
T load(@Nullable URL url);
@NonNull
@CheckResult
T load(@Nullable byte[] model);
@NonNull
@CheckResult
@SuppressWarnings("unchecked")
T load(@Nullable Object model);
}
package com.sdk.glide;
/**
* Priorities for completing loads. If more than one load is queued at a time, the load with the
* higher priority will be started first. Priorities are considered best effort, there are no
* guarantees about the order in which loads will start or finish.
*/
public enum Priority {
IMMEDIATE,
HIGH,
NORMAL,
LOW,
}
package com.sdk.glide;
import android.support.annotation.NonNull;
import com.sdk.glide.request.transition.NoTransition;
import com.sdk.glide.request.transition.TransitionFactory;
import com.sdk.glide.request.transition.ViewAnimationFactory;
import com.sdk.glide.request.transition.ViewPropertyAnimationFactory;
import com.sdk.glide.request.transition.ViewPropertyTransition;
import com.sdk.glide.util.Preconditions;
/**
* A base class for setting a transition to use on a resource when a load completes.
*
* @param <CHILD> The implementation of this class to return to chain methods.
* @param <TranscodeType> The type of resource that will be animated.
*/
public abstract class TransitionOptions<CHILD extends TransitionOptions<CHILD, TranscodeType>,
TranscodeType> implements Cloneable {
private TransitionFactory<? super TranscodeType> transitionFactory = NoTransition.getFactory();
/**
* Removes any existing animation put on the builder. Will be overridden by subsequent calls that
* put an animation.
*
* @return This request builder.
*/
@NonNull
public final CHILD dontTransition() {
return transition(NoTransition.getFactory());
}
/**
* Sets an {@link android.view.animation.Animation} to run on the wrapped target when an resource
* load finishes.
* Will only be run if the resource was loaded asynchronously (i.e. was not in the memory cache).
*
* @param viewAnimationId The resource id of the {@link android.view.animation} to use as the
* transition.
* @return This request builder.
*/
@NonNull
public final CHILD transition(int viewAnimationId) {
return transition(new ViewAnimationFactory<>(viewAnimationId));
}
/**
* Sets an animator to run a {@link android.view.ViewPropertyAnimator} on a view that the target
* may be wrapping when a resource load finishes.
* Will only be run if the load was loaded asynchronously (i.e. was not in the memory cache).
*
* @param animator The {@link com.sdk.glide.request.transition.ViewPropertyTransition
* .Animator} to run.
* @return This request builder.
*/
@NonNull
public final CHILD transition(@NonNull ViewPropertyTransition.Animator animator) {
return transition(new ViewPropertyAnimationFactory<>(animator));
}
/**
* Uses the given {@link TransitionFactory} to build a
* {@link com.sdk.glide.request.transition.Transition} for each request started with these
* {@code TransitionOptions}.
*
* @return This request builder.
*/
@NonNull
public final CHILD transition(
@NonNull TransitionFactory<? super TranscodeType> transitionFactory) {
this.transitionFactory = Preconditions.checkNotNull(transitionFactory);
return self();
}
@SuppressWarnings({
// cast to CHILD is safe given the generic argument represents the object's runtime class
"unchecked",
// CHILD is the correct class name.
"PMD.CloneMethodReturnTypeMustMatchClassName",
// we don't want to throw to be user friendly
"PMD.CloneThrowsCloneNotSupportedException"
})
@Override
public final CHILD clone() {
try {
return (CHILD) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
final TransitionFactory<? super TranscodeType> getTransitionFactory() {
return transitionFactory;
}
@SuppressWarnings("unchecked")
private CHILD self() {
return (CHILD) this;
}
}
package com.sdk.glide.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies a set of GlideModule and/or LibraryGlideModule classes that should be excluded
* from an application.
*
* <p>Used only on AppGlideModules. Adding this annotation to other classes will have no affect.
*
* <p>Cannot be used to exclude AppGlideModules (there must be at most one per Application anyway).
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Excludes {
Class<?>[] value();
}
package com.sdk.glide.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicate a class that extends Glide's public API.
*
* @see GlideOption
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface GlideExtension { }
package com.sdk.glide.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Identifies AppGlideModules and LibraryGlideModules for Glide's annotation processor to merge at
* compile time.
*
* <p>Replaces <meta-data /> tags in AndroidManifest.xml.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface GlideModule {
/**
* Returns the name of the class that will be used as a replacement for
* {@code com.sdk.glide.Glide} in Applications that depend on Glide's generated code.
*/
String glideName() default "GlideApp";
}
package com.sdk.glide.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Identifies methods in {@link GlideExtension} annotated classes that extend
* {@code com.sdk.glide.request.RequestOptions}.
*
* <p>All annotated methods will be added to a single
* {@code com.sdk.glide.request.RequestOptions} implementation generated per application.
* Overlapping method names in different extensions may cause errors at compile time.
*
* <p>Static equivalents of annotated methods will also be generated.
*
* <p>Methods with this annotation will only be found if they belong to classes annotated with
* {@link GlideExtension}.
*
* <p>The preferred way of writing extension methods returns the provided
* {@code com.sdk.glide.request.RequestOptions} object with one or more methods called on it.
* You must not return a newly instantiated {@code com.sdk.glide.request.RequestOptions} object
* as doing so my cause a {@code ClassCastException} at runtime. Calling either
* {@code com.sdk.glide.request.RequestOptions#autoClone()} or
* {@code com.sdk.glide.request.RequestOptions#lock()} is safe, but unnecessary and should
* typically be avoided. The preferred style looks like:
*
* <pre>
* {@code
* {@link @}GlideExtension
* public class MyExtension {
* private MyExtension() {}
*
* {@literal @}GlideOption
* public static RequestOptions myOption(RequestOptions options) {
* return options
* .optionOne()
* .optionTwo();
* }
* }
* }
* </pre>
*
* <p>The deprecated way of writing extension methods is simply a static void method. The
* {@code com.sdk.glide.request.RequestOptions} object is cloned before it is passed to this
* method to avoid an option method returning a new instance, but using methods like
* {@code com.sdk.glide.request.RequestOptions#clone()} or
* {@code com.sdk.glide.request.RequestOptions#autoClone()} can result in options applied in
* the method being silently ignored. Prefer the new style whenever possible.
*
* <pre>
* {@code
* {@literal @}GlideExtension
* public class MyExtension {
* private MyExtension() {}
*
* // Deprecated! Use the new style of GlideOption extensions instead.
* {@literal @}GlideOption
* public static void myOption(RequestOptions options) {
* options
* .optionOne()
* .optionTwo();
* }
* }
* }
* </pre>
*/
@Target(ElementType.METHOD)
// Needs to be parsed from class files in JAR.
@Retention(RetentionPolicy.CLASS)
public @interface GlideOption {
/** Does not intend to override a method in a super class. */
int OVERRIDE_NONE = 0;
/** Expects to call super and then add additional functionality to an overridden method. */
int OVERRIDE_EXTEND = 1;
/** Expects to not call super and replace an overridden method. */
int OVERRIDE_REPLACE = 2;
/**
* Determines how and whether a generated method should extend a method from it's parent.
*
* <p>Must be one of {@link #OVERRIDE_NONE}, {@link #OVERRIDE_EXTEND}, {@link #OVERRIDE_REPLACE}.
*
* <p>The extended method is determined by String and argument matching against methods in the
* extended class. If {@link #OVERRIDE_NONE} is used and the method and arguments match a method
* in the extended class, a compile time error will result. Similarly if any other override type
* is used and no method/arguments in the extended class match, a compile time error will result.
*/
int override() default OVERRIDE_NONE;
/**
* Sets the name for the generated static version of this method.
*
* <p>If this value is not set, the static method name is just the original method name with "Of"
* appended.
*/
String staticMethodName() default "";
/**
* {@code true} to indicate that it's safe to statically memoize the result of this method using
* {@code com.sdk.glide.request.RequestOptions#autoClone()}.
*
* <p>This method should only be used for no-arg methods where there's only a single possible
* value.
*
* <p>Memoization can save object allocations for frequently used options.
*/
boolean memoizeStaticMethod() default false;
/**
* {@code true} to prevent a static builder method from being generated.
*
* <p>By default static methods are generated for all methods annotated with
* {@link GlideOption}. These static factory methods allow for a cleaner API when used
* with {@code com.sdk.glide.RequestBuilder#apply}. The static factory method by default
* simply creates a new {@code com.sdk.glide.request.RequestOptions} object, calls the
* instance version of the method on it and returns it. For example:
* <pre>
* <code>
* public static GlideOptions noAnimation() {
* return new GlideOptions().dontAnimate();
* }
* </code>
* </pre>
*
* @see #memoizeStaticMethod()
* @see #staticMethodName()
*/
boolean skipStaticMethod() default false;
}
package com.sdk.glide.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Identifies methods in {@link GlideExtension} annotated classes that extend
* {@code com.sdk.glide.RequestManager}.
*
* <p>If one or more method is found with this annotation, an additional API entry point that
* exposes a generated {@code com.sdk.glide.RequestManager} subclass will be created. The
* generated API entry point acts as a drop in replacement for Glide. Glide.with(fragment) becomes
* GlideApp.with(fragment). Although the Glide.with variant will still be available, only the new
* API entry point will provide access to these additional methods.
*
* <p>The name of the API entry point created when one of these methods is found can be controlled
* by {@link GlideModule#glideName()}.
*
* <p>Methods with this annotation will only be found if they are contained in a class annotated
* with {@link GlideExtension}.
*
* <p>Methods annotated with GlideType must have a single parameter. The type of the
* single parameter must be {@code com.sdk.glide.RequestBuilder}, with a type
* matching the value of {@link #value()}.
*
* <p>Compilation will fail if a method annotated with this method is identical to a method in
* {@code com.sdk.glide.RequestManager}
*/
@Target(ElementType.METHOD)
// Needs to be parsed from class files in JAR.
@Retention(RetentionPolicy.CLASS)
public @interface GlideType {
/**
* A Resource class name, like GifDrawable.class, Bitmap.class etc.
*
* <p>Must match the type of the {@code com.sdk.glide.RequestBuilder} parameter in the
* annotated method.
*/
Class<?> value();
}
package com.sdk.glide.annotation.compiler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to retrieve LibraryGlideModule and GlideExtension classes in our annotation processor from
* libraries and applications.
*
* <p>Part of the internals of Glide's annotation processor and not for public use.
*/
@Target(ElementType.TYPE)
// Needs to be parsed from class files in JAR.
@Retention(RetentionPolicy.CLASS)
@interface Index {
String[] modules() default {};
String[] extensions() default {};
}
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sdk.glide.disklrucache;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
/**
* Buffers input from an {@link InputStream} for reading lines.
*
* <p>This class is used for buffered reading of lines. For purposes of this class, a line ends
* with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated
* line at end of input is invalid and will be ignored, the caller may use {@code
* hasUnterminatedLine()} to detect it after catching the {@code EOFException}.
*
* <p>This class is intended for reading input that strictly consists of lines, such as line-based
* cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction
* with {@link java.io.InputStreamReader} provides similar functionality, this class uses different
* end-of-input reporting and a more restrictive definition of a line.
*
* <p>This class supports only charsets that encode '\r' and '\n' as a single byte with value 13
* and 10, respectively, and the representation of no other character contains these values.
* We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.
* The default charset is US_ASCII.
*/
class StrictLineReader implements Closeable {
private static final byte CR = (byte) '\r';
private static final byte LF = (byte) '\n';
private final InputStream in;
private final Charset charset;
/*
* Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end
* and the data in the range [pos, end) is buffered for reading. At end of input, if there is
* an unterminated line, we set end == -1, otherwise end == pos. If the underlying
* {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.
*/
private byte[] buf;
private int pos;
private int end;
/**
* Constructs a new {@code LineReader} with the specified charset and the default capacity.
*
* @param in the {@code InputStream} to read data from.
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
* supported.
* @throws NullPointerException if {@code in} or {@code charset} is null.
* @throws IllegalArgumentException if the specified charset is not supported.
*/
public StrictLineReader(InputStream in, Charset charset) {
this(in, 8192, charset);
}
/**
* Constructs a new {@code LineReader} with the specified capacity and charset.
*
* @param in the {@code InputStream} to read data from.
* @param capacity the capacity of the buffer.
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
* supported.
* @throws NullPointerException if {@code in} or {@code charset} is null.
* @throws IllegalArgumentException if {@code capacity} is negative or zero
* or the specified charset is not supported.
*/
public StrictLineReader(InputStream in, int capacity, Charset charset) {
if (in == null || charset == null) {
throw new NullPointerException();
}
if (capacity < 0) {
throw new IllegalArgumentException("capacity <= 0");
}
if (!(charset.equals(Util.US_ASCII))) {
throw new IllegalArgumentException("Unsupported encoding");
}
this.in = in;
this.charset = charset;
buf = new byte[capacity];
}
/**
* Closes the reader by closing the underlying {@code InputStream} and
* marking this reader as closed.
*
* @throws IOException for errors when closing the underlying {@code InputStream}.
*/
public void close() throws IOException {
synchronized (in) {
if (buf != null) {
buf = null;
in.close();
}
}
}
/**
* Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
* this end of line marker is not included in the result.
*
* @return the next line from the input.
* @throws IOException for underlying {@code InputStream} errors.
* @throws EOFException for the end of source stream.
*/
public String readLine() throws IOException {
synchronized (in) {
if (buf == null) {
throw new IOException("LineReader is closed");
}
// Read more data if we are at the end of the buffered data.
// Though it's an error to read after an exception, we will let {@code fillBuf()}
// throw again if that happens; thus we need to handle end == -1 as well as end == pos.
if (pos >= end) {
fillBuf();
}
// Try to find LF in the buffered data and return the line if successful.
for (int i = pos; i != end; ++i) {
if (buf[i] == LF) {
int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
String res = new String(buf, pos, lineEnd - pos, charset.name());
pos = i + 1;
return res;
}
}
// Let's anticipate up to 80 characters on top of those already read.
ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
@Override
public String toString() {
int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
try {
return new String(buf, 0, length, charset.name());
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // Since we control the charset this will never happen.
}
}
};
while (true) {
out.write(buf, pos, end - pos);
// Mark unterminated line in case fillBuf throws EOFException or IOException.
end = -1;
fillBuf();
// Try to find LF in the buffered data and return the line if successful.
for (int i = pos; i != end; ++i) {
if (buf[i] == LF) {
if (i != pos) {
out.write(buf, pos, i - pos);
}
pos = i + 1;
return out.toString();
}
}
}
}
}
public boolean hasUnterminatedLine() {
return end == -1;
}
/**
* Reads new input data into the buffer. Call only with pos == end or end == -1,
* depending on the desired outcome if the function throws.
*/
private void fillBuf() throws IOException {
int result = in.read(buf, 0, buf.length);
if (result == -1) {
throw new EOFException();
}
pos = 0;
end = result;
}
}
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sdk.glide.disklrucache;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.Charset;
/** Junk drawer of utility methods. */
final class Util {
static final Charset US_ASCII = Charset.forName("US-ASCII");
static final Charset UTF_8 = Charset.forName("UTF-8");
private Util() {
}
static String readFully(Reader reader) throws IOException {
try {
StringWriter writer = new StringWriter();
char[] buffer = new char[1024];
int count;
while ((count = reader.read(buffer)) != -1) {
writer.write(buffer, 0, count);
}
return writer.toString();
} finally {
reader.close();
}
}
/**
* Deletes the contents of {@code dir}. Throws an IOException if any file
* could not be deleted, or if {@code dir} is not a readable directory.
*/
static void deleteContents(File dir) throws IOException {
File[] files = dir.listFiles();
if (files == null) {
throw new IOException("not a readable directory: " + dir);
}
for (File file : files) {
if (file.isDirectory()) {
deleteContents(file);
}
if (!file.delete()) {
throw new IOException("failed to delete file: " + file);
}
}
}
static void closeQuietly(/*Auto*/Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sdk.glide.gifdecoder;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.sdk.glide.gifdecoder";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = -1;
public static final String VERSION_NAME = "";
public BuildConfig() {
}
}
package com.sdk.glide.gifdecoder;
import android.graphics.Bitmap;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
/**
* Shared interface for GIF decoders.
*/
public interface GifDecoder {
/** File read status: No errors. */
int STATUS_OK = 0;
/** File read status: Error decoding file (may be partially decoded). */
int STATUS_FORMAT_ERROR = 1;
/** File read status: Unable to open source. */
int STATUS_OPEN_ERROR = 2;
/** Unable to fully decode the current frame. */
int STATUS_PARTIAL_DECODE = 3;
/** The total iteration count which means repeat forever. */
int TOTAL_ITERATION_COUNT_FOREVER = 0;
/** Android Lint annotation for status codes that can be used with a GIF decoder. */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {STATUS_OK, STATUS_FORMAT_ERROR, STATUS_OPEN_ERROR, STATUS_PARTIAL_DECODE})
@interface GifDecodeStatus {
}
/**
* An interface that can be used to provide reused {@link Bitmap}s to avoid GCs
* from constantly allocating {@link Bitmap}s for every frame.
*/
interface BitmapProvider {
/**
* Returns an {@link Bitmap} with exactly the given dimensions and config.
*
* @param width The width in pixels of the desired {@link Bitmap}.
* @param height The height in pixels of the desired {@link Bitmap}.
* @param config The {@link Bitmap.Config} of the desired {@link
* Bitmap}.
*/
@NonNull
Bitmap obtain(int width, int height, @NonNull Bitmap.Config config);
/**
* Releases the given Bitmap back to the pool.
*/
void release(@NonNull Bitmap bitmap);
/**
* Returns a byte array used for decoding and generating the frame bitmap.
*
* @param size the size of the byte array to obtain
*/
@NonNull
byte[] obtainByteArray(int size);
/**
* Releases the given byte array back to the pool.
*/
void release(@NonNull byte[] bytes);
/**
* Returns an int array used for decoding/generating the frame bitmaps.
*/
@NonNull
int[] obtainIntArray(int size);
/**
* Release the given array back to the pool.
*/
void release(@NonNull int[] array);
}
int getWidth();
int getHeight();
@NonNull
ByteBuffer getData();
/**
* Returns the current status of the decoder.
*
* <p> Status will update per frame to allow the caller to tell whether or not the current frame
* was decoded successfully and/or completely. Format and open failures persist across frames.
* </p>
*/
@GifDecodeStatus
int getStatus();
/**
* Move the animation frame counter forward.
*/
void advance();
/**
* Gets display duration for specified frame.
*
* @param n int index of frame.
* @return delay in milliseconds.
*/
int getDelay(int n);
/**
* Gets display duration for the upcoming frame in ms.
*/
int getNextDelay();
/**
* Gets the number of frames read from file.
*
* @return frame count.
*/
int getFrameCount();
/**
* Gets the current index of the animation frame, or -1 if animation hasn't not yet started.
*
* @return frame index.
*/
int getCurrentFrameIndex();
/**
* Resets the frame pointer to before the 0th frame, as if we'd never used this decoder to
* decode any frames.
*/
void resetFrameIndex();
/**
* Gets the "Netscape" loop count, if any. A count of 0 means repeat indefinitely.
*
* @deprecated Use {@link #getNetscapeLoopCount()} instead.
* This method cannot distinguish whether the loop count is 1 or doesn't exist.
* @return loop count if one was specified, else 1.
*/
@Deprecated
int getLoopCount();
/**
* Gets the "Netscape" loop count, if any.
* A count of 0 ({@link GifHeader#NETSCAPE_LOOP_COUNT_FOREVER}) means repeat indefinitely.
* It must not be a negative value.
* <br>
* Use {@link #getTotalIterationCount()}
* to know how many times the animation sequence should be displayed.
*
* @return loop count if one was specified,
* else -1 ({@link GifHeader#NETSCAPE_LOOP_COUNT_DOES_NOT_EXIST}).
*/
int getNetscapeLoopCount();
/**
* Gets the total count
* which represents how many times the animation sequence should be displayed.
* A count of 0 ({@link #TOTAL_ITERATION_COUNT_FOREVER}) means repeat indefinitely.
* It must not be a negative value.
* <p>
* The total count is calculated as follows by using {@link #getNetscapeLoopCount()}.
* This behavior is the same as most web browsers.
* <table border='1'>
* <tr class='tableSubHeadingColor'><th>{@code getNetscapeLoopCount()}</th>
* <th>The total count</th></tr>
* <tr><td>{@link GifHeader#NETSCAPE_LOOP_COUNT_FOREVER}</td>
* <td>{@link #TOTAL_ITERATION_COUNT_FOREVER}</td></tr>
* <tr><td>{@link GifHeader#NETSCAPE_LOOP_COUNT_DOES_NOT_EXIST}</td>
* <td>{@code 1}</td></tr>
* <tr><td>{@code n (n > 0)}</td>
* <td>{@code n + 1}</td></tr>
* </table>
* </p>
*
* @see <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=592735#c5">Discussion about
* the iteration count of animated GIFs (Chromium Issue 592735)</a>
*
* @return total iteration count calculated from "Netscape" loop count.
*/
int getTotalIterationCount();
/**
* Returns an estimated byte size for this decoder based on the data provided to {@link
* #setData(GifHeader, byte[])}, as well as internal buffers.
*/
int getByteSize();
/**
* Get the next frame in the animation sequence.
*
* @return Bitmap representation of frame.
*/
@Nullable
Bitmap getNextFrame();
/**
* Reads GIF image from stream.
*
* @param is containing GIF file.
* @return read status code (0 = no errors).
*/
@GifDecodeStatus
int read(@Nullable InputStream is, int contentLength);
void clear();
void setData(@NonNull GifHeader header, @NonNull byte[] data);
void setData(@NonNull GifHeader header, @NonNull ByteBuffer buffer);
void setData(@NonNull GifHeader header, @NonNull ByteBuffer buffer, int sampleSize);
/**
* Reads GIF image from byte array.
*
* @param data containing GIF file.
* @return read status code (0 = no errors).
*/
@GifDecodeStatus
int read(@Nullable byte[] data);
/**
* Sets the default {@link Bitmap.Config} to use when decoding frames of a GIF.
*
* <p>Valid options are {@link Bitmap.Config#ARGB_8888} and
* {@link Bitmap.Config#RGB_565}.
* {@link Bitmap.Config#ARGB_8888} will produce higher quality frames, but will
* also use 2x the memory of {@link Bitmap.Config#RGB_565}.
*
* <p>Defaults to {@link Bitmap.Config#ARGB_8888}
*
* <p>This value is not a guarantee. For example if set to
* {@link Bitmap.Config#RGB_565} and the GIF contains transparent pixels,
* {@link Bitmap.Config#ARGB_8888} will be used anyway to support the
* transparency.
*/
void setDefaultBitmapConfig(@NonNull Bitmap.Config format);
}
package com.sdk.glide.gifdecoder;
import android.support.annotation.ColorInt;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Inner model class housing metadata for each frame.
*
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">GIF 89a Specification</a>
*/
class GifFrame {
/**
* GIF Disposal Method meaning take no action.
* <p><b>GIF89a</b>: <i>No disposal specified.
* The decoder is not required to take any action.</i></p>
*/
static final int DISPOSAL_UNSPECIFIED = 0;
/**
* GIF Disposal Method meaning leave canvas from previous frame.
* <p><b>GIF89a</b>: <i>Do not dispose.
* The graphic is to be left in place.</i></p>
*/
static final int DISPOSAL_NONE = 1;
/**
* GIF Disposal Method meaning clear canvas to background color.
* <p><b>GIF89a</b>: <i>Restore to background color.
* The area used by the graphic must be restored to the background color.</i></p>
*/
static final int DISPOSAL_BACKGROUND = 2;
/**
* GIF Disposal Method meaning clear canvas to frame before last.
* <p><b>GIF89a</b>: <i>Restore to previous.
* The decoder is required to restore the area overwritten by the graphic
* with what was there prior to rendering the graphic.</i></p>
*/
static final int DISPOSAL_PREVIOUS = 3;
/**
* <p><b>GIF89a</b>:
* <i>Indicates the way in which the graphic is to be treated after being displayed.</i></p>
* Disposal methods 0-3 are defined, 4-7 are reserved for future use.
*
* @see #DISPOSAL_UNSPECIFIED
* @see #DISPOSAL_NONE
* @see #DISPOSAL_BACKGROUND
* @see #DISPOSAL_PREVIOUS
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {DISPOSAL_UNSPECIFIED, DISPOSAL_NONE, DISPOSAL_BACKGROUND, DISPOSAL_PREVIOUS})
private @interface GifDisposalMethod {
}
int ix, iy, iw, ih;
/**
* Control Flag.
*/
boolean interlace;
/**
* Control Flag.
*/
boolean transparency;
/**
* Disposal Method.
*/
@GifDisposalMethod
int dispose;
/**
* Transparency Index.
*/
int transIndex;
/**
* Delay, in milliseconds, to next frame.
*/
int delay;
/**
* Index in the raw buffer where we need to start reading to decode.
*/
int bufferFrameStart;
/**
* Local Color Table.
*/
@ColorInt
int[] lct;
}
package com.sdk.glide.gifdecoder;
import android.support.annotation.ColorInt;
import java.util.ArrayList;
import java.util.List;
/**
* A header object containing the number of frames in an animated GIF image as well as basic
* metadata like width and height that can be used to decode each individual frame of the GIF. Can
* be shared by one or more {@link com.sdk.glide.gifdecoder.GifDecoder}s to play the same
* animated GIF in multiple views.
*
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">GIF 89a Specification</a>
*/
public class GifHeader {
/** The "Netscape" loop count which means loop forever. */
public static final int NETSCAPE_LOOP_COUNT_FOREVER = 0;
/** Indicates that this header has no "Netscape" loop count. */
public static final int NETSCAPE_LOOP_COUNT_DOES_NOT_EXIST = -1;
@ColorInt
int[] gct = null;
@GifDecoder.GifDecodeStatus
int status = GifDecoder.STATUS_OK;
int frameCount = 0;
GifFrame currentFrame;
final List<GifFrame> frames = new ArrayList<>();
/** Logical screen size: Full image width. */
int width;
/** Logical screen size: Full image height. */
int height;
// 1 : global color table flag.
boolean gctFlag;
/**
* Size of Global Color Table.
* The value is already computed to be a regular number, this field doesn't store the exponent.
*/
int gctSize;
/** Background color index into the Global/Local color table. */
int bgIndex;
/**
* Pixel aspect ratio.
* Factor used to compute an approximation of the aspect ratio of the pixel in the original image.
*/
int pixelAspect;
@ColorInt
int bgColor;
int loopCount = NETSCAPE_LOOP_COUNT_DOES_NOT_EXIST;
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getNumFrames() {
return frameCount;
}
/**
* Global status code of GIF data parsing.
*/
@GifDecoder.GifDecodeStatus
public int getStatus() {
return status;
}
}
package com.sdk.glide.integration.okhttp3;
import android.content.Context;
import android.support.annotation.NonNull;
import com.sdk.glide.Glide;
import com.sdk.glide.GlideBuilder;
import com.sdk.glide.Registry;
import com.sdk.glide.load.model.GlideUrl;
import java.io.InputStream;
/**
* A {@link com.sdk.glide.module.GlideModule} implementation to replace Glide's default
* {@link java.net.HttpURLConnection} based {@link com.sdk.glide.load.model.ModelLoader}
* with an OkHttp based {@link com.sdk.glide.load.model.ModelLoader}.
*
* <p> If you're using gradle, you can include this module simply by depending on the aar, the
* module will be merged in by manifest merger. For other build systems or for more more
* information, see {@link com.sdk.glide.module.GlideModule}. </p>
*
* @deprecated Replaced by {@link OkHttpLibraryGlideModule} for Applications that use Glide's
* annotations.
*/
@Deprecated
public class OkHttpGlideModule implements com.sdk.glide.module.GlideModule {
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
// Do nothing.
}
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
}
package com.sdk.glide.integration.okhttp3;
import android.content.Context;
import android.support.annotation.NonNull;
import com.sdk.glide.Glide;
import com.sdk.glide.Registry;
import com.sdk.glide.annotation.GlideModule;
import com.sdk.glide.load.model.GlideUrl;
import com.sdk.glide.module.AppGlideModule;
import com.sdk.glide.module.LibraryGlideModule;
import java.io.InputStream;
/**
* Registers OkHttp related classes via Glide's annotation processor.
*
* <p>For Applications that depend on this library and include an
* {@link AppGlideModule} and Glide's annotation processor, this class
* will be automatically included.
*/
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
}
package com.sdk.glide.integration.okhttp3;
import android.support.annotation.NonNull;
import android.util.Log;
import com.sdk.glide.Priority;
import com.sdk.glide.load.DataSource;
import com.sdk.glide.load.HttpException;
import com.sdk.glide.load.data.DataFetcher;
import com.sdk.glide.load.model.GlideUrl;
import com.sdk.glide.util.ContentLengthInputStream;
import com.sdk.glide.util.Preconditions;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* Fetches an {@link InputStream} using the okhttp library.
*/
public class OkHttpStreamFetcher implements DataFetcher<InputStream>, okhttp3.Callback {
private static final String TAG = "OkHttpFetcher";
private final Call.Factory client;
private final GlideUrl url;
private InputStream stream;
private ResponseBody responseBody;
private DataCallback<? super InputStream> callback;
// call may be accessed on the main thread while the object is in use on other threads. All other
// accesses to variables may occur on different threads, but only one at a time.
private volatile Call call;
// Public API.
@SuppressWarnings("WeakerAccess")
public OkHttpStreamFetcher(Call.Factory client, GlideUrl url) {
this.client = client;
this.url = url;
}
@Override
public void loadData(@NonNull Priority priority,
@NonNull final DataCallback<? super InputStream> callback) {
Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
this.callback = callback;
call = client.newCall(request);
call.enqueue(this);
}
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp failed to obtain result", e);
}
callback.onLoadFailed(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
responseBody = response.body();
if (response.isSuccessful()) {
long contentLength = Preconditions.checkNotNull(responseBody).contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
callback.onDataReady(stream);
} else {
callback.onLoadFailed(new HttpException(response.message(), response.code()));
}
}
@Override
public void cleanup() {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
// Ignored
}
if (responseBody != null) {
responseBody.close();
}
callback = null;
}
@Override
public void cancel() {
Call local = call;
if (local != null) {
local.cancel();
}
}
@NonNull
@Override
public Class<InputStream> getDataClass() {
return InputStream.class;
}
@NonNull
@Override
public DataSource getDataSource() {
return DataSource.REMOTE;
}
}
package com.sdk.glide.integration.okhttp3;
import android.support.annotation.NonNull;
import com.sdk.glide.load.Options;
import com.sdk.glide.load.model.GlideUrl;
import com.sdk.glide.load.model.ModelLoader;
import com.sdk.glide.load.model.ModelLoaderFactory;
import com.sdk.glide.load.model.MultiModelLoaderFactory;
import java.io.InputStream;
import okhttp3.Call;
import okhttp3.OkHttpClient;
/**
* A simple model loader for fetching media over http/https using OkHttp.
*/
public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private final Call.Factory client;
// Public API.
@SuppressWarnings("WeakerAccess")
public OkHttpUrlLoader(@NonNull Call.Factory client) {
this.client = client;
}
@Override
public boolean handles(@NonNull GlideUrl url) {
return true;
}
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
return new LoadData<>(model, new OkHttpStreamFetcher(client, model));
}
/**
* The default factory for {@link OkHttpUrlLoader}s.
*/
// Public API.
@SuppressWarnings("WeakerAccess")
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
private static volatile Call.Factory internalClient;
private final Call.Factory client;
private static Call.Factory getInternalClient() {
if (internalClient == null) {
synchronized (Factory.class) {
if (internalClient == null) {
internalClient = new OkHttpClient();
}
}
}
return internalClient;
}
/**
* Constructor for a new Factory that runs requests using a static singleton client.
*/
public Factory() {
this(getInternalClient());
}
/**
* Constructor for a new Factory that runs requests using given client.
*
* @param client this is typically an instance of {@code OkHttpClient}.
*/
public Factory(@NonNull Call.Factory client) {
this.client = client;
}
@NonNull
@Override
public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new OkHttpUrlLoader(client);
}
@Override
public void teardown() {
// Do nothing, this instance doesn't own the client.
}
}
}
package com.sdk.glide.load;
/**
* Indicates the origin of some retrieved data.
*/
public enum DataSource {
/**
* Indicates data was probably retrieved locally from the device, although it may have been
* obtained through a content provider that may have obtained the data from a remote source.
*/
LOCAL,
/**
* Indicates data was retrieved from a remote source other than the device.
*/
REMOTE,
/**
* Indicates data was retrieved unmodified from the on device cache.
*/
DATA_DISK_CACHE,
/**
* Indicates data was retrieved from modified content in the on device cache.
*/
RESOURCE_DISK_CACHE,
/**
* Indicates data was retrieved from the in memory cache.
*/
MEMORY_CACHE,
}
package com.sdk.glide.load;
/**
* Options for setting the value of {@link android.graphics.Bitmap#getConfig()} for
* {@link android.graphics.Bitmap}s returned by {@link com.sdk.glide.load.ResourceDecoder}s.
*
* <p> Note - In some cases it may not be possible to obey the requested setting, not all
* {@link com.sdk.glide.load.resource.bitmap.Downsampler}s support setting formats and certain
* images may not be able to be loaded as certain configurations. Therefore this class represents a
* preference rather than a requirement. </p>
*/
public enum DecodeFormat {
/**
* Bitmaps returned by the {@link com.sdk.glide.load.ResourceDecoder}.
* should return {@link android.graphics.Bitmap.Config#ARGB_8888} for
* {@link android.graphics.Bitmap#getConfig()} when possible.
*
* <p>On Android O+, this format will will use ARGB_8888 only when it's not possible to use
* {@link android.graphics.Bitmap.Config#HARDWARE}. More information is available about hardware
* Bitmaps here: https://goo.gl/tn2A6k. If you need to disable hardware Bitmaps for a particular
* request, use {@link com.sdk.glide.request.RequestOptions#disallowHardwareConfig()}.
*
* <p> GIF images decoded by {@link android.graphics.BitmapFactory} currently use an internal
* hidden format that is returned as null from {@link android.graphics.Bitmap#getConfig()}. Since
* we cannot force {@link android.graphics.BitmapFactory} to always return our desired config,
* this setting is a preference, not a promise.
*/
PREFER_ARGB_8888,
/**
* Identical to {@link #PREFER_ARGB_8888} but prevents Glide from using {@link
* android.graphics.Bitmap.Config#HARDWARE} on Android O+.
*
* @deprecated If you must disable hardware bitmaps, set
* {@link com.sdk.glide.load.resource.bitmap.Downsampler#ALLOW_HARDWARE_CONFIG} to false
* instead.
*/
@Deprecated
PREFER_ARGB_8888_DISALLOW_HARDWARE,
/**
* Bitmaps decoded from image formats that support and/or use alpha (some types of PNGs, GIFs etc)
* should return {@link android.graphics.Bitmap.Config#ARGB_8888} for
* {@link android.graphics.Bitmap#getConfig()}. Bitmaps decoded from formats that don't support or
* use alpha should return {@link android.graphics.Bitmap.Config#RGB_565} for
* {@link android.graphics.Bitmap#getConfig()}.
*
* <p>On Android O+, this format will will use ARGB_8888 only when it's not possible to use
* {@link android.graphics.Bitmap.Config#HARDWARE}.
*/
PREFER_RGB_565;
/**
* The default value for DecodeFormat.
*/
public static final DecodeFormat DEFAULT = PREFER_ARGB_8888_DISALLOW_HARDWARE;
}
package com.sdk.glide.load;
/**
* Details how an {@link com.sdk.glide.load.ResourceEncoder} will encode a resource to cache.
*/
public enum EncodeStrategy {
/**
* Writes the original unmodified data for the resource to disk, not include downsampling or
* transformations.
*/
SOURCE,
/**
* Writes the decoded, downsampled and transformed data for the resource to disk.
*/
TRANSFORMED,
/**
* Will write no data.
*/
NONE,
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import java.io.File;
/**
* An interface for writing data to some persistent data store (i.e. a local File cache).
*
* @param <T> The type of the data that will be written.
*/
public interface Encoder<T> {
/**
* Writes the given data to the given output stream and returns True if the write completed
* successfully and should be committed.
*
* @param data The data to write.
* @param file The File to write the data to.
* @param options The put of options to apply when encoding.
*/
boolean encode(@NonNull T data, @NonNull File file, @NonNull Options options);
}
package com.sdk.glide.load;
import android.support.annotation.Nullable;
import java.io.IOException;
/**
* Thrown when an http request fails.
*
* <p>Exposes the specific status code or {@link #UNKNOWN} via {@link #getStatusCode()} so
* users may attempt to retry or otherwise uniformly handle certain types of errors regardless of
* the underlying http library.
*/
// Public API.
@SuppressWarnings({"WeakerAccess", "unused"})
public final class HttpException extends IOException {
private static final long serialVersionUID = 1L;
public static final int UNKNOWN = -1;
private final int statusCode;
public HttpException(int statusCode) {
this("Http request failed with status code: " + statusCode, statusCode);
}
public HttpException(String message) {
this(message, UNKNOWN);
}
public HttpException(String message, int statusCode) {
this(message, statusCode, null /*cause*/);
}
public HttpException(String message, int statusCode, @Nullable Throwable cause) {
super(message, cause);
this.statusCode = statusCode;
}
/**
* Returns the http status code, or {@link #UNKNOWN} if the request failed without providing
* a status code.
*/
public int getStatusCode() {
return statusCode;
}
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import com.sdk.glide.load.engine.bitmap_recycle.ArrayPool;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
* Interface for the ImageHeaderParser.
*/
public interface ImageHeaderParser {
/**
* A constant indicating we were unable to parse the orientation from the image either because no
* exif segment containing orientation data existed, or because of an I/O error attempting to read
* the exif segment.
*/
int UNKNOWN_ORIENTATION = -1;
/**
* The format of the image data including whether or not the image may include transparent
* pixels.
*/
enum ImageType {
GIF(true),
JPEG(false),
RAW(false),
/** PNG type with alpha. */
PNG_A(true),
/** PNG type without alpha. */
PNG(false),
/** WebP type with alpha. */
WEBP_A(true),
/** WebP type without alpha. */
WEBP(false),
/** Unrecognized type. */
UNKNOWN(false);
private final boolean hasAlpha;
ImageType(boolean hasAlpha) {
this.hasAlpha = hasAlpha;
}
public boolean hasAlpha() {
return hasAlpha;
}
}
@NonNull
ImageType getType(@NonNull InputStream is) throws IOException;
@NonNull
ImageType getType(@NonNull ByteBuffer byteBuffer) throws IOException;
/**
* Parse the orientation from the image header. If it doesn't handle this image type (or this is
* not an image) it will return a default value rather than throwing an exception.
*
* @return The exif orientation if present or -1 if the header couldn't be parsed or doesn't
* contain an orientation
*/
int getOrientation(@NonNull InputStream is, @NonNull ArrayPool byteArrayPool) throws IOException;
int getOrientation(@NonNull ByteBuffer byteBuffer, @NonNull ArrayPool byteArrayPool)
throws IOException;
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sdk.glide.load.ImageHeaderParser.ImageType;
import com.sdk.glide.load.engine.bitmap_recycle.ArrayPool;
import com.sdk.glide.load.resource.bitmap.RecyclableBufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
/**
* Utilities for the ImageHeaderParser.
*/
public final class ImageHeaderParserUtils {
// 5MB. This is the max image header size we can handle, we preallocate a much smaller buffer but
// will resize up to this amount if necessary.
private static final int MARK_POSITION = 5 * 1024 * 1024;
private ImageHeaderParserUtils() { }
/** Returns the ImageType for the given InputStream. */
@NonNull
public static ImageType getType(@NonNull List<ImageHeaderParser> parsers,
@Nullable InputStream is, @NonNull ArrayPool byteArrayPool) throws IOException {
if (is == null) {
return ImageType.UNKNOWN;
}
if (!is.markSupported()) {
is = new RecyclableBufferedInputStream(is, byteArrayPool);
}
is.mark(MARK_POSITION);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = parsers.size(); i < size; i++) {
ImageHeaderParser parser = parsers.get(i);
try {
ImageType type = parser.getType(is);
if (type != ImageType.UNKNOWN) {
return type;
}
} finally {
is.reset();
}
}
return ImageType.UNKNOWN;
}
/** Returns the ImageType for the given ByteBuffer. */
@NonNull
public static ImageType getType(@NonNull List<ImageHeaderParser> parsers,
@Nullable ByteBuffer buffer)
throws IOException {
if (buffer == null) {
return ImageType.UNKNOWN;
}
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = parsers.size(); i < size; i++) {
ImageHeaderParser parser = parsers.get(i);
ImageType type = parser.getType(buffer);
if (type != ImageType.UNKNOWN) {
return type;
}
}
return ImageType.UNKNOWN;
}
/**
* Returns the orientation for the given InputStream.
*/
public static int getOrientation(@NonNull List<ImageHeaderParser> parsers,
@Nullable InputStream is, @NonNull ArrayPool byteArrayPool) throws IOException {
if (is == null) {
return ImageHeaderParser.UNKNOWN_ORIENTATION;
}
if (!is.markSupported()) {
is = new RecyclableBufferedInputStream(is, byteArrayPool);
}
is.mark(MARK_POSITION);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = parsers.size(); i < size; i++) {
ImageHeaderParser parser = parsers.get(i);
try {
int orientation = parser.getOrientation(is, byteArrayPool);
if (orientation != ImageHeaderParser.UNKNOWN_ORIENTATION) {
return orientation;
}
} finally {
is.reset();
}
}
return ImageHeaderParser.UNKNOWN_ORIENTATION;
}
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import java.nio.charset.Charset;
import java.security.MessageDigest;
/**
* An interface that uniquely identifies some put of data. Implementations must implement {@link
* Object#equals(Object)} and {@link Object#hashCode()}. Implementations are generally expected to
* add all uniquely identifying information used in in {@link java.lang.Object#equals(Object)}} and
* {@link Object#hashCode()}} to the given {@link java.security.MessageDigest} in {@link
* #updateDiskCacheKey(java.security.MessageDigest)}}, although this requirement is not as strict
* for partial cache key signatures.
*/
public interface Key {
String STRING_CHARSET_NAME = "UTF-8";
Charset CHARSET = Charset.forName(STRING_CHARSET_NAME);
/**
* Adds all uniquely identifying information to the given digest.
*
* <p> Note - Using {@link java.security.MessageDigest#reset()} inside of this method will result
* in undefined behavior. </p>
*/
void updateDiskCacheKey(@NonNull MessageDigest messageDigest);
/**
* For caching to work correctly, implementations <em>must</em> implement this method and
* {@link #hashCode()}.
*/
@Override
boolean equals(Object o);
/**
* For caching to work correctly, implementations <em>must</em> implement this method and
* {@link #equals(Object)}.
*/
@Override
int hashCode();
}
package com.sdk.glide.load;
import android.content.Context;
import android.support.annotation.NonNull;
import com.sdk.glide.load.engine.Resource;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collection;
/**
* A transformation that applies one or more transformations in iteration order to a resource.
*
* @param <T> The type of {@link com.sdk.glide.load.engine.Resource} that will be transformed.
*/
public class MultiTransformation<T> implements Transformation<T> {
private final Collection<? extends Transformation<T>> transformations;
@SafeVarargs
@SuppressWarnings("varargs")
public MultiTransformation(@NonNull Transformation<T>... transformations) {
if (transformations.length == 0) {
throw new IllegalArgumentException(
"MultiTransformation must contain at least one Transformation");
}
this.transformations = Arrays.asList(transformations);
}
public MultiTransformation(@NonNull Collection<? extends Transformation<T>> transformationList) {
if (transformationList.isEmpty()) {
throw new IllegalArgumentException(
"MultiTransformation must contain at least one Transformation");
}
this.transformations = transformationList;
}
@NonNull
@Override
public Resource<T> transform(
@NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
Resource<T> previous = resource;
for (Transformation<T> transformation : transformations) {
Resource<T> transformed = transformation.transform(context, previous, outWidth, outHeight);
if (previous != null && !previous.equals(resource) && !previous.equals(transformed)) {
previous.recycle();
}
previous = transformed;
}
return previous;
}
@Override
public boolean equals(Object o) {
if (o instanceof MultiTransformation) {
MultiTransformation<?> other = (MultiTransformation<?>) o;
return transformations.equals(other.transformations);
}
return false;
}
@Override
public int hashCode() {
return transformations.hashCode();
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
for (Transformation<T> transformation : transformations) {
transformation.updateDiskCacheKey(messageDigest);
}
}
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sdk.glide.util.Preconditions;
import java.security.MessageDigest;
/**
* Defines available component (decoders, encoders, model loaders etc.) options with optional
* default values and the ability to affect the resource disk cache key used by {@link
* com.sdk.glide.load.engine.DiskCacheStrategy#RESOURCE}.
*
* <p>
* Implementations must either be unique (usually declared as static final variables), or
* implement {@link #equals(Object)} and {@link #hashCode()}.
* </p>
*
* <p>
* Implementations can implement {@link #update(Object, MessageDigest)} to make sure that
* the disk cache key includes the specific option set.
* </p>
*
* @param <T> The type of the option ({@link Integer}, {@link
* android.graphics.Bitmap.CompressFormat} etc.), must implement {@link #equals(Object)} and
* {@link #hashCode()}.
*/
public final class Option<T> {
private static final CacheKeyUpdater<Object> EMPTY_UPDATER = new CacheKeyUpdater<Object>() {
@Override
public void update(@NonNull byte[] keyBytes, @NonNull Object value,
@NonNull MessageDigest messageDigest) {
// Do nothing.
}
};
private final T defaultValue;
private final CacheKeyUpdater<T> cacheKeyUpdater;
private final String key;
private volatile byte[] keyBytes;
/**
* Returns a new {@link Option} that does not affect disk cache keys with a {@code null} default
* value.
*
* @param key A unique package prefixed {@link String} that identifies this option (must be
* stable across builds, so {@link Class#getName()} should <em>not</em> be used).
*/
@NonNull
public static <T> Option<T> memory(@NonNull String key) {
return new Option<>(key, null, Option.<T>emptyUpdater());
}
/**
* Returns a new {@link Option} that does not affect disk cache keys with the given value as the
* default value.
*
* @param key A unique package prefixed {@link String} that identifies this option (must be
* stable across builds, so {@link Class#getName()} should <em>not</em> be used).
*/
@NonNull
public static <T> Option<T> memory(@NonNull String key, @NonNull T defaultValue) {
return new Option<>(key, defaultValue, Option.<T>emptyUpdater());
}
/**
* Returns a new {@link Option} that uses the given {@link
* com.sdk.glide.load.Option.CacheKeyUpdater} to update disk cache keys.
*
* @param key A unique package prefixed {@link String} that identifies this option (must be
* stable across builds, so {@link Class#getName()} should <em>not</em> be used).
*/
@NonNull
public static <T> Option<T> disk(@NonNull String key,
@NonNull CacheKeyUpdater<T> cacheKeyUpdater) {
return new Option<>(key, null, cacheKeyUpdater);
}
/**
* Returns a new {@link Option} that uses the given {@link
* com.sdk.glide.load.Option.CacheKeyUpdater} to update disk cache keys and provides
* the given value as the default value.
*
* @param key A unique package prefixed {@link String} that identifies this option (must be
* stable across builds, so {@link Class#getName()} should <em>not</em> be used).
*/
@NonNull
public static <T> Option<T> disk(@NonNull String key, @Nullable T defaultValue,
@NonNull CacheKeyUpdater<T> cacheKeyUpdater) {
return new Option<>(key, defaultValue, cacheKeyUpdater);
}
private Option(@NonNull String key, @Nullable T defaultValue,
@NonNull CacheKeyUpdater<T> cacheKeyUpdater) {
this.key = Preconditions.checkNotEmpty(key);
this.defaultValue = defaultValue;
this.cacheKeyUpdater = Preconditions.checkNotNull(cacheKeyUpdater);
}
/**
* Returns a reasonable default to use if no other value is set, or {@code null}.
*/
// Public API.
@SuppressWarnings("WeakerAccess")
@Nullable
public T getDefaultValue() {
return defaultValue;
}
/**
* Updates the given {@link MessageDigest} used to construct a cache key with the given
* value using the {@link com.sdk.glide.load.Option.CacheKeyUpdater} optionally provided in
* the constructor.
*/
public void update(@NonNull T value, @NonNull MessageDigest messageDigest) {
cacheKeyUpdater.update(getKeyBytes(), value, messageDigest);
}
@NonNull
private byte[] getKeyBytes() {
if (keyBytes == null) {
keyBytes = key.getBytes(Key.CHARSET);
}
return keyBytes;
}
@Override
public boolean equals(Object o) {
if (o instanceof Option) {
Option<?> other = (Option<?>) o;
return key.equals(other.key);
}
return false;
}
@Override
public int hashCode() {
return key.hashCode();
}
@NonNull
@SuppressWarnings("unchecked")
private static <T> CacheKeyUpdater<T> emptyUpdater() {
return (CacheKeyUpdater<T>) EMPTY_UPDATER;
}
@Override
public String toString() {
return "Option{"
+ "key='" + key + '\''
+ '}';
}
/**
* An interface that updates a {@link MessageDigest} with the given value as part of a process to
* generate a disk cache key.
*
* @param <T> The type of the option.
*/
public interface CacheKeyUpdater<T> {
/**
* Updates the given {@link MessageDigest} with the bytes of the given key (to avoid incidental
* value collisions when values are not particularly unique) and value.
*
* <p>If your {@link Option} shouldn't affect the disk cache key, you should not implement this
* class and use {@link Option#memory(String)} or {@link Option#memory(String, Object)} instead.
*
* @param keyBytes The bytes of the {@link String} used as the key for this particular
* {@link Option}. Should be added to the {@code messageDigest} using
* {@link MessageDigest#update(byte[])} by all implementations if the digest is updated with
* the given {@code value} parameter.
*
* @param value The value of of this particular option. Typically you should convert the value
* to a byte array using some stable mechanism and then call
* {@link MessageDigest#update(byte[])} to update the given digest.
*/
void update(@NonNull byte[] keyBytes, @NonNull T value, @NonNull MessageDigest messageDigest);
}
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.ArrayMap;
import android.support.v4.util.SimpleArrayMap;
import com.sdk.glide.util.CachedHashCodeArrayMap;
import java.security.MessageDigest;
/**
* A set of {@link Option Options} to apply to in memory and disk cache keys.
*/
public final class Options implements Key {
private final ArrayMap<Option<?>, Object> values = new CachedHashCodeArrayMap<>();
public void putAll(@NonNull Options other) {
values.putAll((SimpleArrayMap<Option<?>, Object>) other.values);
}
@NonNull
public <T> Options set(@NonNull Option<T> option, @NonNull T value) {
values.put(option, value);
return this;
}
@Nullable
@SuppressWarnings("unchecked")
public <T> T get(@NonNull Option<T> option) {
return values.containsKey(option) ? (T) values.get(option) : option.getDefaultValue();
}
@Override
public boolean equals(Object o) {
if (o instanceof Options) {
Options other = (Options) o;
return values.equals(other.values);
}
return false;
}
@Override
public int hashCode() {
return values.hashCode();
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
for (int i = 0; i < values.size(); i++) {
Option<?> key = values.keyAt(i);
Object value = values.valueAt(i);
updateDiskCacheKey(key, value, messageDigest);
}
}
@Override
public String toString() {
return "Options{"
+ "values=" + values
+ '}';
}
@SuppressWarnings("unchecked")
private static <T> void updateDiskCacheKey(@NonNull Option<T> option, @NonNull Object value,
@NonNull MessageDigest md) {
option.update((T) value, md);
}
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sdk.glide.load.engine.Resource;
import java.io.IOException;
/**
* An interface for decoding resources.
*
* @param <T> The type the resource will be decoded from (File, InputStream etc).
* @param <Z> The type of the decoded resource (Bitmap, Drawable etc).
*/
public interface ResourceDecoder<T, Z> {
/**
* Returns {@code true} if this decoder is capable of decoding the given source with the given
* options, and {@code false} otherwise.
*
* <p>Decoders should make a best effort attempt to quickly determine if they are likely to be
* able to decode data, but should not attempt to completely read the given data. A typical
* implementation would check the file headers verify they match content the decoder expects to
* handle (i.e. a GIF decoder should verify that the image contains the GIF header block.
*
* <p>Decoders that return {@code true} from {@code handles} may still return {@code null} from
* {@link #decode(Object, int, int, Options)} if the data is partial or formatted incorrectly.
*/
boolean handles(@NonNull T source, @NonNull Options options) throws IOException;
/**
* Returns a decoded resource from the given data or null if no resource could be decoded.
*
* <p>The {@code source} is managed by the caller, there's no need to close it. The returned
* {@link Resource} will be {@link Resource#recycle() released} when the engine sees fit.
*
* <p>Note - The {@code width} and {@code height} arguments are hints only, there is no
* requirement that the decoded resource exactly match the given dimensions. A typical use case
* would be to use the target dimensions to determine how much to downsample Bitmaps by to avoid
* overly large allocations.
*
* @param source The data the resource should be decoded from.
* @param width The ideal width in pixels of the decoded resource, or {@link
* com.sdk.glide.request.target.Target#SIZE_ORIGINAL} to indicate the original
* resource width.
* @param height The ideal height in pixels of the decoded resource, or {@link
* com.sdk.glide.request.target.Target#SIZE_ORIGINAL} to indicate the original
* resource height.
* @param options A map of string keys to objects that may or may not contain options available to
* this particular implementation. Implementations should not assume that any or
* all of their option keys are present. However, implementations may assume that
* if one of their option keys is present, it's value is non-null and is of the
* expected type.
*/
@Nullable
Resource<Z> decode(@NonNull T source, int width, int height, @NonNull Options options)
throws IOException;
}
package com.sdk.glide.load;
import android.support.annotation.NonNull;
import com.sdk.glide.load.engine.Resource;
/**
* An interface for writing data from a resource to some persistent data store (i.e. a local File
* cache).
*
* @param <T> The type of the data contained by the resource.
*/
public interface ResourceEncoder<T> extends Encoder<Resource<T>> {
// specializing the generic arguments
@NonNull
EncodeStrategy getEncodeStrategy(@NonNull Options options);
}
package com.sdk.glide.load;
import android.content.Context;
import android.support.annotation.NonNull;
import com.sdk.glide.load.engine.Resource;
import java.nio.charset.Charset;
import java.security.MessageDigest;
/**
* A class for performing an arbitrary transformation on a resource that implements
* {@link #equals(Object)} and {@link #hashCode()}} to identify the transformation in the memory
* cache and {@link #updateDiskCacheKey(java.security.MessageDigest)}} to identify the
* transformation in disk caches.
*
* <p>Using the fully qualified class name as a static final {@link String} (not
* {@link Class#getName()} to avoid proguard obfuscation) is an easy way to implement
* {@link #updateDiskCacheKey(java.security.MessageDigest)}} correctly. If additional arguments are
* required they can be passed in to the constructor of the {@code Transformation} and then used to
* update the {@link java.security.MessageDigest} passed in to
* {@link #updateDiskCacheKey(MessageDigest)}. If arguments are primitive types, they can typically
* easily be serialized using {@link java.nio.ByteBuffer}. {@link String} types can be serialized
* with {@link String#getBytes(Charset)} using the constant {@link #CHARSET}.
*
* <p>Implementations <em>must</em> implement {@link #equals(Object)} and {@link #hashCode()} for
* memory caching to work correctly.
*
* @param <T> The type of the resource being transformed.
*/
public interface Transformation<T> extends Key {
/**
* Transforms the given resource and returns the transformed resource.
*
* <p>If the original resource object is not returned, the original resource will be
* recycled and it's internal resources may be reused. This means it is not safe to rely on the
* original resource or any internal state of the original resource in any new resource that is
* created. Usually this shouldn't occur, but if absolutely necessary either the original resource
* object can be returned with modified internal state, or the data in the original resource can
* be copied into the transformed resource.
*
* <p>If a Transformation is updated, {@link #equals(Object)}, {@link #hashCode()}, and
* {@link #updateDiskCacheKey(java.security.MessageDigest)} should all change. If you're using a
* simple String key an easy way to do this is to append a version number to your key. Failing to
* do so will mean users may see images loaded from cache that had the old version of the
* Transformation applied. Changing the return values of those methods will ensure that the cache
* key has changed and therefore that any cached resources will be re-generated using the updated
* Transformation.
*
* <p>During development you may need to either using {@link
* com.sdk.glide.load.engine.DiskCacheStrategy#NONE} or make sure {@link
* #updateDiskCacheKey(java.security.MessageDigest)} changes each time you make a change to the
* Transformation. Otherwise the resource you request may be loaded from disk cache and your
* Transformation may not be called.
*
* @param context The Application context
* @param resource The resource to transform.
* @param outWidth The width of the view or target the resource will be displayed in, or {@link
* com.sdk.glide.request.target.Target#SIZE_ORIGINAL} to indicate the
* original resource width.
* @param outHeight The height of the view or target the resource will be displayed in, or {@link
* com.sdk.glide.request.target.Target#SIZE_ORIGINAL} to indicate the
* original resource height.
* @return The transformed resource.
*/
@NonNull
Resource<T> transform(@NonNull Context context, @NonNull Resource<T> resource,
int outWidth, int outHeight);
}
package com.sdk.glide.load.data;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.support.annotation.NonNull;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Fetches an {@link AssetFileDescriptor} for a local {@link android.net.Uri}.
*/
public final class AssetFileDescriptorLocalUriFetcher extends LocalUriFetcher<AssetFileDescriptor> {
public AssetFileDescriptorLocalUriFetcher(ContentResolver contentResolver, Uri uri) {
super(contentResolver, uri);
}
@Override
protected AssetFileDescriptor loadResource(Uri uri, ContentResolver contentResolver)
throws FileNotFoundException {
AssetFileDescriptor result = contentResolver.openAssetFileDescriptor(uri, "r");
if (result == null) {
throw new FileNotFoundException("FileDescriptor is null for: " + uri);
}
return result;
}
@Override
protected void close(AssetFileDescriptor data) throws IOException {
data.close();
}
@NonNull
@Override
public Class<AssetFileDescriptor> getDataClass() {
return AssetFileDescriptor.class;
}
}
package com.sdk.glide.load.data;
import android.content.res.AssetManager;
import android.support.annotation.NonNull;
import android.util.Log;
import com.sdk.glide.Priority;
import com.sdk.glide.load.DataSource;
import java.io.IOException;
/**
* An abstract class for obtaining data for an asset path using an {@link
* android.content.res.AssetManager}.
*
* @param <T> The type of data obtained from the asset path (InputStream, FileDescriptor etc).
*/
public abstract class AssetPathFetcher<T> implements DataFetcher<T> {
private static final String TAG = "AssetPathFetcher";
private final String assetPath;
private final AssetManager assetManager;
private T data;
// Public API.
@SuppressWarnings("WeakerAccess")
public AssetPathFetcher(AssetManager assetManager, String assetPath) {
this.assetManager = assetManager;
this.assetPath = assetPath;
}
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super T> callback) {
try {
data = loadResource(assetManager, assetPath);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data from asset manager", e);
}
callback.onLoadFailed(e);
return;
}
callback.onDataReady(data);
}
@Override
public void cleanup() {
if (data == null) {
return;
}
try {
close(data);
} catch (IOException e) {
// Ignored.
}
}
@Override
public void cancel() {
// Do nothing.
}
@NonNull
@Override
public DataSource getDataSource() {
return DataSource.LOCAL;
}
/**
* Opens the given asset path with the given {@link android.content.res.AssetManager} and returns
* the concrete data type returned by the AssetManager.
*
* @param assetManager An AssetManager to use to open the given path.
* @param path A string path pointing to a resource in assets to open.
*/
protected abstract T loadResource(AssetManager assetManager, String path) throws IOException;
/**
* Closes the concrete data type if necessary.
*
* @param data The data to close.
*/
protected abstract void close(T data) throws IOException;
}
package com.sdk.glide.load.data;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import com.sdk.glide.load.engine.bitmap_recycle.ArrayPool;
import java.io.IOException;
import java.io.OutputStream;
/**
* An {@link OutputStream} implementation that recycles and re-uses {@code byte[]}s using the
* provided {@link ArrayPool}.
*/
public final class BufferedOutputStream extends OutputStream {
@NonNull
private final OutputStream out;
private byte[] buffer;
private ArrayPool arrayPool;
private int index;
public BufferedOutputStream(@NonNull OutputStream out, @NonNull ArrayPool arrayPool) {
this(out, arrayPool, ArrayPool.STANDARD_BUFFER_SIZE_BYTES);
}
@VisibleForTesting
BufferedOutputStream(@NonNull OutputStream out, ArrayPool arrayPool, int bufferSize) {
this.out = out;
this.arrayPool = arrayPool;
buffer = arrayPool.get(bufferSize, byte[].class);
}
@Override
public void write(int b) throws IOException {
buffer[index++] = (byte) b;
maybeFlushBuffer();
}
@Override
public void write(@NonNull byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(@NonNull byte[] b, int initialOffset, int length) throws IOException {
int writtenSoFar = 0;
do {
int remainingToWrite = length - writtenSoFar;
int currentOffset = initialOffset + writtenSoFar;
// If we still need to write at least the buffer size worth of bytes, we might as well do so
// directly and avoid the overhead of copying to the buffer first.
if (index == 0 && remainingToWrite >= buffer.length) {
out.write(b, currentOffset, remainingToWrite);
return;
}
int remainingSpaceInBuffer = buffer.length - index;
int totalBytesToWriteToBuffer = Math.min(remainingToWrite, remainingSpaceInBuffer);
System.arraycopy(b, currentOffset, buffer, index, totalBytesToWriteToBuffer);
index += totalBytesToWriteToBuffer;
writtenSoFar += totalBytesToWriteToBuffer;
maybeFlushBuffer();
} while (writtenSoFar < length);
}
@Override
public void flush() throws IOException {
flushBuffer();
out.flush();
}
private void flushBuffer() throws IOException {
if (index > 0) {
out.write(buffer, 0, index);
index = 0;
}
}
private void maybeFlushBuffer() throws IOException {
if (index == buffer.length) {
flushBuffer();
}
}
@Override
public void close() throws IOException {
try {
flush();
} finally {
out.close();
}
release();
}
private void release() {
if (buffer != null) {
arrayPool.put(buffer);
buffer = null;
}
}
}
package com.sdk.glide.load.data;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sdk.glide.Priority;
import com.sdk.glide.load.DataSource;
/**
* Lazily retrieves data that can be used to load a resource.
*
* <p> A new instance is
* created per resource load by {@link com.sdk.glide.load.model.ModelLoader}. {@link
* #loadData(com.sdk.glide.Priority, com.sdk.glide.load.data.DataFetcher.DataCallback)}
* may or may not be called for any given load depending on whether or not the corresponding
* resource is cached. Cancel also may or may not be called. If
* {@link #loadData(com.sdk.glide.Priority,
* com.sdk.glide.load.data.DataFetcher.DataCallback)}} is called, then so {@link #cleanup()}
* will be called. </p>
*
* @param <T> The type of data to be loaded (InputStream, byte[], File etc).
*/
public interface DataFetcher<T> {
/**
* Callback that must be called when data has been loaded and is available, or when the load
* fails.
*
* @param <T> The type of data that will be loaded.
*/
interface DataCallback<T> {
/**
* Called with the loaded data if the load succeeded, or with {@code null} if the load failed.
*/
void onDataReady(@Nullable T data);
/**
* Called when the load fails.
*
* @param e a non-null {@link Exception} indicating why the load failed.
*/
void onLoadFailed(@NonNull Exception e);
}
/**
* Fetch data from which a resource can be decoded.
*
* <p> This will always be called on background thread so it is safe to perform long running tasks
* here. Any third party libraries called must be thread safe (or move the work to another thread)
* since this method will be called from a thread in a
* {@link java.util.concurrent.ExecutorService}
* that may have more than one background thread. </p>
*
* You <b>MUST</b> use the {@link DataCallback} once the request is complete.
*
* You are free to move the fetch work to another thread and call the callback from there.
*
* <p> This method will only be called when the corresponding resource is not in the cache. </p>
*
* <p> Note - this method will be run on a background thread so blocking I/O is safe. </p>
*
* @param priority The priority with which the request should be completed.
* @param callback The callback to use when the request is complete
* @see #cleanup() where the data retuned will be cleaned up
*/
void loadData(@NonNull Priority priority, @NonNull DataCallback<? super T> callback);
/**
* Cleanup or recycle any resources used by this data fetcher. This method will be called in a
* finally block after the data provided by {@link #loadData(com.sdk.glide.Priority,
* com.sdk.glide.load.data.DataFetcher.DataCallback)} has been decoded by the
* {@link com.sdk.glide.load.ResourceDecoder}.
*
* <p> Note - this method will be run on a background thread so blocking I/O is safe. </p>
*/
void cleanup();
/**
* A method that will be called when a load is no longer relevant and has been cancelled. This
* method does not need to guarantee that any in process loads do not finish. It also may be
* called before a load starts or after it finishes.
*
* <p> The best way to use this method is to cancel any loads that have not yet started, but allow
* those that are in process to finish since its we typically will want to display the same
* resource in a different view in the near future. </p>
*
* <p> Note - this method will be run on the main thread so it should not perform blocking
* operations and should finish quickly. </p>
*/
void cancel();
/**
* Returns the class of the data this fetcher will attempt to obtain.
*/
@NonNull
Class<T> getDataClass();
/**
* Returns the {@link com.sdk.glide.load.DataSource} this fetcher will return data from.
*/
@NonNull
DataSource getDataSource();
}
package com.sdk.glide.load.data;
import android.support.annotation.NonNull;
import java.io.IOException;
/**
* Responsible for rewinding a stream like data types.
*
* @param <T> The stream like data type that can be rewound.
*/
public interface DataRewinder<T> {
/**
* A factory interface for producing individual
* {@link com.sdk.glide.load.data.DataRewinder}s.
*
* @param <T> The type of data that the {@link com.sdk.glide.load.data.DataRewinder} will
* wrap.
*/
interface Factory<T> {
/**
* Returns a new {@link com.sdk.glide.load.data.DataRewinder} wrapping the given data.
*/
@NonNull
DataRewinder<T> build(@NonNull T data);
/**
* Returns the class of data this factory can produce
* {@link com.sdk.glide.load.data.DataRewinder}s for.
*/
@NonNull
Class<T> getDataClass();
}
/**
* Rewinds the wrapped data back to the position it was at when this object was instantiated and
* returns the re-wound data (or a wrapper for the re-wound data).
*
* @return An object pointing to the wrapped data.
*/
@NonNull
T rewindAndGet() throws IOException;
/**
* Called when this rewinder is no longer needed and can be cleaned up.
*
* <p> The underlying data may still be in use and should not be closed or invalidated. </p>
*/
void cleanup();
}
package com.sdk.glide.load.data;
import android.support.annotation.NonNull;
import com.sdk.glide.util.Preconditions;
import java.util.HashMap;
import java.util.Map;
/**
* Stores a mapping of data class to {@link com.sdk.glide.load.data.DataRewinder.Factory} and
* allows registration of new types and factories.
*/
public class DataRewinderRegistry {
private final Map<Class<?>, DataRewinder.Factory<?>> rewinders = new HashMap<>();
private static final DataRewinder.Factory<?> DEFAULT_FACTORY =
new DataRewinder.Factory<Object>() {
@NonNull
@Override
public DataRewinder<Object> build(@NonNull Object data) {
return new DefaultRewinder(data);
}
@NonNull
@Override
public Class<Object> getDataClass() {
throw new UnsupportedOperationException("Not implemented");
}
};
public synchronized void register(@NonNull DataRewinder.Factory<?> factory) {
rewinders.put(factory.getDataClass(), factory);
}
@NonNull
@SuppressWarnings("unchecked")
public synchronized <T> DataRewinder<T> build(@NonNull T data) {
Preconditions.checkNotNull(data);
DataRewinder.Factory<T> result = (DataRewinder.Factory<T>) rewinders.get(data.getClass());
if (result == null) {
for (DataRewinder.Factory<?> registeredFactory : rewinders.values()) {
if (registeredFactory.getDataClass().isAssignableFrom(data.getClass())) {
result = (DataRewinder.Factory<T>) registeredFactory;
break;
}
}
}
if (result == null) {
result = (DataRewinder.Factory<T>) DEFAULT_FACTORY;
}
return result.build(data);
}
private static final class DefaultRewinder implements DataRewinder<Object> {
private final Object data;
DefaultRewinder(@NonNull Object data) {
this.data = data;
}
@NonNull
@Override
public Object rewindAndGet() {
return data;
}
@Override
public void cleanup() {
// Do nothing.
}
}
}
package com.sdk.glide.load.data;
import android.support.annotation.NonNull;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Adds an exif segment with an orientation attribute to a wrapped {@link InputStream} containing
* image data.
*
* <p>This class assumes that the wrapped stream contains an image format that can contain
* exif information and performs no verification. </p>
*/
public final class ExifOrientationStream extends FilterInputStream {
/** Allow two bytes for the file format. */
private static final int SEGMENT_START_POSITION = 2;
private static final byte[] EXIF_SEGMENT = new byte[] {
/* segment start id. */
(byte) 0xFF,
/* segment type. */
(byte) 0xE1,
/* segmentLength. */
0x00,
(byte) 0x1C,
/* exif identifier. */
0x45,
0x78,
0x69,
0x66,
0x00,
0x00,
/* motorola byte order (big endian). */
(byte) 0x4D,
(byte) 0x4D,
/* filler? */
0x00,
0x00,
/* first id offset. */
0x00,
0x00,
0x00,
0x08,
/* tagCount. */
0x00,
0x01,
/* exif tag type. */
0x01,
0x12,
/* 2 byte format. */
0x00,
0x02,
/* component count. */
0x00,
0x00,
0x00,
0x01,
/* 2 byte orientation value, the first byte of which is always 0. */
0x00,
};
private static final int SEGMENT_LENGTH = EXIF_SEGMENT.length;
private static final int ORIENTATION_POSITION = SEGMENT_LENGTH + SEGMENT_START_POSITION;
private final byte orientation;
private int position;
public ExifOrientationStream(InputStream in, int orientation) {
super(in);
if (orientation < -1 || orientation > 8) {
throw new IllegalArgumentException("Cannot add invalid orientation: " + orientation);
}
this.orientation = (byte) orientation;
}
@Override
public boolean markSupported() {
return false;
}
// No need for synchronized since all we do is throw.
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
@Override
public void mark(int readLimit) {
throw new UnsupportedOperationException();
}
@Override
public int read() throws IOException {
final int result;
if (position < SEGMENT_START_POSITION || position > ORIENTATION_POSITION) {
result = super.read();
} else if (position == ORIENTATION_POSITION) {
result = orientation;
} else {
result = EXIF_SEGMENT[position - SEGMENT_START_POSITION] & 0xFF;
}
if (result != -1) {
position++;
}
return result;
}
@Override
public int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException {
int read;
if (position > ORIENTATION_POSITION) {
read = super.read(buffer, byteOffset, byteCount);
} else if (position == ORIENTATION_POSITION) {
buffer[byteOffset] = orientation;
read = 1;
} else if (position < SEGMENT_START_POSITION) {
read = super.read(buffer, byteOffset, SEGMENT_START_POSITION - position);
} else {
read = Math.min(ORIENTATION_POSITION - position, byteCount);
System.arraycopy(EXIF_SEGMENT, position - SEGMENT_START_POSITION, buffer, byteOffset, read);
}
if (read > 0) {
position += read;
}
return read;
}
@Override
public long skip(long byteCount) throws IOException {
long skipped = super.skip(byteCount);
if (skipped > 0) {
// See http://errorprone.info/bugpattern/NarrowingCompoundAssignment.
position = (int) (position + skipped);
}
return skipped;
}
// No need for synchronized since all we do is throw.
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
@Override
public void reset() throws IOException {
throw new UnsupportedOperationException();
}
}
package com.sdk.glide.load.data;
import android.content.res.AssetManager;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import java.io.IOException;
/**
* Fetches an {@link android.os.ParcelFileDescriptor} for an asset path.
*/
public class FileDescriptorAssetPathFetcher extends AssetPathFetcher<ParcelFileDescriptor> {
public FileDescriptorAssetPathFetcher(AssetManager assetManager, String assetPath) {
super(assetManager, assetPath);
}
@Override
protected ParcelFileDescriptor loadResource(AssetManager assetManager, String path)
throws IOException {
return assetManager.openFd(path).getParcelFileDescriptor();
}
@Override
protected void close(ParcelFileDescriptor data) throws IOException {
data.close();
}
@NonNull
@Override
public Class<ParcelFileDescriptor> getDataClass() {
return ParcelFileDescriptor.class;
}
}
package com.sdk.glide.load.data;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Fetches an {@link android.os.ParcelFileDescriptor} for a local {@link android.net.Uri}.
*/
public class FileDescriptorLocalUriFetcher extends LocalUriFetcher<ParcelFileDescriptor> {
public FileDescriptorLocalUriFetcher(ContentResolver contentResolver, Uri uri) {
super(contentResolver, uri);
}
@Override
protected ParcelFileDescriptor loadResource(Uri uri, ContentResolver contentResolver)
throws FileNotFoundException {
AssetFileDescriptor assetFileDescriptor = contentResolver.openAssetFileDescriptor(uri, "r");
if (assetFileDescriptor == null) {
throw new FileNotFoundException("FileDescriptor is null for: " + uri);
}
return assetFileDescriptor.getParcelFileDescriptor();
}
@Override
protected void close(ParcelFileDescriptor data) throws IOException {
data.close();
}
@NonNull
@Override
public Class<ParcelFileDescriptor> getDataClass() {
return ParcelFileDescriptor.class;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment