删除依赖工程,直接引用在线包

This commit is contained in:
BA7LZD 2020-06-07 22:53:00 +08:00
parent 502d3ffe53
commit c3df1e1d75
377 changed files with 82 additions and 39101 deletions

View File

@ -4,8 +4,8 @@
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.6.1" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.6.1" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.6.3" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.6.3" />
</configuration>
</facet>
<facet type="android" name="Android">
@ -25,7 +25,7 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/classes" />
<exclude-output />
@ -103,45 +103,105 @@
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test.espresso:espresso-idling-resource:3.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout-solver:1.1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.material:material:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.7.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:retrofit:2.7.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.tencent.qcloud:cosxml:5.4.31@jar" level="project" />
<orderEntry type="library" name="Gradle: com.tencent.qcloud:qcloud-foundation:1.5.17@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:4.4.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp:okhttp:2.7.5@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:2.6.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.3.70@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.70@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.5@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:disklrucache:4.11.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:annotations:4.11.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.parse.bolts:bolts-tasks:1.4.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.ihsanbal:LoggingInterceptor:3.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.greenrobot:eventbus:3.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.navigation:navigation-ui:2.2.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.material:material:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.lzy.widget:ninegridview:0.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.sackcentury:shinebutton:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.wdullaer:materialdatetimepicker:4.2.3@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager2:viewpager2:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-extensions:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-extensions:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.navigation:navigation-fragment:2.2.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:4.11.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.chrisbanes.photoview:library:1.2.4@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v4:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.2.4@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.transition:transition:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:GSYVideoPlayer:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-java:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.andkulikov:transitionseverywhere:2.0.0-beta01@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.transition:transition:1.3.1@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.navigation:navigation-runtime:2.2.2@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.navigation:navigation-common:2.2.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:GSYVideoPlayer-exo2:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: tv.danmaku.ijk.media:ijkplayer-exo:0.8.8@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer-ui:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.media:media:1.0.1@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-process:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-service:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-process:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-service:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:gifdecoder:4.11.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.exifinterface:exifinterface:1.3.0-alpha01@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.documentfile:documentfile:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.print:print:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout:1.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-base:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: tv.danmaku.ijk.media:ijkplayer-java:0.8.8@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer-core:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer-dash:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer-hls:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:exoplayer-smoothstreaming:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyvideoplayer-androidvideocache:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.exoplayer:extension-rtmp:2.11.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-armv5:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-armv7a:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-arm64:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-x64:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.shuyu:gsyVideoPlayer-x86:7.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.gyf.immersionbar:immersionbar:3.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.gyf.immersionbar:immersionbar-components:3.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: de.hdodenhof:circleimageview:3.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.lcodecorex:tkrefreshlayout:1.0.7@aar" level="project" />
<orderEntry type="library" name="Gradle: com.tencent.qcloud:logUtils:5.4.31@aar" level="project" />
<orderEntry type="library" name="Gradle: com.daasuu:EasingInterpolator:1.3.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.blankj:utilcodex:1.28.4@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.LuckSiege.PictureSelector:picture_library:v2.5.6@aar" level="project" />
<orderEntry type="library" name="Gradle: com.github.LuckSiege.PictureSelector:ucrop:v2.5.6@aar" level="project" />
</component>
</module>

View File

@ -2,7 +2,6 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 29
ndkVersion "21.1.6352462"
buildToolsVersion "29.0.3"
defaultConfig {
@ -75,10 +74,9 @@ dependencies {
//RecyclerView
//implementation 'com.lovejjfg.powerrecycle:powerrecycle:2.0.0'
//
//implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.5.6'
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.5.6'
//
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':picture_library')
}

View File

@ -1 +0,0 @@
/build

View File

@ -1,36 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion cfgs.compileSdkVersion
defaultConfig {
minSdkVersion cfgs.minSdkVersion
targetSdkVersion cfgs.targetSdkVersion
versionCode cfgs.versionCode
versionName cfgs.versionName
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:${cfgs.version_appcompat}"
implementation "androidx.recyclerview:recyclerview:${cfgs.version_recyclerview}"
implementation "androidx.concurrent:concurrent-futures:${cfgs.futures_version}"
implementation "com.squareup.okio:okio:${cfgs.okio_version}"
implementation "androidx.camera:camera-lifecycle:${cfgs.camerax_version}"
implementation "androidx.localbroadcastmanager:localbroadcastmanager:${cfgs.localbroadcastmanager}"
implementation "androidx.camera:camera-view:${cfgs.camerax_view}"
api project(':ucrop')
}

View File

@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/luck/Documents/android-sdk-macosx-2/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.luck.picture.lib">
<uses-sdk tools:overrideLibrary="androidx.camera.view,
androidx.camera:camera-camera2,
androidx.camera.camera2,androidx.camera.lifecycle,
androidx.camera.core" />
<application>
<provider
android:name="com.luck.picture.lib.PictureFileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity
android:name=".PictureSelectorActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PictureSelectorWeChatStyleActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PictureSelectorCameraEmptyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/Picture.Theme.Translucent" />
<activity
android:name=".PictureCustomCameraActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PicturePreviewActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PictureSelectorPreviewWeChatStyleActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PictureVideoPlayActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="sensor" />
<activity
android:name=".PictureExternalPreviewActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".PicturePlayAudioActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:theme="@style/Base.Theme.NoActionBar" />
<activity
android:name="com.yalantis.ucrop.PictureMultiCuttingActivity"
android:theme="@style/Base.Theme.NoActionBar" />
</application>
</manifest>

View File

@ -1,23 +0,0 @@
package com.luck.picture.lib;
import android.content.Context;
import android.content.ContextWrapper;
import com.luck.picture.lib.language.PictureLanguageUtils;
/**
* @authorluck
* @date2019-12-15 19:34
* @describeContextWrapper
*/
public class PictureContextWrapper extends ContextWrapper {
public PictureContextWrapper(Context base) {
super(base);
}
public static ContextWrapper wrap(Context context, int language) {
PictureLanguageUtils.setAppLanguage(context, language);
return new PictureContextWrapper(context);
}
}

View File

@ -1,286 +0,0 @@
package com.luck.picture.lib;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.CameraX;
import androidx.camera.view.CameraView;
import com.luck.picture.lib.camera.CustomCameraView;
import com.luck.picture.lib.camera.listener.CameraListener;
import com.luck.picture.lib.camera.view.CaptureLayout;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.dialog.PictureCustomDialog;
import com.luck.picture.lib.permissions.PermissionChecker;
import java.io.File;
import java.lang.ref.WeakReference;
/**
* @authorluck
* @date2020-01-04 14:05
* @describeCustom photos and videos
*/
public class PictureCustomCameraActivity extends PictureSelectorCameraEmptyActivity {
private final static String TAG = PictureCustomCameraActivity.class.getSimpleName();
private CustomCameraView mCameraView;
protected boolean isEnterSetting;
@Override
public boolean isImmersive() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(lp);
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
// 验证存储权限
boolean isExternalStorage = PermissionChecker
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
PermissionChecker
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (!isExternalStorage) {
PermissionChecker.requestPermissions(this, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
return;
}
// 验证相机权限和麦克风权限
if (PermissionChecker
.checkSelfPermission(this, Manifest.permission.CAMERA)) {
boolean isRecordAudio = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
if (isRecordAudio) {
createCameraView();
} else {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
}
} else {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
}
}
/**
* 创建CameraView
*/
private void createCameraView() {
if (mCameraView == null) {
mCameraView = new CustomCameraView(getContext());
setContentView(mCameraView);
initView();
}
}
@Override
protected void onResume() {
super.onResume();
// 这里只针对权限被手动拒绝后进入设置页面重新获取权限后的操作
if (isEnterSetting) {
boolean isExternalStorage = PermissionChecker
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
PermissionChecker
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (isExternalStorage) {
boolean isCameraPermissionChecker = PermissionChecker
.checkSelfPermission(this, Manifest.permission.CAMERA);
if (isCameraPermissionChecker) {
boolean isRecordAudio = PermissionChecker
.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
if (isRecordAudio) {
createCameraView();
} else {
showPermissionsDialog(false, getString(R.string.picture_audio));
}
} else {
showPermissionsDialog(false, getString(R.string.picture_camera));
}
} else {
showPermissionsDialog(false, getString(R.string.picture_jurisdiction));
}
isEnterSetting = false;
}
}
/**
* 初始化控件
*/
protected void initView() {
mCameraView.setPictureSelectionConfig(config);
// 绑定生命周期
mCameraView.setBindToLifecycle(new WeakReference<>(this).get());
// 视频最大拍摄时长
if (config.recordVideoSecond > 0) {
mCameraView.setRecordVideoMaxTime(config.recordVideoSecond);
}
// 视频最小拍摄时长
if (config.recordVideoMinSecond > 0) {
mCameraView.setRecordVideoMinTime(config.recordVideoMinSecond);
}
// 获取CameraView
CameraView cameraView = mCameraView.getCameraView();
if (cameraView != null && config.isCameraAroundState) {
cameraView.toggleCamera();
}
// 获取录制按钮
CaptureLayout captureLayout = mCameraView.getCaptureLayout();
if (captureLayout != null) {
captureLayout.setButtonFeatures(config.buttonFeatures);
}
// 拍照预览
mCameraView.setImageCallbackListener((file, imageView) -> {
if (config != null && PictureSelectionConfig.imageEngine != null && file != null) {
PictureSelectionConfig.imageEngine.loadImage(getContext(), file.getAbsolutePath(), imageView);
}
});
// 设置拍照或拍视频回调监听
mCameraView.setCameraListener(new CameraListener() {
@Override
public void onPictureSuccess(@NonNull File file) {
config.cameraMimeType = PictureMimeType.ofImage();
Intent intent = new Intent();
intent.putExtra(PictureConfig.EXTRA_MEDIA_PATH, file.getAbsolutePath());
intent.putExtra(PictureConfig.EXTRA_CONFIG, config);
if (config.camera) {
dispatchHandleCamera(intent);
} else {
setResult(RESULT_OK, intent);
onBackPressed();
}
}
@Override
public void onRecordSuccess(@NonNull File file) {
config.cameraMimeType = PictureMimeType.ofVideo();
Intent intent = new Intent();
intent.putExtra(PictureConfig.EXTRA_MEDIA_PATH, file.getAbsolutePath());
intent.putExtra(PictureConfig.EXTRA_CONFIG, config);
if (config.camera) {
dispatchHandleCamera(intent);
} else {
setResult(RESULT_OK, intent);
onBackPressed();
}
}
@Override
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
Log.i(TAG, "onError: " + message);
}
});
//左边按钮点击事件
mCameraView.setOnClickListener(() -> onBackPressed());
}
@Override
public void onBackPressed() {
if (config != null && config.camera && PictureSelectionConfig.listener != null) {
PictureSelectionConfig.listener.onCancel();
}
closeActivity();
}
@SuppressLint("RestrictedApi")
@Override
protected void onDestroy() {
if (mCameraView != null) {
CameraX.unbindAll();
mCameraView = null;
}
super.onDestroy();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
// 存储权限
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
} else {
showPermissionsDialog(true, getString(R.string.picture_jurisdiction));
}
break;
case PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE:
// 相机权限
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
boolean isRecordAudio = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
if (isRecordAudio) {
createCameraView();
} else {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
}
} else {
showPermissionsDialog(true, getString(R.string.picture_camera));
}
break;
case PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE:
// 录音权限
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
createCameraView();
} else {
showPermissionsDialog(false, getString(R.string.picture_audio));
}
break;
}
}
@Override
protected void showPermissionsDialog(boolean isCamera, String errorMsg) {
if (isFinishing()) {
return;
}
final PictureCustomDialog dialog =
new PictureCustomDialog(getContext(), R.layout.picture_wind_base_dialog);
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
Button btn_cancel = dialog.findViewById(R.id.btn_cancel);
Button btn_commit = dialog.findViewById(R.id.btn_commit);
btn_commit.setText(getString(R.string.picture_go_setting));
TextView tvTitle = dialog.findViewById(R.id.tvTitle);
TextView tv_content = dialog.findViewById(R.id.tv_content);
tvTitle.setText(getString(R.string.picture_prompt));
tv_content.setText(errorMsg);
btn_cancel.setOnClickListener(v -> {
if (!isFinishing()) {
dialog.dismiss();
}
closeActivity();
});
btn_commit.setOnClickListener(v -> {
if (!isFinishing()) {
dialog.dismiss();
}
PermissionChecker.launchAppDetailsSettings(getContext());
isEnterSetting = true;
});
dialog.show();
}
}

View File

@ -1,640 +0,0 @@
package com.luck.picture.lib;
import android.Manifest;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.luck.picture.lib.broadcast.BroadcastAction;
import com.luck.picture.lib.broadcast.BroadcastManager;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.dialog.PictureCustomDialog;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.listener.OnImageCompleteCallback;
import com.luck.picture.lib.permissions.PermissionChecker;
import com.luck.picture.lib.photoview.PhotoView;
import com.luck.picture.lib.thread.PictureThreadUtils;
import com.luck.picture.lib.tools.AttrsUtils;
import com.luck.picture.lib.tools.DateUtils;
import com.luck.picture.lib.tools.JumpUtils;
import com.luck.picture.lib.tools.MediaUtils;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.ToastUtils;
import com.luck.picture.lib.tools.ValueOf;
import com.luck.picture.lib.widget.PreviewViewPager;
import com.luck.picture.lib.widget.longimage.ImageSource;
import com.luck.picture.lib.widget.longimage.ImageViewState;
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import okio.BufferedSource;
import okio.Okio;
/**
* @authorluck
* @data2017/01/18 下午1:00
* @描述: 预览图片
*/
public class PictureExternalPreviewActivity extends PictureBaseActivity implements View.OnClickListener {
private ImageButton ibLeftBack;
private TextView tvTitle;
private PreviewViewPager viewPager;
private List<LocalMedia> images = new ArrayList<>();
private int position = 0;
private SimpleFragmentAdapter adapter;
private String downloadPath;
private String mMimeType;
private ImageButton ibDelete;
private View titleViewBg;
@Override
public int getResourceId() {
return R.layout.picture_activity_external_preview;
}
@Override
protected void initWidgets() {
super.initWidgets();
titleViewBg = findViewById(R.id.titleViewBg);
tvTitle = findViewById(R.id.picture_title);
ibLeftBack = findViewById(R.id.left_back);
ibDelete = findViewById(R.id.ib_delete);
viewPager = findViewById(R.id.preview_pager);
position = getIntent().getIntExtra(PictureConfig.EXTRA_POSITION, 0);
images = (List<LocalMedia>) getIntent().getSerializableExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST);
ibLeftBack.setOnClickListener(this);
ibDelete.setOnClickListener(this);
ibDelete.setVisibility(config.style != null ? config.style.pictureExternalPreviewGonePreviewDelete
? View.VISIBLE : View.GONE : View.GONE);
initViewPageAdapterData();
}
/**
* 设置样式
*/
@Override
public void initPictureSelectorStyle() {
if (config.style != null) {
if (config.style.pictureTitleTextColor != 0) {
tvTitle.setTextColor(config.style.pictureTitleTextColor);
}
if (config.style.pictureTitleTextSize != 0) {
tvTitle.setTextSize(config.style.pictureTitleTextSize);
}
if (config.style.pictureLeftBackIcon != 0) {
ibLeftBack.setImageResource(config.style.pictureLeftBackIcon);
}
if (config.style.pictureExternalPreviewDeleteStyle != 0) {
ibDelete.setImageResource(config.style.pictureExternalPreviewDeleteStyle);
}
if (config.style.pictureTitleBarBackgroundColor != 0) {
titleViewBg.setBackgroundColor(colorPrimary);
}
} else {
int previewBgColor = AttrsUtils.getTypeValueColor(getContext(), R.attr.picture_ac_preview_title_bg);
if (previewBgColor != 0) {
titleViewBg.setBackgroundColor(previewBgColor);
} else {
titleViewBg.setBackgroundColor(colorPrimary);
}
}
}
private void initViewPageAdapterData() {
tvTitle.setText(getString(R.string.picture_preview_image_num,
position + 1, images.size()));
adapter = new SimpleFragmentAdapter();
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(position);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int index) {
tvTitle.setText(getString(R.string.picture_preview_image_num,
index + 1, images.size()));
position = index;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.left_back) {
finish();
exitAnimation();
} else if (id == R.id.ib_delete) {
if (images != null && images.size() > 0) {
int currentItem = viewPager.getCurrentItem();
images.remove(currentItem);
adapter.removeCacheView(currentItem);
// 删除通知用户更新
Bundle bundle = new Bundle();
bundle.putInt(PictureConfig.EXTRA_PREVIEW_DELETE_POSITION, currentItem);
BroadcastManager.getInstance(getContext())
.action(BroadcastAction.ACTION_DELETE_PREVIEW_POSITION)
.extras(bundle).broadcast();
if (images.size() == 0) {
onBackPressed();
return;
}
tvTitle.setText(getString(R.string.picture_preview_image_num,
position + 1, images.size()));
position = currentItem;
adapter.notifyDataSetChanged();
}
}
}
public class SimpleFragmentAdapter extends PagerAdapter {
/**
* 最大缓存图片数量
*/
private static final int MAX_CACHE_SIZE = 20;
/**
* 缓存view
*/
private SparseArray<View> mCacheView;
private void clear() {
if (null != mCacheView) {
mCacheView.clear();
mCacheView = null;
}
}
public void removeCacheView(int position) {
if (mCacheView != null && position < mCacheView.size()) {
mCacheView.removeAt(position);
}
}
public SimpleFragmentAdapter() {
super();
this.mCacheView = new SparseArray<>();
}
@Override
public int getCount() {
return images != null ? images.size() : 0;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
(container).removeView((View) object);
if (mCacheView.size() > MAX_CACHE_SIZE) {
mCacheView.remove(position);
}
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View contentView = mCacheView.get(position);
if (contentView == null) {
contentView = LayoutInflater.from(container.getContext())
.inflate(R.layout.picture_image_preview, container, false);
mCacheView.put(position, contentView);
}
// 常规图控件
final PhotoView imageView = contentView.findViewById(R.id.preview_image);
// 长图控件
final SubsamplingScaleImageView longImageView = contentView.findViewById(R.id.longImg);
// 视频播放按钮
ImageView ivPlay = contentView.findViewById(R.id.iv_play);
LocalMedia media = images.get(position);
if (media != null) {
final String path;
if (media.isCut() && !media.isCompressed()) {
// 裁剪过
path = media.getCutPath();
} else if (media.isCompressed() || (media.isCut() && media.isCompressed())) {
// 压缩过,或者裁剪同时压缩过,以最终压缩过图片为准
path = media.getCompressPath();
} else if (!TextUtils.isEmpty(media.getAndroidQToPath())) {
// AndroidQ特有path
path = media.getAndroidQToPath();
} else {
// 原图
path = media.getPath();
}
boolean isHttp = PictureMimeType.isHasHttp(path);
String mimeType = isHttp ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
ivPlay.setVisibility(isHasVideo ? View.VISIBLE : View.GONE);
boolean isGif = PictureMimeType.isGif(mimeType);
boolean eqLongImg = MediaUtils.isLongImg(media);
imageView.setVisibility(eqLongImg && !isGif ? View.GONE : View.VISIBLE);
longImageView.setVisibility(eqLongImg && !isGif ? View.VISIBLE : View.GONE);
// 压缩过的gif就不是gif了
if (isGif && !media.isCompressed()) {
if (config != null && PictureSelectionConfig.imageEngine != null) {
PictureSelectionConfig.imageEngine.loadAsGifImage
(getContext(), path, imageView);
}
} else {
if (config != null && PictureSelectionConfig.imageEngine != null) {
if (isHttp) {
// 网络图片
PictureSelectionConfig.imageEngine.loadImage(contentView.getContext(), path,
imageView, longImageView, new OnImageCompleteCallback() {
@Override
public void onShowLoading() {
showPleaseDialog();
}
@Override
public void onHideLoading() {
dismissDialog();
}
});
} else {
if (eqLongImg) {
displayLongPic(PictureMimeType.isContent(path)
? Uri.parse(path) : Uri.fromFile(new File(path)), longImageView);
} else {
PictureSelectionConfig.imageEngine.loadImage(contentView.getContext(), path, imageView);
}
}
}
}
imageView.setOnViewTapListener((view, x, y) -> {
finish();
exitAnimation();
});
longImageView.setOnClickListener(v -> {
finish();
exitAnimation();
});
if (!isHasVideo) {
longImageView.setOnLongClickListener(v -> {
if (config.isNotPreviewDownload) {
if (PermissionChecker.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
downloadPath = path;
String currentMimeType = PictureMimeType.isHasHttp(path) ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
mMimeType = PictureMimeType.isJPG(currentMimeType) ? PictureMimeType.MIME_TYPE_JPEG : currentMimeType;
showDownLoadDialog();
} else {
PermissionChecker.requestPermissions(PictureExternalPreviewActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
}
}
return true;
});
}
if (!isHasVideo) {
imageView.setOnLongClickListener(v -> {
if (config.isNotPreviewDownload) {
if (PermissionChecker.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
downloadPath = path;
String currentMimeType = PictureMimeType.isHasHttp(path) ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
mMimeType = PictureMimeType.isJPG(currentMimeType) ? PictureMimeType.MIME_TYPE_JPEG : currentMimeType;
showDownLoadDialog();
} else {
PermissionChecker.requestPermissions(PictureExternalPreviewActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
}
}
return true;
});
}
ivPlay.setOnClickListener(v -> {
if (PictureSelectionConfig.customVideoPlayCallback != null) {
PictureSelectionConfig.customVideoPlayCallback.startPlayVideo(media);
} else {
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString(PictureConfig.EXTRA_VIDEO_PATH, path);
intent.putExtras(bundle);
JumpUtils.startPictureVideoPlayActivity(container.getContext(), bundle, PictureConfig.PREVIEW_VIDEO_CODE);
}
});
}
(container).addView(contentView, 0);
return contentView;
}
}
/**
* 加载长图
*
* @param uri
* @param longImg
*/
private void displayLongPic(Uri uri, SubsamplingScaleImageView longImg) {
longImg.setQuickScaleEnabled(true);
longImg.setZoomEnabled(true);
longImg.setPanEnabled(true);
longImg.setDoubleTapZoomDuration(100);
longImg.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
longImg.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
longImg.setImage(ImageSource.uri(uri), new ImageViewState(0, new PointF(0, 0), 0));
}
/**
* 下载图片提示
*/
private void showDownLoadDialog() {
if (!isFinishing() && !TextUtils.isEmpty(downloadPath)) {
final PictureCustomDialog dialog =
new PictureCustomDialog(getContext(), R.layout.picture_wind_base_dialog);
Button btn_cancel = dialog.findViewById(R.id.btn_cancel);
Button btn_commit = dialog.findViewById(R.id.btn_commit);
TextView tvTitle = dialog.findViewById(R.id.tvTitle);
TextView tv_content = dialog.findViewById(R.id.tv_content);
tvTitle.setText(getString(R.string.picture_prompt));
tv_content.setText(getString(R.string.picture_prompt_content));
btn_cancel.setOnClickListener(v -> {
if (!isFinishing()) {
dialog.dismiss();
}
});
btn_commit.setOnClickListener(view -> {
boolean isHttp = PictureMimeType.isHasHttp(downloadPath);
showPleaseDialog();
if (isHttp) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<String>() {
@Override
public String doInBackground() {
return showLoadingImage(downloadPath);
}
@Override
public void onSuccess(String result) {
onSuccessful(result);
}
});
} else {
// 有可能本地图片
try {
if (PictureMimeType.isContent(downloadPath)) {
savePictureAlbumAndroidQ(PictureMimeType.isContent(downloadPath) ? Uri.parse(downloadPath) : Uri.fromFile(new File(downloadPath)));
} else {
// 把文件插入到系统图库
savePictureAlbum();
}
} catch (Exception e) {
ToastUtils.s(getContext(), getString(R.string.picture_save_error) + "\n" + e.getMessage());
dismissDialog();
e.printStackTrace();
}
}
if (!isFinishing()) {
dialog.dismiss();
}
});
dialog.show();
}
}
/**
* 保存相片至本地相册
*
* @throws Exception
*/
private void savePictureAlbum() throws Exception {
String suffix = PictureMimeType.getLastImgSuffix(mMimeType);
String state = Environment.getExternalStorageState();
File rootDir = state.equals(Environment.MEDIA_MOUNTED)
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
: getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (rootDir != null && !rootDir.exists() && rootDir.mkdirs()) {
}
File folderDir = new File(SdkVersionUtils.checkedAndroid_Q() || !state.equals(Environment.MEDIA_MOUNTED)
? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + PictureMimeType.CAMERA + File.separator);
if (folderDir != null && !folderDir.exists() && folderDir.mkdirs()) {
}
String fileName = DateUtils.getCreateFileName("IMG_") + suffix;
File file = new File(folderDir, fileName);
PictureFileUtils.copyFile(downloadPath, file.getAbsolutePath());
onSuccessful(file.getAbsolutePath());
}
/**
* 图片保存成功
*
* @param result
*/
private void onSuccessful(String result) {
dismissDialog();
if (!TextUtils.isEmpty(result)) {
try {
if (!SdkVersionUtils.checkedAndroid_Q()) {
File file = new File(result);
MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), null);
new PictureMediaScannerConnection(getContext(), file.getAbsolutePath(), () -> {
});
}
ToastUtils.s(getContext(), getString(R.string.picture_save_success) + "\n" + result);
} catch (Exception e) {
e.printStackTrace();
}
} else {
ToastUtils.s(getContext(), getString(R.string.picture_save_error));
}
}
/**
* 保存图片到picture 目录Android Q适配最简单的做法就是保存到公共目录不用SAF存储
*
* @param inputUri
*/
private void savePictureAlbumAndroidQ(Uri inputUri) {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_"));
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis()));
contentValues.put(MediaStore.Images.Media.MIME_TYPE, mMimeType);
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM);
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
if (uri == null) {
ToastUtils.s(getContext(), getString(R.string.picture_save_error));
return;
}
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<String>() {
@Override
public String doInBackground() {
BufferedSource buffer = null;
try {
buffer = Okio.buffer(Okio.source(Objects.requireNonNull(getContentResolver().openInputStream(inputUri))));
OutputStream outputStream = getContentResolver().openOutputStream(uri);
boolean bufferCopy = PictureFileUtils.bufferCopy(buffer, outputStream);
if (bufferCopy) {
return PictureFileUtils.getPath(getContext(), uri);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (buffer != null && buffer.isOpen()) {
PictureFileUtils.close(buffer);
}
}
return "";
}
@Override
public void onSuccess(String result) {
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
onSuccessful(result);
}
});
}
/**
* 针对Q版本创建uri
*
* @return
*/
private Uri createOutImageUri() {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_"));
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis()));
contentValues.put(MediaStore.Images.Media.MIME_TYPE, mMimeType);
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM);
return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
}
// 下载图片保存至手机
public String showLoadingImage(String urlPath) {
Uri outImageUri = null;
OutputStream outputStream = null;
InputStream inputStream = null;
BufferedSource inBuffer = null;
try {
if (SdkVersionUtils.checkedAndroid_Q()) {
outImageUri = createOutImageUri();
} else {
String suffix = PictureMimeType.getLastImgSuffix(mMimeType);
String state = Environment.getExternalStorageState();
File rootDir =
state.equals(Environment.MEDIA_MOUNTED)
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
: getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (rootDir != null) {
if (!rootDir.exists()) {
rootDir.mkdirs();
}
File folderDir = new File(!state.equals(Environment.MEDIA_MOUNTED)
? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + PictureMimeType.CAMERA + File.separator);
if (!folderDir.exists() && folderDir.mkdirs()) {
}
String fileName = DateUtils.getCreateFileName("IMG_") + suffix;
File file = new File(folderDir, fileName);
outImageUri = Uri.fromFile(file);
}
}
if (outImageUri != null) {
outputStream = Objects.requireNonNull(getContentResolver().openOutputStream(outImageUri));
URL u = new URL(urlPath);
inputStream = u.openStream();
inBuffer = Okio.buffer(Okio.source(inputStream));
boolean bufferCopy = PictureFileUtils.bufferCopy(inBuffer, outputStream);
if (bufferCopy) {
return PictureFileUtils.getPath(this, outImageUri);
}
}
} catch (Exception e) {
if (outImageUri != null && SdkVersionUtils.checkedAndroid_Q()) {
getContentResolver().delete(outImageUri, null, null);
}
} finally {
PictureFileUtils.close(inputStream);
PictureFileUtils.close(outputStream);
PictureFileUtils.close(inBuffer);
}
return null;
}
@Override
public void onBackPressed() {
super.onBackPressed();
finish();
exitAnimation();
}
private void exitAnimation() {
overridePendingTransition(R.anim.picture_anim_fade_in, config.windowAnimationStyle != null
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0
? config.windowAnimationStyle.activityPreviewExitAnimation : R.anim.picture_anim_exit);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (adapter != null) {
adapter.clear();
}
if (PictureSelectionConfig.customVideoPlayCallback != null) {
PictureSelectionConfig.customVideoPlayCallback = null;
}
if (PictureSelectionConfig.onCustomCameraInterfaceListener != null) {
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
// 存储权限
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
showDownLoadDialog();
} else {
ToastUtils.s(getContext(), getString(R.string.picture_jurisdiction));
}
}
break;
}
}
}

View File

@ -1,12 +0,0 @@
package com.luck.picture.lib;
import androidx.core.content.FileProvider;
/**
* @authorluck
* @data2016/3/28 下午2:00
* @描述: 自定义FileProvider 解决FileProvider冲突问题
*/
public class PictureFileProvider extends FileProvider {
}

View File

@ -1,49 +0,0 @@
package com.luck.picture.lib;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.text.TextUtils;
/**
* @authorluck
* @date2019-12-03 10:41
* @describe刷新相册
*/
public class PictureMediaScannerConnection implements MediaScannerConnection.MediaScannerConnectionClient {
public interface ScanListener {
void onScanFinish();
}
private MediaScannerConnection mMs;
private String mPath;
private ScanListener mListener;
public PictureMediaScannerConnection(Context context, String path, ScanListener l) {
this.mListener = l;
this.mPath = path;
this.mMs = new MediaScannerConnection(context.getApplicationContext(), this);
this.mMs.connect();
}
public PictureMediaScannerConnection(Context context, String path) {
this.mPath = path;
this.mMs = new MediaScannerConnection(context.getApplicationContext(), this);
this.mMs.connect();
}
@Override
public void onMediaScannerConnected() {
if (!TextUtils.isEmpty(mPath)) {
mMs.scanFile(mPath, null);
}
}
@Override
public void onScanCompleted(String path, Uri uri) {
mMs.disconnect();
if (mListener != null) {
mListener.onScanFinish();
}
}
}

View File

@ -1,211 +0,0 @@
package com.luck.picture.lib;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.TextView;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.tools.DateUtils;
/**
* # No longer maintain audio related functions,
* but can continue to use but there will be phone compatibility issues.
* <p>
* 不再维护音频相关功能但可以继续使用但会有机型兼容性问题
*/
@Deprecated
public class PicturePlayAudioActivity extends PictureBaseActivity implements View.OnClickListener {
private String audio_path;
private MediaPlayer mediaPlayer;
private SeekBar musicSeekBar;
private boolean isPlayAudio = false;
private TextView tv_PlayPause, tv_Stop, tv_Quit,
tv_musicStatus, tv_musicTotal, tv_musicTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
}
@Override
public int getResourceId() {
return R.layout.picture_play_audio;
}
@Override
protected void initWidgets() {
super.initWidgets();
audio_path = getIntent().getStringExtra(PictureConfig.EXTRA_AUDIO_PATH);
tv_musicStatus = findViewById(R.id.tv_musicStatus);
tv_musicTime = findViewById(R.id.tv_musicTime);
musicSeekBar = findViewById(R.id.musicSeekBar);
tv_musicTotal = findViewById(R.id.tv_musicTotal);
tv_PlayPause = findViewById(R.id.tv_PlayPause);
tv_Stop = findViewById(R.id.tv_Stop);
tv_Quit = findViewById(R.id.tv_Quit);
handler.postDelayed(() -> initPlayer(audio_path), 30);
tv_PlayPause.setOnClickListener(this);
tv_Stop.setOnClickListener(this);
tv_Quit.setOnClickListener(this);
musicSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mediaPlayer.seekTo(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
// 通过 Handler 更新 UI 上的组件状态
public Handler handler = new Handler();
public Runnable runnable = new Runnable() {
@Override
public void run() {
try {
if (mediaPlayer != null) {
tv_musicTime.setText(DateUtils.formatDurationTime(mediaPlayer.getCurrentPosition()));
musicSeekBar.setProgress(mediaPlayer.getCurrentPosition());
musicSeekBar.setMax(mediaPlayer.getDuration());
tv_musicTotal.setText(DateUtils.formatDurationTime(mediaPlayer.getDuration()));
handler.postDelayed(runnable, 200);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
/**
* 初始化音频播放组件
*
* @param path
*/
private void initPlayer(String path) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.setLooping(true);
playAudio();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.tv_PlayPause) {
playAudio();
}
if (i == R.id.tv_Stop) {
tv_musicStatus.setText(getString(R.string.picture_stop_audio));
tv_PlayPause.setText(getString(R.string.picture_play_audio));
stop(audio_path);
}
if (i == R.id.tv_Quit) {
handler.removeCallbacks(runnable);
new Handler().postDelayed(() -> stop(audio_path), 30);
try {
closeActivity();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 播放音频
*/
private void playAudio() {
if (mediaPlayer != null) {
musicSeekBar.setProgress(mediaPlayer.getCurrentPosition());
musicSeekBar.setMax(mediaPlayer.getDuration());
}
String ppStr = tv_PlayPause.getText().toString();
if (ppStr.equals(getString(R.string.picture_play_audio))) {
tv_PlayPause.setText(getString(R.string.picture_pause_audio));
tv_musicStatus.setText(getString(R.string.picture_play_audio));
playOrPause();
} else {
tv_PlayPause.setText(getString(R.string.picture_play_audio));
tv_musicStatus.setText(getString(R.string.picture_pause_audio));
playOrPause();
}
if (!isPlayAudio) {
handler.post(runnable);
isPlayAudio = true;
}
}
/**
* 停止播放
*
* @param path
*/
public void stop(String path) {
if (mediaPlayer != null) {
try {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 暂停播放
*/
public void playOrPause() {
try {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
closeActivity();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null && handler != null) {
handler.removeCallbacks(runnable);
mediaPlayer.release();
mediaPlayer = null;
}
}
}

View File

@ -1,244 +0,0 @@
package com.luck.picture.lib;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.style.PictureParameterStyle;
import com.luck.picture.lib.tools.DoubleUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2017-5-24 22:30
* @describePictureSelector
*/
public final class PictureSelector {
private final WeakReference<Activity> mActivity;
private final WeakReference<Fragment> mFragment;
private PictureSelector(Activity activity) {
this(activity, null);
}
private PictureSelector(Fragment fragment) {
this(fragment.getActivity(), fragment);
}
private PictureSelector(Activity activity, Fragment fragment) {
mActivity = new WeakReference<>(activity);
mFragment = new WeakReference<>(fragment);
}
/**
* Start PictureSelector for Activity.
*
* @param activity
* @return PictureSelector instance.
*/
public static PictureSelector create(Activity activity) {
return new PictureSelector(activity);
}
/**
* Start PictureSelector for Fragment.
*
* @param fragment
* @return PictureSelector instance.
*/
public static PictureSelector create(Fragment fragment) {
return new PictureSelector(fragment);
}
/**
* @param chooseMode Select the type of picture you wantall or Picture or Video .
* @return LocalMedia PictureSelectionModel
* Use {@link PictureMimeType.ofAll(),ofImage(),ofVideo(),ofAudio()}.
*/
public PictureSelectionModel openGallery(int chooseMode) {
return new PictureSelectionModel(this, chooseMode);
}
/**
* @param chooseMode Select the type of picture you wantPicture or Video.
* @return LocalMedia PictureSelectionModel
* Use {@link PictureMimeType.ofImage(),ofVideo()}.
*/
public PictureSelectionModel openCamera(int chooseMode) {
return new PictureSelectionModel(this, chooseMode, true);
}
/**
* 外部预览时设置样式
*
* @param themeStyle
* @return
*/
public PictureSelectionModel themeStyle(int themeStyle) {
return new PictureSelectionModel(this, PictureMimeType.ofImage())
.theme(themeStyle);
}
/**
* 外部预览时动态代码设置样式
*
* @param style
* @return
*/
public PictureSelectionModel setPictureStyle(PictureParameterStyle style) {
return new PictureSelectionModel(this, PictureMimeType.ofImage())
.setPictureStyle(style);
}
/**
* @param data
* @return Selector Multiple LocalMedia
*/
public static List<LocalMedia> obtainMultipleResult(Intent data) {
if (data != null) {
List<LocalMedia> result = data.getParcelableArrayListExtra(PictureConfig.EXTRA_RESULT_SELECTION);
return result == null ? new ArrayList<>() : result;
}
return new ArrayList<>();
}
/**
* @param data
* @return Put image Intent Data
*/
public static Intent putIntentResult(List<LocalMedia> data) {
return new Intent().putParcelableArrayListExtra(PictureConfig.EXTRA_RESULT_SELECTION,
(ArrayList<? extends Parcelable>) data);
}
/**
* @param bundle
* @return get Selector LocalMedia
*/
public static List<LocalMedia> obtainSelectorList(Bundle bundle) {
if (bundle != null) {
List<LocalMedia> selectionMedias = bundle.getParcelableArrayList(PictureConfig.EXTRA_SELECT_LIST);
return selectionMedias == null ? new ArrayList<>() : selectionMedias;
}
return new ArrayList<>();
}
/**
* @param selectedImages
* @return put Selector LocalMedia
*/
public static void saveSelectorList(Bundle outState, List<LocalMedia> selectedImages) {
outState.putParcelableArrayList(PictureConfig.EXTRA_SELECT_LIST,
(ArrayList<? extends Parcelable>) selectedImages);
}
/**
* set preview image
*
* @param position
* @param medias
*/
public void externalPicturePreview(int position, List<LocalMedia> medias, int enterAnimation) {
if (!DoubleUtils.isFastDoubleClick()) {
if (getActivity() != null) {
Intent intent = new Intent(getActivity(), PictureExternalPreviewActivity.class);
intent.putParcelableArrayListExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST,
(ArrayList<? extends Parcelable>) medias);
intent.putExtra(PictureConfig.EXTRA_POSITION, position);
getActivity().startActivity(intent);
getActivity().overridePendingTransition(enterAnimation != 0
? enterAnimation : R.anim.picture_anim_enter, R.anim.picture_anim_fade_in);
} else {
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
}
}
}
/**
* set preview image
*
* @param position
* @param medias
* @param directory_path
*/
public void externalPicturePreview(int position, String directory_path, List<LocalMedia> medias, int enterAnimation) {
if (!DoubleUtils.isFastDoubleClick()) {
if (getActivity() != null) {
Intent intent = new Intent(getActivity(), PictureExternalPreviewActivity.class);
intent.putParcelableArrayListExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST, (ArrayList<? extends Parcelable>) medias);
intent.putExtra(PictureConfig.EXTRA_POSITION, position);
intent.putExtra(PictureConfig.EXTRA_DIRECTORY_PATH, directory_path);
getActivity().startActivity(intent);
getActivity().overridePendingTransition(enterAnimation != 0
? enterAnimation : R.anim.picture_anim_enter, R.anim.picture_anim_fade_in);
} else {
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
}
}
}
/**
* set preview video
*
* @param path
*/
public void externalPictureVideo(String path) {
if (!DoubleUtils.isFastDoubleClick()) {
if (getActivity() != null) {
Intent intent = new Intent(getActivity(), PictureVideoPlayActivity.class);
intent.putExtra(PictureConfig.EXTRA_VIDEO_PATH, path);
intent.putExtra(PictureConfig.EXTRA_PREVIEW_VIDEO, true);
getActivity().startActivity(intent);
} else {
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
}
}
}
/**
* set preview audio
*
* @param path
*/
public void externalPictureAudio(String path) {
if (!DoubleUtils.isFastDoubleClick()) {
if (getActivity() != null) {
Intent intent = new Intent(getActivity(), PicturePlayAudioActivity.class);
intent.putExtra(PictureConfig.EXTRA_AUDIO_PATH, path);
getActivity().startActivity(intent);
getActivity().overridePendingTransition(R.anim.picture_anim_enter, 0);
} else {
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
}
}
}
/**
* @return Activity.
*/
@Nullable
Activity getActivity() {
return mActivity.get();
}
/**
* @return Fragment.
*/
@Nullable
Fragment getFragment() {
return mFragment != null ? mFragment.get() : null;
}
}

View File

@ -1,395 +0,0 @@
package com.luck.picture.lib;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.immersive.ImmersiveManage;
import com.luck.picture.lib.permissions.PermissionChecker;
import com.luck.picture.lib.thread.PictureThreadUtils;
import com.luck.picture.lib.tools.BitmapUtils;
import com.luck.picture.lib.tools.MediaUtils;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.ToastUtils;
import com.luck.picture.lib.tools.ValueOf;
import com.yalantis.ucrop.UCrop;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2019-11-15 21:41
* @describePictureSelectorCameraEmptyActivity
*/
public class PictureSelectorCameraEmptyActivity extends PictureBaseActivity {
@Override
public void immersive() {
ImmersiveManage.immersiveAboveAPI23(this
, ContextCompat.getColor(this, R.color.picture_color_transparent)
, ContextCompat.getColor(this, R.color.picture_color_transparent)
, openWhiteStatusBar);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (config == null) {
closeActivity();
return;
}
if (!config.isUseCustomCamera) {
if (savedInstanceState == null) {
if (PermissionChecker
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
PermissionChecker
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (PictureSelectionConfig.onCustomCameraInterfaceListener != null) {
if (config.chooseMode == PictureConfig.TYPE_VIDEO) {
PictureSelectionConfig.onCustomCameraInterfaceListener.onCameraClick(getContext(), config, PictureConfig.TYPE_VIDEO);
} else {
PictureSelectionConfig.onCustomCameraInterfaceListener.onCameraClick(getContext(), config, PictureConfig.TYPE_IMAGE);
}
} else {
onTakePhoto();
}
} else {
PermissionChecker.requestPermissions(this, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
}
}
setTheme(R.style.Picture_Theme_Translucent);
}
}
@Override
public int getResourceId() {
return R.layout.picture_empty;
}
/**
* open camera
*/
private void onTakePhoto() {
if (PermissionChecker
.checkSelfPermission(this, Manifest.permission.CAMERA)) {
boolean isPermissionChecker = true;
if (config != null && config.isUseCustomCamera) {
isPermissionChecker = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
}
if (isPermissionChecker) {
startCamera();
} else {
PermissionChecker
.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
}
} else {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
}
}
/**
* Open the Camera by type
*/
private void startCamera() {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
case PictureConfig.TYPE_IMAGE:
startOpenCamera();
break;
case PictureConfig.TYPE_VIDEO:
startOpenCameraVideo();
break;
case PictureConfig.TYPE_AUDIO:
startOpenCameraAudio();
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case UCrop.REQUEST_CROP:
singleCropHandleResult(data);
break;
case PictureConfig.REQUEST_CAMERA:
dispatchHandleCamera(data);
break;
default:
break;
}
} else if (resultCode == RESULT_CANCELED) {
if (config != null && PictureSelectionConfig.listener != null) {
PictureSelectionConfig.listener.onCancel();
}
closeActivity();
} else if (resultCode == UCrop.RESULT_ERROR) {
if (data == null) {
return;
}
Throwable throwable = (Throwable) data.getSerializableExtra(UCrop.EXTRA_ERROR);
ToastUtils.s(getContext(), throwable.getMessage());
}
}
/**
* Single picture clipping callback
*
* @param data
*/
protected void singleCropHandleResult(Intent data) {
if (data == null) {
return;
}
List<LocalMedia> medias = new ArrayList<>();
Uri resultUri = UCrop.getOutput(data);
if (resultUri == null) {
return;
}
String cutPath = resultUri.getPath();
boolean isCutEmpty = TextUtils.isEmpty(cutPath);
LocalMedia media = new LocalMedia(config.cameraPath, 0, false,
config.isCamera ? 1 : 0, 0, config.chooseMode);
if (SdkVersionUtils.checkedAndroid_Q()) {
int lastIndexOf = config.cameraPath.lastIndexOf("/") + 1;
media.setId(lastIndexOf > 0 ? ValueOf.toLong(config.cameraPath.substring(lastIndexOf)) : -1);
media.setAndroidQToPath(cutPath);
if (isCutEmpty) {
if (PictureMimeType.isContent(config.cameraPath)) {
String path = PictureFileUtils.getPath(this, Uri.parse(config.cameraPath));
media.setSize(!TextUtils.isEmpty(path) ? new File(path).length() : 0);
} else {
media.setSize(new File(config.cameraPath).length());
}
} else {
media.setSize(new File(cutPath).length());
}
} else {
// Taking a photo generates a temporary id
media.setId(System.currentTimeMillis());
media.setSize(new File(isCutEmpty ? media.getPath() : cutPath).length());
}
media.setCut(!isCutEmpty);
media.setCutPath(cutPath);
String mimeType = PictureMimeType.getImageMimeType(cutPath);
media.setMimeType(mimeType);
int width = 0, height = 0;
media.setOrientation(-1);
if (PictureMimeType.isContent(media.getPath())) {
if (PictureMimeType.isHasVideo(media.getMimeType())) {
int[] size = MediaUtils.getVideoSizeForUri(getContext(), Uri.parse(media.getPath()));
width = size[0];
height = size[1];
} else if (PictureMimeType.isHasImage(media.getMimeType())) {
int[] size = MediaUtils.getImageSizeForUri(getContext(), Uri.parse(media.getPath()));
width = size[0];
height = size[1];
}
} else {
if (PictureMimeType.isHasVideo(media.getMimeType())) {
int[] size = MediaUtils.getVideoSizeForUrl(media.getPath());
width = size[0];
height = size[1];
} else if (PictureMimeType.isHasImage(media.getMimeType())) {
int[] size = MediaUtils.getImageSizeForUrl(media.getPath());
width = size[0];
height = size[1];
}
}
media.setWidth(width);
media.setHeight(height);
// The width and height of the image are reversed if there is rotation information
MediaUtils.setOrientationAsynchronous(getContext(), media, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH,
item -> {
medias.add(item);
handlerResult(medias);
});
}
/**
* dispatchHandleCamera
*
* @param intent
*/
protected void dispatchHandleCamera(Intent intent) {
boolean isAudio = config.chooseMode == PictureMimeType.ofAudio();
config.cameraPath = isAudio ? getAudioPath(intent) : config.cameraPath;
if (TextUtils.isEmpty(config.cameraPath)) {
return;
}
showPleaseDialog();
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<LocalMedia>() {
@Override
public LocalMedia doInBackground() {
LocalMedia media = new LocalMedia();
String mimeType = isAudio ? PictureMimeType.MIME_TYPE_AUDIO : "";
int[] newSize = new int[2];
long duration = 0;
if (!isAudio) {
if (PictureMimeType.isContent(config.cameraPath)) {
// content: Processing rules
String path = PictureFileUtils.getPath(getContext(), Uri.parse(config.cameraPath));
if (!TextUtils.isEmpty(path)) {
File cameraFile = new File(path);
mimeType = PictureMimeType.getMimeType(config.cameraMimeType);
media.setSize(cameraFile.length());
}
if (PictureMimeType.isHasImage(mimeType)) {
newSize = MediaUtils.getImageSizeForUrlToAndroidQ(getContext(), config.cameraPath);
} else if (PictureMimeType.isHasVideo(mimeType)) {
newSize = MediaUtils.getVideoSizeForUri(getContext(), Uri.parse(config.cameraPath));
duration = MediaUtils.extractDuration(getContext(), SdkVersionUtils.checkedAndroid_Q(), config.cameraPath);
}
int lastIndexOf = config.cameraPath.lastIndexOf("/") + 1;
media.setId(lastIndexOf > 0 ? ValueOf.toLong(config.cameraPath.substring(lastIndexOf)) : -1);
media.setRealPath(path);
// Custom photo has been in the application sandbox into the file
String mediaPath = intent != null ? intent.getStringExtra(PictureConfig.EXTRA_MEDIA_PATH) : null;
media.setAndroidQToPath(mediaPath);
} else {
File cameraFile = new File(config.cameraPath);
mimeType = PictureMimeType.getMimeType(config.cameraMimeType);
media.setSize(cameraFile.length());
if (PictureMimeType.isHasImage(mimeType)) {
int degree = PictureFileUtils.readPictureDegree(getContext(), config.cameraPath);
BitmapUtils.rotateImage(degree, config.cameraPath);
newSize = MediaUtils.getImageSizeForUrl(config.cameraPath);
} else if (PictureMimeType.isHasVideo(mimeType)) {
newSize = MediaUtils.getVideoSizeForUrl(config.cameraPath);
duration = MediaUtils.extractDuration(getContext(), SdkVersionUtils.checkedAndroid_Q(), config.cameraPath);
}
// Taking a photo generates a temporary id
media.setId(System.currentTimeMillis());
}
media.setPath(config.cameraPath);
media.setDuration(duration);
media.setMimeType(mimeType);
media.setWidth(newSize[0]);
media.setHeight(newSize[1]);
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isHasVideo(media.getMimeType())) {
media.setParentFolderName(Environment.DIRECTORY_MOVIES);
} else {
media.setParentFolderName(PictureMimeType.CAMERA);
}
media.setChooseModel(config.chooseMode);
long bucketId = MediaUtils.getCameraFirstBucketId(getContext());
media.setBucketId(bucketId);
// The width and height of the image are reversed if there is rotation information
MediaUtils.setOrientationSynchronous(getContext(), media, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH);
}
return media;
}
@Override
public void onSuccess(LocalMedia result) {
// Refresh the system library
dismissDialog();
if (!SdkVersionUtils.checkedAndroid_Q()) {
if (config.isFallbackVersion3) {
new PictureMediaScannerConnection(getContext(), config.cameraPath);
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(config.cameraPath))));
}
}
dispatchCameraHandleResult(result);
// Solve some phone using Camera, DCIM will produce repetitive problems
if (!SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isHasImage(result.getMimeType())) {
int lastImageId = MediaUtils.getDCIMLastImageId(getContext());
if (lastImageId != -1) {
MediaUtils.removeMedia(getContext(), lastImageId);
}
}
}
});
}
/**
* dispatchCameraHandleResult
*
* @param media
*/
private void dispatchCameraHandleResult(LocalMedia media) {
boolean isHasImage = PictureMimeType.isHasImage(media.getMimeType());
if (config.enableCrop && isHasImage) {
config.originalPath = config.cameraPath;
startCrop(config.cameraPath, media.getMimeType());
} else if (config.isCompress && isHasImage && !config.isCheckOriginalImage) {
List<LocalMedia> result = new ArrayList<>();
result.add(media);
compressImage(result);
} else {
List<LocalMedia> result = new ArrayList<>();
result.add(media);
onResult(result);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
// Store Permissions
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
PermissionChecker.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
} else {
ToastUtils.s(getContext(), getString(R.string.picture_jurisdiction));
closeActivity();
}
break;
case PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE:
// Camera Permissions
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
onTakePhoto();
} else {
closeActivity();
ToastUtils.s(getContext(), getString(R.string.picture_camera));
}
break;
case PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE:
// Recording Permissions
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
onTakePhoto();
} else {
closeActivity();
ToastUtils.s(getContext(), getString(R.string.picture_audio));
}
break;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
closeActivity();
}
}

View File

@ -1,46 +0,0 @@
package com.luck.picture.lib;
import android.content.Context;
import android.media.ExifInterface;
import android.net.Uri;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import java.io.InputStream;
/**
* @authorluck
* @date2020-04-12 13:13
* @describePictureSelector对外提供的一些方法
*/
public class PictureSelectorExternalUtils {
/**
* 获取ExifInterface
*
* @param context
* @param url
* @return
*/
public static ExifInterface getExifInterface(Context context, String url) {
ExifInterface exifInterface = null;
InputStream inputStream = null;
try {
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(url)) {
inputStream = context.getContentResolver().openInputStream(Uri.parse(url));
if (inputStream != null) {
exifInterface = new ExifInterface(inputStream);
}
} else {
exifInterface = new ExifInterface(url);
}
return exifInterface;
} catch (Exception e) {
e.printStackTrace();
} finally {
PictureFileUtils.close(inputStream);
}
return null;
}
}

View File

@ -1,387 +0,0 @@
package com.luck.picture.lib;
import android.text.TextUtils;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.luck.picture.lib.adapter.PictureWeChatPreviewGalleryAdapter;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.decoration.GridSpacingItemDecoration;
import com.luck.picture.lib.decoration.WrapContentLinearLayoutManager;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.tools.ScreenUtils;
/**
* @authorluck
* @date2019-11-30 17:16
* @describePictureSelector WeChatStyle
*/
public class PictureSelectorPreviewWeChatStyleActivity extends PicturePreviewActivity {
/**
* alpha duration
*/
private final static int ALPHA_DURATION = 300;
private TextView mPictureSendView;
private RecyclerView mRvGallery;
private TextView tvSelected;
private View bottomLine;
private PictureWeChatPreviewGalleryAdapter mGalleryAdapter;
@Override
public int getResourceId() {
return R.layout.picture_wechat_style_preview;
}
private void goneParent() {
if (tvMediaNum.getVisibility() == View.VISIBLE) {
tvMediaNum.setVisibility(View.GONE);
}
if (mTvPictureOk.getVisibility() == View.VISIBLE) {
mTvPictureOk.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(check.getText())) {
check.setText("");
}
}
@Override
protected void initWidgets() {
super.initWidgets();
goneParent();
mRvGallery = findViewById(R.id.rv_gallery);
bottomLine = findViewById(R.id.bottomLine);
tvSelected = findViewById(R.id.tv_selected);
mPictureSendView = findViewById(R.id.picture_send);
mPictureSendView.setOnClickListener(this);
mPictureSendView.setText(getString(R.string.picture_send));
mCbOriginal.setTextSize(16);
mGalleryAdapter = new PictureWeChatPreviewGalleryAdapter(config);
WrapContentLinearLayoutManager layoutManager = new WrapContentLinearLayoutManager(getContext());
layoutManager.setOrientation(WrapContentLinearLayoutManager.HORIZONTAL);
mRvGallery.setLayoutManager(layoutManager);
mRvGallery.addItemDecoration(new GridSpacingItemDecoration(Integer.MAX_VALUE,
ScreenUtils.dip2px(this, 8), false));
mRvGallery.setAdapter(mGalleryAdapter);
mGalleryAdapter.setItemClickListener((position, media, v) -> {
if (viewPager != null && media != null) {
if (isEqualsDirectory(media.getParentFolderName(), currentDirectory)) {
int newPosition = isBottomPreview ? position : isShowCamera ? media.position - 1 : media.position;
viewPager.setCurrentItem(newPosition);
} else {
// TODO The picture is not in the album directory, click invalid
}
}
});
if (isBottomPreview) {
if (selectData != null && selectData.size() > position) {
int size = selectData.size();
for (int i = 0; i < size; i++) {
LocalMedia media = selectData.get(i);
media.setChecked(false);
}
LocalMedia media = selectData.get(position);
media.setChecked(true);
}
} else {
int size = selectData != null ? selectData.size() : 0;
for (int i = 0; i < size; i++) {
LocalMedia media = selectData.get(i);
if (isEqualsDirectory(media.getParentFolderName(), currentDirectory)) {
media.setChecked(isShowCamera ? media.position - 1 == position : media.position == position);
}
}
}
}
/**
* Is it the same directory
*
* @param parentFolderName
* @param currentDirectory
* @return
*/
private boolean isEqualsDirectory(String parentFolderName, String currentDirectory) {
return isBottomPreview
|| TextUtils.isEmpty(parentFolderName)
|| TextUtils.isEmpty(currentDirectory)
|| currentDirectory.equals(getString(R.string.picture_camera_roll))
|| parentFolderName.equals(currentDirectory);
}
@Override
public void initPictureSelectorStyle() {
super.initPictureSelectorStyle();
if (config.style != null) {
if (config.style.pictureCompleteBackgroundStyle != 0) {
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
}
if (config.style.pictureRightTextSize != 0) {
mPictureSendView.setTextSize(config.style.pictureRightTextSize);
}
if (!TextUtils.isEmpty(config.style.pictureWeChatPreviewSelectedText)) {
tvSelected.setText(config.style.pictureWeChatPreviewSelectedText);
}
if (config.style.pictureWeChatPreviewSelectedTextSize != 0) {
tvSelected.setTextSize(config.style.pictureWeChatPreviewSelectedTextSize);
}
if (config.style.picturePreviewBottomBgColor != 0) {
selectBarLayout.setBackgroundColor(config.style.picturePreviewBottomBgColor);
} else {
selectBarLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_half_grey));
}
if (config.style.pictureCompleteTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
} else {
if (config.style.pictureCancelTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureCancelTextColor);
} else {
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
}
}
if (config.style.pictureOriginalFontColor == 0) {
mCbOriginal.setTextColor(ContextCompat
.getColor(this, R.color.picture_color_white));
}
if (config.style.pictureWeChatChooseStyle != 0) {
check.setBackgroundResource(config.style.pictureWeChatChooseStyle);
} else {
check.setBackgroundResource(R.drawable.picture_wechat_select_cb);
}
if (config.isOriginalControl) {
if (config.style.pictureOriginalControlStyle == 0) {
mCbOriginal.setButtonDrawable(ContextCompat
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
}
}
if (config.style.pictureWeChatLeftBackStyle != 0) {
pictureLeftBack.setImageResource(config.style.pictureWeChatLeftBackStyle);
} else {
pictureLeftBack.setImageResource(R.drawable.picture_icon_back);
}
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
mPictureSendView.setText(config.style.pictureUnCompleteText);
}
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
selectBarLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_half_grey));
check.setBackgroundResource(R.drawable.picture_wechat_select_cb);
pictureLeftBack.setImageResource(R.drawable.picture_icon_back);
mCbOriginal.setTextColor(ContextCompat
.getColor(this, R.color.picture_color_white));
if (config.isOriginalControl) {
mCbOriginal.setButtonDrawable(ContextCompat
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
}
}
onSelectNumChange(false);
}
@Override
public void onClick(View v) {
super.onClick(v);
int id = v.getId();
if (id == R.id.picture_send) {
boolean enable = selectData.size() != 0;
if (enable) {
mTvPictureOk.performClick();
} else {
btnCheck.performClick();
boolean isNewEnableStatus = selectData.size() != 0;
if (isNewEnableStatus) {
mTvPictureOk.performClick();
}
}
}
}
@Override
protected void onUpdateSelectedChange(LocalMedia media) {
onChangeMediaStatus(media);
}
@Override
protected void onSelectedChange(boolean isAddRemove, LocalMedia media) {
if (isAddRemove) {
media.setChecked(true);
if (config.selectionMode == PictureConfig.SINGLE) {
mGalleryAdapter.addSingleMediaToData(media);
}
} else {
media.setChecked(false);
mGalleryAdapter.removeMediaToData(media);
if (isBottomPreview) {
if (selectData != null && selectData.size() > position) {
selectData.get(position).setChecked(true);
}
if (mGalleryAdapter.isDataEmpty()) {
onActivityBackPressed();
} else {
int currentItem = viewPager.getCurrentItem();
adapter.remove(currentItem);
adapter.removeCacheView(currentItem);
position = currentItem;
tvTitle.setText(getString(R.string.picture_preview_image_num,
position + 1, adapter.getSize()));
check.setSelected(true);
adapter.notifyDataSetChanged();
}
}
}
int itemCount = mGalleryAdapter.getItemCount();
if (itemCount > 5) {
mRvGallery.smoothScrollToPosition(itemCount - 1);
}
}
@Override
protected void onPageSelectedChange(LocalMedia media) {
super.onPageSelectedChange(media);
goneParent();
if (!config.previewEggs) {
onChangeMediaStatus(media);
}
}
/**
* onChangeMediaStatus
*
* @param media
*/
private void onChangeMediaStatus(LocalMedia media) {
if (mGalleryAdapter != null) {
int itemCount = mGalleryAdapter.getItemCount();
if (itemCount > 0) {
boolean isChangeData = false;
for (int i = 0; i < itemCount; i++) {
LocalMedia item = mGalleryAdapter.getItem(i);
if (item == null || TextUtils.isEmpty(item.getPath())) {
continue;
}
boolean isOldChecked = item.isChecked();
boolean isNewChecked = item.getPath().equals(media.getPath()) || item.getId() == media.getId();
if (!isChangeData) {
isChangeData = (isOldChecked && !isNewChecked) || (!isOldChecked && isNewChecked);
}
item.setChecked(isNewChecked);
}
if (isChangeData) {
mGalleryAdapter.notifyDataSetChanged();
}
}
}
}
@Override
protected void onSelectNumChange(boolean isRefresh) {
if (mPictureSendView == null) {
return;
}
goneParent();
boolean enable = selectData.size() != 0;
if (enable) {
initCompleteText(selectData.size());
if (mRvGallery.getVisibility() == View.GONE) {
mRvGallery.animate().alpha(1).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
mRvGallery.setVisibility(View.VISIBLE);
bottomLine.animate().alpha(1).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
bottomLine.setVisibility(View.VISIBLE);
// 重置一片内存区域 不然在其他地方添加也影响这里的数量
mGalleryAdapter.setNewData(selectData);
}
if (config.style != null) {
if (config.style.pictureCompleteTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
}
if (config.style.pictureCompleteBackgroundStyle != 0) {
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
}
} else {
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
}
} else {
if (config.style != null && !TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
mPictureSendView.setText(config.style.pictureUnCompleteText);
} else {
mPictureSendView.setText(getString(R.string.picture_send));
}
mRvGallery.animate().alpha(0).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
mRvGallery.setVisibility(View.GONE);
bottomLine.animate().alpha(0).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
bottomLine.setVisibility(View.GONE);
}
}
/**
* initCompleteText
*/
@Override
protected void initCompleteText(int startCount) {
boolean isNotEmptyStyle = config.style != null;
if (config.isWithVideoImage) {
// 混选模式
if (config.selectionMode == PictureConfig.SINGLE) {
if (startCount <= 0) {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(), 1));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
? config.style.pictureCompleteText : getString(R.string.picture_send));
}
}
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText,
selectData.size(), config.maxSelectNum));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, selectData.size(),
config.maxSelectNum));
}
}
} else {
String mimeType = selectData.get(0).getMimeType();
int maxSize = PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0 ? config.maxVideoSelectNum : config.maxSelectNum;
if (config.selectionMode == PictureConfig.SINGLE) {
if (startCount <= 0) {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(),
1));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
? config.style.pictureCompleteText : getString(R.string.picture_send));
}
}
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(), maxSize));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText
: getString(R.string.picture_send_num, selectData.size(), maxSize));
}
}
}
}
}

View File

@ -1,286 +0,0 @@
package com.luck.picture.lib;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.tools.AttrsUtils;
import java.util.List;
/**
* @authorluck
* @date2019-11-30 13:27
* @describePictureSelector WeChatStyle
*/
public class PictureSelectorWeChatStyleActivity extends PictureSelectorActivity {
private TextView mPictureSendView;
private RelativeLayout rlAlbum;
@Override
public int getResourceId() {
return R.layout.picture_wechat_style_selector;
}
@Override
protected void initWidgets() {
super.initWidgets();
rlAlbum = findViewById(R.id.rlAlbum);
mPictureSendView = findViewById(R.id.picture_send);
mPictureSendView.setOnClickListener(this);
mPictureSendView.setText(getString(R.string.picture_send));
mTvPicturePreview.setTextSize(16);
mCbOriginal.setTextSize(16);
boolean isChooseMode = config.selectionMode ==
PictureConfig.SINGLE && config.isSingleDirectReturn;
mPictureSendView.setVisibility(isChooseMode ? View.GONE : View.VISIBLE);
if (rlAlbum.getLayoutParams() != null
&& rlAlbum.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) rlAlbum.getLayoutParams();
if (isChooseMode) {
lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
} else {
lp.addRule(RelativeLayout.RIGHT_OF, R.id.pictureLeftBack);
}
}
}
@Override
public void initPictureSelectorStyle() {
if (config.style != null) {
if (config.style.pictureUnCompleteBackgroundStyle != 0) {
mPictureSendView.setBackgroundResource(config.style.pictureUnCompleteBackgroundStyle);
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
}
if (config.style.pictureBottomBgColor != 0) {
mBottomLayout.setBackgroundColor(config.style.pictureBottomBgColor);
} else {
mBottomLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_grey));
}
if (config.style.pictureUnCompleteTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureUnCompleteTextColor);
} else {
if (config.style.pictureCancelTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureCancelTextColor);
} else {
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
}
}
if (config.style.pictureRightTextSize != 0) {
mPictureSendView.setTextSize(config.style.pictureRightTextSize);
}
if (config.style.pictureOriginalFontColor == 0) {
mCbOriginal.setTextColor(ContextCompat
.getColor(this, R.color.picture_color_white));
}
if (config.isOriginalControl) {
if (config.style.pictureOriginalControlStyle == 0) {
mCbOriginal.setButtonDrawable(ContextCompat
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
}
}
if (config.style.pictureContainerBackgroundColor != 0) {
container.setBackgroundColor(config.style.pictureContainerBackgroundColor);
}
if (config.style.pictureWeChatTitleBackgroundStyle != 0) {
rlAlbum.setBackgroundResource(config.style.pictureWeChatTitleBackgroundStyle);
} else {
rlAlbum.setBackgroundResource(R.drawable.picture_album_bg);
}
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
mPictureSendView.setText(config.style.pictureUnCompleteText);
}
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
rlAlbum.setBackgroundResource(R.drawable.picture_album_bg);
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
int pictureBottomBgColor = AttrsUtils.getTypeValueColor(getContext(), R.attr.picture_bottom_bg);
mBottomLayout.setBackgroundColor(pictureBottomBgColor != 0
? pictureBottomBgColor : ContextCompat.getColor(getContext(), R.color.picture_color_grey));
mCbOriginal.setTextColor(ContextCompat
.getColor(this, R.color.picture_color_white));
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.picture_icon_wechat_down);
mIvArrow.setImageDrawable(drawable);
if (config.isOriginalControl) {
mCbOriginal.setButtonDrawable(ContextCompat
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
}
}
super.initPictureSelectorStyle();
goneParentView();
}
/**
* Hide views that are not needed by the parent container
*/
private void goneParentView() {
mTvPictureRight.setVisibility(View.GONE);
mTvPictureImgNum.setVisibility(View.GONE);
mTvPictureOk.setVisibility(View.GONE);
}
@Override
protected void changeImageNumber(List<LocalMedia> selectData) {
if (mPictureSendView == null) {
return;
}
int size = selectData.size();
boolean enable = size != 0;
if (enable) {
mPictureSendView.setEnabled(true);
mPictureSendView.setSelected(true);
mTvPicturePreview.setEnabled(true);
mTvPicturePreview.setSelected(true);
initCompleteText(selectData);
if (config.style != null) {
if (config.style.pictureCompleteBackgroundStyle != 0) {
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
}
if (config.style.pictureCompleteTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
} else {
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
}
if (config.style.picturePreviewTextColor != 0) {
mTvPicturePreview.setTextColor(config.style.picturePreviewTextColor);
} else {
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
}
if (!TextUtils.isEmpty(config.style.picturePreviewText)) {
mTvPicturePreview.setText(config.style.picturePreviewText);
} else {
mTvPicturePreview.setText(getString(R.string.picture_preview_num, size));
}
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
mTvPicturePreview.setText(getString(R.string.picture_preview_num, size));
}
} else {
mPictureSendView.setEnabled(false);
mPictureSendView.setSelected(false);
mTvPicturePreview.setEnabled(false);
mTvPicturePreview.setSelected(false);
if (config.style != null) {
if (config.style.pictureUnCompleteBackgroundStyle != 0) {
mPictureSendView.setBackgroundResource(config.style.pictureUnCompleteBackgroundStyle);
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
}
if (config.style.pictureUnCompleteTextColor != 0) {
mPictureSendView.setTextColor(config.style.pictureUnCompleteTextColor);
} else {
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
}
if (config.style.pictureUnPreviewTextColor != 0) {
mTvPicturePreview.setTextColor(config.style.pictureUnPreviewTextColor);
} else {
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_9b));
}
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
mPictureSendView.setText(config.style.pictureUnCompleteText);
} else {
mPictureSendView.setText(getString(R.string.picture_send));
}
if (!TextUtils.isEmpty(config.style.pictureUnPreviewText)) {
mTvPicturePreview.setText(config.style.pictureUnPreviewText);
} else {
mTvPicturePreview.setText(getString(R.string.picture_preview));
}
} else {
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_9b));
mTvPicturePreview.setText(getString(R.string.picture_preview));
mPictureSendView.setText(getString(R.string.picture_send));
}
}
}
@Override
public void onClick(View v) {
super.onClick(v);
int id = v.getId();
if (id == R.id.picture_send) {
if (folderWindow != null
&& folderWindow.isShowing()) {
folderWindow.dismiss();
} else {
mTvPictureOk.performClick();
}
}
}
@Override
protected void onChangeData(List<LocalMedia> list) {
super.onChangeData(list);
initCompleteText(list);
}
@Override
protected void initCompleteText(List<LocalMedia> list) {
int size = list.size();
boolean isNotEmptyStyle = config.style != null;
if (config.isWithVideoImage) {
if (config.selectionMode == PictureConfig.SINGLE) {
if (size <= 0) {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, 1));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
? config.style.pictureCompleteText : getString(R.string.picture_send));
}
}
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, config.maxSelectNum));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, size, config.maxSelectNum));
}
}
} else {
String mimeType = list.get(0).getMimeType();
int maxSize = PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0 ? config.maxVideoSelectNum : config.maxSelectNum;
if (config.selectionMode == PictureConfig.SINGLE) {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, 1));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
? config.style.pictureCompleteText : getString(R.string.picture_send));
}
} else {
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, maxSize));
} else {
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, size, maxSize));
}
}
}
}
}

View File

@ -1,218 +0,0 @@
package com.luck.picture.lib;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.VideoView;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.tools.SdkVersionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @data2017/8/28 下午11:00
* @描述: 视频播放类
*/
public class PictureVideoPlayActivity extends PictureBaseActivity implements
MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener, View.OnClickListener {
private String videoPath;
private ImageButton ibLeftBack;
private MediaController mMediaController;
private VideoView mVideoView;
private TextView tvConfirm;
private ImageView iv_play;
private int mPositionWhenPaused = -1;
@Override
public boolean isImmersive() {
return false;
}
@Override
public boolean isRequestedOrientation() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
super.onCreate(savedInstanceState);
}
@Override
public int getResourceId() {
return R.layout.picture_activity_video_play;
}
@Override
protected void initPictureSelectorStyle() {
if (config.style != null) {
if (config.style.pictureLeftBackIcon != 0) {
ibLeftBack.setImageResource(config.style.pictureLeftBackIcon);
}
}
}
@Override
protected void initWidgets() {
super.initWidgets();
videoPath = getIntent().getStringExtra(PictureConfig.EXTRA_VIDEO_PATH);
boolean isExternalPreview = getIntent().getBooleanExtra
(PictureConfig.EXTRA_PREVIEW_VIDEO, false);
if (TextUtils.isEmpty(videoPath)) {
LocalMedia media = getIntent().getParcelableExtra(PictureConfig.EXTRA_MEDIA_KEY);
if (media == null || TextUtils.isEmpty(media.getPath())) {
finish();
return;
}
videoPath = media.getPath();
}
if (TextUtils.isEmpty(videoPath)) {
closeActivity();
return;
}
ibLeftBack = findViewById(R.id.pictureLeftBack);
mVideoView = findViewById(R.id.video_view);
tvConfirm = findViewById(R.id.tv_confirm);
mVideoView.setBackgroundColor(Color.BLACK);
iv_play = findViewById(R.id.iv_play);
mMediaController = new MediaController(this);
mVideoView.setOnCompletionListener(this);
mVideoView.setOnPreparedListener(this);
mVideoView.setMediaController(mMediaController);
ibLeftBack.setOnClickListener(this);
iv_play.setOnClickListener(this);
tvConfirm.setOnClickListener(this);
tvConfirm.setVisibility(config.selectionMode
== PictureConfig.SINGLE
&& config.enPreviewVideo && !isExternalPreview ? View.VISIBLE : View.GONE);
}
@Override
public void onStart() {
// Play Video
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(videoPath)) {
mVideoView.setVideoURI(Uri.parse(videoPath));
} else {
mVideoView.setVideoPath(videoPath);
}
mVideoView.start();
super.onStart();
}
@Override
public void onPause() {
// Stop video when the activity is pause.
mPositionWhenPaused = mVideoView.getCurrentPosition();
mVideoView.stopPlayback();
super.onPause();
}
@Override
protected void onDestroy() {
mMediaController = null;
mVideoView = null;
iv_play = null;
super.onDestroy();
}
@Override
public void onResume() {
// Resume video player
if (mPositionWhenPaused >= 0) {
mVideoView.seekTo(mPositionWhenPaused);
mPositionWhenPaused = -1;
}
super.onResume();
}
@Override
public boolean onError(MediaPlayer player, int arg1, int arg2) {
return false;
}
@Override
public void onCompletion(MediaPlayer mp) {
if (null != iv_play) {
iv_play.setVisibility(View.VISIBLE);
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.pictureLeftBack) {
onBackPressed();
} else if (id == R.id.iv_play) {
mVideoView.start();
iv_play.setVisibility(View.INVISIBLE);
} else if (id == R.id.tv_confirm) {
List<LocalMedia> result = new ArrayList<>();
result.add(getIntent().getParcelableExtra(PictureConfig.EXTRA_MEDIA_KEY));
setResult(RESULT_OK, new Intent()
.putParcelableArrayListExtra(PictureConfig.EXTRA_SELECT_LIST,
(ArrayList<? extends Parcelable>) result));
onBackPressed();
}
}
@Override
public void onBackPressed() {
if (config.windowAnimationStyle != null
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0) {
finish();
overridePendingTransition(0, config.windowAnimationStyle != null
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0 ?
config.windowAnimationStyle.activityPreviewExitAnimation : R.anim.picture_anim_exit);
} else {
closeActivity();
}
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new ContextWrapper(newBase) {
@Override
public Object getSystemService(String name) {
if (Context.AUDIO_SERVICE.equals(name)) {
return getApplicationContext().getSystemService(name);
}
return super.getSystemService(name);
}
});
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.setOnInfoListener((mp1, what, extra) -> {
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// video started
mVideoView.setBackgroundColor(Color.TRANSPARENT);
return true;
}
return false;
});
}
}

View File

@ -1,122 +0,0 @@
package com.luck.picture.lib.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMediaFolder;
import com.luck.picture.lib.listener.OnAlbumItemClickListener;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2016-12-11 17:02
* @describePictureAlbumDirectoryAdapter
*/
public class PictureAlbumDirectoryAdapter extends RecyclerView.Adapter<PictureAlbumDirectoryAdapter.ViewHolder> {
private List<LocalMediaFolder> folders = new ArrayList<>();
private int chooseMode;
private PictureSelectionConfig config;
public PictureAlbumDirectoryAdapter(PictureSelectionConfig config) {
super();
this.config = config;
this.chooseMode = config.chooseMode;
}
public void bindFolderData(List<LocalMediaFolder> folders) {
this.folders = folders == null ? new ArrayList<>() : folders;
notifyDataSetChanged();
}
public void setChooseMode(int chooseMode) {
this.chooseMode = chooseMode;
}
public List<LocalMediaFolder> getFolderData() {
return folders == null ? new ArrayList<>() : folders;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.picture_album_folder_item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final LocalMediaFolder folder = folders.get(position);
String name = folder.getName();
int imageNum = folder.getImageNum();
String imagePath = folder.getFirstImagePath();
boolean isChecked = folder.isChecked();
int checkedNum = folder.getCheckedNum();
holder.tvSign.setVisibility(checkedNum > 0 ? View.VISIBLE : View.INVISIBLE);
holder.itemView.setSelected(isChecked);
if (config.style != null && config.style.pictureAlbumStyle != 0) {
holder.itemView.setBackgroundResource(config.style.pictureAlbumStyle);
}
if (chooseMode == PictureMimeType.ofAudio()) {
holder.ivFirstImage.setImageResource(R.drawable.picture_audio_placeholder);
} else {
if (PictureSelectionConfig.imageEngine != null) {
PictureSelectionConfig.imageEngine.loadFolderImage(holder.itemView.getContext(),
imagePath, holder.ivFirstImage);
}
}
Context context = holder.itemView.getContext();
String firstTitle = folder.getOfAllType() != -1 ? folder.getOfAllType() == PictureMimeType.ofAudio() ?
context.getString(R.string.picture_all_audio)
: context.getString(R.string.picture_camera_roll) : name;
holder.tvFolderName.setText(context.getString(R.string.picture_camera_roll_num, firstTitle, imageNum));
holder.itemView.setOnClickListener(view -> {
if (onAlbumItemClickListener != null) {
int size = folders.size();
for (int i = 0; i < size; i++) {
LocalMediaFolder mediaFolder = folders.get(i);
mediaFolder.setChecked(false);
}
folder.setChecked(true);
notifyDataSetChanged();
onAlbumItemClickListener.onItemClick(position, folder.isCameraFolder(), folder.getBucketId(), folder.getName(), folder.getData());
}
});
}
@Override
public int getItemCount() {
return folders.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivFirstImage;
TextView tvFolderName, tvSign;
public ViewHolder(View itemView) {
super(itemView);
ivFirstImage = itemView.findViewById(R.id.first_image);
tvFolderName = itemView.findViewById(R.id.tv_folder_name);
tvSign = itemView.findViewById(R.id.tv_sign);
if (config.style != null && config.style.pictureFolderCheckedDotStyle != 0) {
tvSign.setBackgroundResource(config.style.pictureFolderCheckedDotStyle);
}
}
}
private OnAlbumItemClickListener onAlbumItemClickListener;
public void setOnAlbumItemClickListener(OnAlbumItemClickListener listener) {
this.onAlbumItemClickListener = listener;
}
}

View File

@ -1,682 +0,0 @@
package com.luck.picture.lib.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.dialog.PictureCustomDialog;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.listener.OnPhotoSelectChangedListener;
import com.luck.picture.lib.tools.AnimUtils;
import com.luck.picture.lib.tools.DateUtils;
import com.luck.picture.lib.tools.MediaUtils;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.StringUtils;
import com.luck.picture.lib.tools.ToastUtils;
import com.luck.picture.lib.tools.VoiceUtils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2016-12-30 12:02
* @describePictureImageGridAdapter
*/
public class PictureImageGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private boolean showCamera;
private OnPhotoSelectChangedListener imageSelectChangedListener;
private List<LocalMedia> data = new ArrayList<>();
private List<LocalMedia> selectData = new ArrayList<>();
private PictureSelectionConfig config;
public PictureImageGridAdapter(Context context, PictureSelectionConfig config) {
this.context = context;
this.config = config;
this.showCamera = config.isCamera;
}
public void setShowCamera(boolean showCamera) {
this.showCamera = showCamera;
}
public boolean isShowCamera() {
return showCamera;
}
/**
* 全量刷新
*
* @param data
*/
public void bindData(List<LocalMedia> data) {
this.data = data == null ? new ArrayList<>() : data;
this.notifyDataSetChanged();
}
public void bindSelectData(List<LocalMedia> images) {
// 这里重新构构造一个新集合不然会产生已选集合一变结果集合也会添加的问题
List<LocalMedia> selection = new ArrayList<>();
int size = images.size();
for (int i = 0; i < size; i++) {
LocalMedia media = images.get(i);
selection.add(media);
}
this.selectData = selection;
if (!config.isSingleDirectReturn) {
subSelectPosition();
if (imageSelectChangedListener != null) {
imageSelectChangedListener.onChange(selectData);
}
}
}
public List<LocalMedia> getSelectedData() {
return selectData == null ? new ArrayList<>() : selectData;
}
public int getSelectedSize() {
return selectData == null ? 0 : selectData.size();
}
public List<LocalMedia> getData() {
return data == null ? new ArrayList<>() : data;
}
public boolean isDataEmpty() {
return data == null || data.size() == 0;
}
public void clear() {
if (getSize() > 0) {
data.clear();
}
}
public int getSize() {
return data == null ? 0 : data.size();
}
public LocalMedia getItem(int position) {
return getSize() > 0 ? data.get(position) : null;
}
@Override
public int getItemViewType(int position) {
if (showCamera && position == 0) {
return PictureConfig.TYPE_CAMERA;
} else {
return PictureConfig.TYPE_PICTURE;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == PictureConfig.TYPE_CAMERA) {
View view = LayoutInflater.from(context).inflate(R.layout.picture_item_camera, parent, false);
return new CameraViewHolder(view);
} else {
View view = LayoutInflater.from(context).inflate(R.layout.picture_image_grid_item, parent, false);
return new ViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, final int position) {
if (getItemViewType(position) == PictureConfig.TYPE_CAMERA) {
CameraViewHolder headerHolder = (CameraViewHolder) holder;
headerHolder.headerView.setOnClickListener(v -> {
if (imageSelectChangedListener != null) {
imageSelectChangedListener.onTakePhoto();
}
});
} else {
final ViewHolder contentHolder = (ViewHolder) holder;
final LocalMedia image = data.get(showCamera ? position - 1 : position);
image.position = contentHolder.getAdapterPosition();
final String path = image.getPath();
final String mimeType = image.getMimeType();
if (config.checkNumMode) {
notifyCheckChanged(contentHolder, image);
}
if (config.isSingleDirectReturn) {
contentHolder.tvCheck.setVisibility(View.GONE);
contentHolder.btnCheck.setVisibility(View.GONE);
} else {
selectImage(contentHolder, isSelected(image));
contentHolder.tvCheck.setVisibility(View.VISIBLE);
contentHolder.btnCheck.setVisibility(View.VISIBLE);
// 启用了蒙层效果
if (config.isMaxSelectEnabledMask) {
dispatchHandleMask(contentHolder, image);
}
}
contentHolder.tvIsGif.setVisibility(PictureMimeType.isGif(mimeType) ? View.VISIBLE : View.GONE);
if (PictureMimeType.isHasImage(image.getMimeType())) {
if (image.loadLongImageStatus == PictureConfig.NORMAL) {
image.isLongImage = MediaUtils.isLongImg(image);
image.loadLongImageStatus = PictureConfig.LOADED;
}
contentHolder.tvLongChart.setVisibility(image.isLongImage ? View.VISIBLE : View.GONE);
} else {
image.loadLongImageStatus = PictureConfig.NORMAL;
contentHolder.tvLongChart.setVisibility(View.GONE);
}
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
if (isHasVideo || PictureMimeType.isHasAudio(mimeType)) {
contentHolder.tvDuration.setVisibility(View.VISIBLE);
contentHolder.tvDuration.setText(DateUtils.formatDurationTime(image.getDuration()));
contentHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds
(isHasVideo ? R.drawable.picture_icon_video : R.drawable.picture_icon_audio,
0, 0, 0);
} else {
contentHolder.tvDuration.setVisibility(View.GONE);
}
if (config.chooseMode == PictureMimeType.ofAudio()) {
contentHolder.ivPicture.setImageResource(R.drawable.picture_audio_placeholder);
} else {
if (PictureSelectionConfig.imageEngine != null) {
PictureSelectionConfig.imageEngine.loadGridImage(context, path, contentHolder.ivPicture);
}
}
if (config.enablePreview || config.enPreviewVideo || config.enablePreviewAudio) {
contentHolder.btnCheck.setOnClickListener(v -> {
if (config.isMaxSelectEnabledMask) {
if (!contentHolder.tvCheck.isSelected() && getSelectedSize() >= config.maxSelectNum) {
String msg = StringUtils.getMsg(context, config.chooseMode == PictureMimeType.ofAll() ? null : image.getMimeType(), config.maxSelectNum);
showPromptDialog(msg);
return;
}
}
// If the original path does not exist or the path does exist but the file does not exist
String newPath = image.getRealPath();
if (!TextUtils.isEmpty(newPath) && !new File(newPath).exists()) {
ToastUtils.s(context, PictureMimeType.s(context, mimeType));
return;
}
// The width and height of the image are reversed if there is rotation information
MediaUtils.setOrientationAsynchronous(context, image, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH, null);
changeCheckboxState(contentHolder, image);
});
}
contentHolder.contentView.setOnClickListener(v -> {
if (config.isMaxSelectEnabledMask) {
if (image.isMaxSelectEnabledMask()) {
return;
}
}
// If the original path does not exist or the path does exist but the file does not exist
String newPath = image.getRealPath();
if (!TextUtils.isEmpty(newPath) && !new File(newPath).exists()) {
ToastUtils.s(context, PictureMimeType.s(context, mimeType));
return;
}
int index = showCamera ? position - 1 : position;
if (index == -1) {
return;
}
// The width and height of the image are reversed if there is rotation information
MediaUtils.setOrientationAsynchronous(context, image, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH, null);
boolean eqResult =
PictureMimeType.isHasImage(mimeType) && config.enablePreview
|| PictureMimeType.isHasVideo(mimeType) && (config.enPreviewVideo
|| config.selectionMode == PictureConfig.SINGLE)
|| PictureMimeType.isHasAudio(mimeType) && (config.enablePreviewAudio
|| config.selectionMode == PictureConfig.SINGLE);
if (eqResult) {
if (PictureMimeType.isHasVideo(image.getMimeType())) {
if (config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
// The video is less than the minimum specified length
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
return;
}
if (config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
// The length of the video exceeds the specified length
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
return;
}
}
imageSelectChangedListener.onPictureClick(image, index);
} else {
changeCheckboxState(contentHolder, image);
}
});
}
}
/**
* Handle mask effects
*
* @param contentHolder
* @param item
*/
private void dispatchHandleMask(ViewHolder contentHolder, LocalMedia item) {
if (config.isWithVideoImage && config.maxVideoSelectNum > 0) {
if (getSelectedSize() >= config.maxSelectNum) {
boolean isSelected = contentHolder.tvCheck.isSelected();
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
(context, isSelected ? R.color.picture_color_80 : R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
item.setMaxSelectEnabledMask(!isSelected);
} else {
item.setMaxSelectEnabledMask(false);
}
} else {
LocalMedia media = selectData.size() > 0 ? selectData.get(0) : null;
if (media != null) {
boolean isSelected = contentHolder.tvCheck.isSelected();
if (config.chooseMode == PictureMimeType.ofAll()) {
if (PictureMimeType.isHasImage(media.getMimeType())) {
// All videos are not optional
if (!isSelected && !PictureMimeType.isHasImage(item.getMimeType())) {
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
(context, PictureMimeType.isHasVideo(item.getMimeType()) ? R.color.picture_color_half_white : R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
}
item.setMaxSelectEnabledMask(PictureMimeType.isHasVideo(item.getMimeType()));
} else if (PictureMimeType.isHasVideo(media.getMimeType())) {
// All images are not optional
if (!isSelected && !PictureMimeType.isHasVideo(item.getMimeType())) {
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
(context, PictureMimeType.isHasImage(item.getMimeType()) ? R.color.picture_color_half_white : R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
}
item.setMaxSelectEnabledMask(PictureMimeType.isHasImage(item.getMimeType()));
}
} else {
if (config.chooseMode == PictureMimeType.ofVideo() && config.maxVideoSelectNum > 0) {
if (!isSelected && getSelectedSize() == config.maxVideoSelectNum) {
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
(context, R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
}
item.setMaxSelectEnabledMask(!isSelected && getSelectedSize() == config.maxVideoSelectNum);
} else {
if (!isSelected && getSelectedSize() == config.maxSelectNum) {
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
(context, R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
}
item.setMaxSelectEnabledMask(!isSelected && getSelectedSize() == config.maxSelectNum);
}
}
}
}
}
@Override
public int getItemCount() {
return showCamera ? data.size() + 1 : data.size();
}
public class CameraViewHolder extends RecyclerView.ViewHolder {
View headerView;
TextView tvCamera;
public CameraViewHolder(View itemView) {
super(itemView);
headerView = itemView;
tvCamera = itemView.findViewById(R.id.tvCamera);
String title = config.chooseMode == PictureMimeType.ofAudio() ?
context.getString(R.string.picture_tape)
: context.getString(R.string.picture_take_picture);
tvCamera.setText(title);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivPicture;
TextView tvCheck;
TextView tvDuration, tvIsGif, tvLongChart;
View contentView;
View btnCheck;
public ViewHolder(View itemView) {
super(itemView);
contentView = itemView;
ivPicture = itemView.findViewById(R.id.ivPicture);
tvCheck = itemView.findViewById(R.id.tvCheck);
btnCheck = itemView.findViewById(R.id.btnCheck);
tvDuration = itemView.findViewById(R.id.tv_duration);
tvIsGif = itemView.findViewById(R.id.tv_isGif);
tvLongChart = itemView.findViewById(R.id.tv_long_chart);
if (config.style != null) {
if (config.style.pictureCheckedStyle != 0) {
tvCheck.setBackgroundResource(config.style.pictureCheckedStyle);
}
}
}
}
public boolean isSelected(LocalMedia image) {
int size = selectData.size();
for (int i = 0; i < size; i++) {
LocalMedia media = selectData.get(i);
if (media == null || TextUtils.isEmpty(media.getPath())) {
continue;
}
if (media.getPath()
.equals(image.getPath())
|| media.getId() == image.getId()) {
return true;
}
}
return false;
}
/**
* Update button status
*/
private void notifyCheckChanged(ViewHolder viewHolder, LocalMedia imageBean) {
viewHolder.tvCheck.setText("");
int size = selectData.size();
for (int i = 0; i < size; i++) {
LocalMedia media = selectData.get(i);
if (media.getPath().equals(imageBean.getPath())
|| media.getId() == imageBean.getId()) {
imageBean.setNum(media.getNum());
media.setPosition(imageBean.getPosition());
viewHolder.tvCheck.setText(String.valueOf(imageBean.getNum()));
}
}
}
/**
* Update the selected status of the image
*
* @param contentHolder
* @param image
*/
@SuppressLint("StringFormatMatches")
private void changeCheckboxState(ViewHolder contentHolder, LocalMedia image) {
boolean isChecked = contentHolder.tvCheck.isSelected();
int count = selectData.size();
String mimeType = count > 0 ? selectData.get(0).getMimeType() : "";
if (config.isWithVideoImage) {
// isWithVideoImage mode
int videoSize = 0;
for (int i = 0; i < count; i++) {
LocalMedia media = selectData.get(i);
if (PictureMimeType.isHasVideo(media.getMimeType())) {
videoSize++;
}
}
if (PictureMimeType.isHasVideo(image.getMimeType())) {
if (config.maxVideoSelectNum <= 0) {
showPromptDialog(context.getString(R.string.picture_rule));
return;
}
if (getSelectedSize() >= config.maxSelectNum && !isChecked) {
showPromptDialog(context.getString(R.string.picture_message_max_num, config.maxSelectNum));
return;
}
if (videoSize >= config.maxVideoSelectNum && !isChecked) {
showPromptDialog(StringUtils.getMsg(context, image.getMimeType(), config.maxVideoSelectNum));
return;
}
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
return;
}
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
return;
}
}
if (PictureMimeType.isHasImage(image.getMimeType())) {
if (getSelectedSize() >= config.maxSelectNum && !isChecked) {
showPromptDialog(context.getString(R.string.picture_message_max_num, config.maxSelectNum));
return;
}
}
} else {
if (!TextUtils.isEmpty(mimeType)) {
boolean mimeTypeSame = PictureMimeType.isMimeTypeSame(mimeType, image.getMimeType());
if (!mimeTypeSame) {
showPromptDialog(context.getString(R.string.picture_rule));
return;
}
}
if (PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0) {
if (count >= config.maxVideoSelectNum && !isChecked) {
showPromptDialog(StringUtils.getMsg(context, mimeType, config.maxVideoSelectNum));
return;
}
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
return;
}
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
return;
}
} else {
if (count >= config.maxSelectNum && !isChecked) {
showPromptDialog(StringUtils.getMsg(context, mimeType, config.maxSelectNum));
return;
}
if (PictureMimeType.isHasVideo(image.getMimeType())) {
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
return;
}
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
return;
}
}
}
}
if (isChecked) {
for (int i = 0; i < count; i++) {
LocalMedia media = selectData.get(i);
if (media == null || TextUtils.isEmpty(media.getPath())) {
continue;
}
if (media.getPath().equals(image.getPath())
|| media.getId() == image.getId()) {
selectData.remove(media);
subSelectPosition();
AnimUtils.disZoom(contentHolder.ivPicture, config.zoomAnim);
break;
}
}
} else {
// The radio
if (config.selectionMode == PictureConfig.SINGLE) {
singleRadioMediaImage();
}
// If the width and height are 0, regain the width and height
if (image.getWidth() == 0 || image.getHeight() == 0) {
int width = 0, height = 0;
image.setOrientation(-1);
if (PictureMimeType.isContent(image.getPath())) {
if (PictureMimeType.isHasVideo(image.getMimeType())) {
int[] size = MediaUtils.getVideoSizeForUri(context, Uri.parse(image.getPath()));
width = size[0];
height = size[1];
} else if (PictureMimeType.isHasImage(image.getMimeType())) {
int[] size = MediaUtils.getImageSizeForUri(context, Uri.parse(image.getPath()));
width = size[0];
height = size[1];
}
} else {
if (PictureMimeType.isHasVideo(image.getMimeType())) {
int[] size = MediaUtils.getVideoSizeForUrl(image.getPath());
width = size[0];
height = size[1];
} else if (PictureMimeType.isHasImage(image.getMimeType())) {
int[] size = MediaUtils.getImageSizeForUrl(image.getPath());
width = size[0];
height = size[1];
}
}
image.setWidth(width);
image.setHeight(height);
}
selectData.add(image);
image.setNum(selectData.size());
VoiceUtils.getInstance().play();
AnimUtils.zoom(contentHolder.ivPicture, config.zoomAnim);
contentHolder.tvCheck.startAnimation(AnimationUtils.loadAnimation(context, R.anim.picture_anim_modal_in));
}
boolean isRefreshAll = false;
if (config.isMaxSelectEnabledMask) {
if (config.chooseMode == PictureMimeType.ofAll()) {
// ofAll
if (config.isWithVideoImage && config.maxVideoSelectNum > 0) {
if (getSelectedSize() >= config.maxSelectNum) {
isRefreshAll = true;
}
if (isChecked) {
// delete
if (getSelectedSize() == config.maxSelectNum - 1) {
isRefreshAll = true;
}
}
} else {
if (!isChecked && getSelectedSize() == 1) {
// add
isRefreshAll = true;
}
if (isChecked && getSelectedSize() == 0) {
// delete
isRefreshAll = true;
}
}
} else {
// ofImage or ofVideo or ofAudio
if (config.chooseMode == PictureMimeType.ofVideo() && config.maxVideoSelectNum > 0) {
if (!isChecked && getSelectedSize() == config.maxVideoSelectNum) {
// add
isRefreshAll = true;
}
if (isChecked && getSelectedSize() == config.maxVideoSelectNum - 1) {
// delete
isRefreshAll = true;
}
} else {
if (!isChecked && getSelectedSize() == config.maxSelectNum) {
// add
isRefreshAll = true;
}
if (isChecked && getSelectedSize() == config.maxSelectNum - 1) {
// delete
isRefreshAll = true;
}
}
}
}
if (isRefreshAll) {
notifyDataSetChanged();
} else {
notifyItemChanged(contentHolder.getAdapterPosition());
}
selectImage(contentHolder, !isChecked);
if (imageSelectChangedListener != null) {
imageSelectChangedListener.onChange(selectData);
}
}
/**
* Radio mode
*/
private void singleRadioMediaImage() {
if (selectData != null
&& selectData.size() > 0) {
LocalMedia media = selectData.get(0);
notifyItemChanged(media.position);
selectData.clear();
}
}
/**
* Update the selection order
*/
private void subSelectPosition() {
if (config.checkNumMode) {
int size = selectData.size();
for (int index = 0; index < size; index++) {
LocalMedia media = selectData.get(index);
media.setNum(index + 1);
notifyItemChanged(media.position);
}
}
}
/**
* Select the image and animate it
*
* @param holder
* @param isChecked
*/
public void selectImage(ViewHolder holder, boolean isChecked) {
holder.tvCheck.setSelected(isChecked);
if (isChecked) {
holder.ivPicture.setColorFilter(ContextCompat.getColor
(context, R.color.picture_color_80), PorterDuff.Mode.SRC_ATOP);
} else {
holder.ivPicture.setColorFilter(ContextCompat.getColor
(context, R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
}
}
/**
* Tips
*/
private void showPromptDialog(String content) {
PictureCustomDialog dialog = new PictureCustomDialog(context, R.layout.picture_prompt_dialog);
TextView btnOk = dialog.findViewById(R.id.btnOk);
TextView tvContent = dialog.findViewById(R.id.tv_content);
tvContent.setText(content);
btnOk.setOnClickListener(v -> dialog.dismiss());
dialog.show();
}
/**
* Binding listener
*
* @param imageSelectChangedListener
*/
public void setOnPhotoSelectChangedListener(OnPhotoSelectChangedListener
imageSelectChangedListener) {
this.imageSelectChangedListener = imageSelectChangedListener;
}
}

View File

@ -1,225 +0,0 @@
package com.luck.picture.lib.adapter;
import android.content.Intent;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.photoview.PhotoView;
import com.luck.picture.lib.tools.JumpUtils;
import com.luck.picture.lib.tools.MediaUtils;
import com.luck.picture.lib.widget.longimage.ImageSource;
import com.luck.picture.lib.widget.longimage.ImageViewState;
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @data2018/1/27 下午7:50
* @describe:PictureSimpleFragmentAdapter
*/
public class PictureSimpleFragmentAdapter extends PagerAdapter {
private List<LocalMedia> data;
private OnCallBackActivity onBackPressed;
private PictureSelectionConfig config;
/**
* Maximum number of cached images
*/
private static final int MAX_CACHE_SIZE = 20;
/**
* To cache the view
*/
private SparseArray<View> mCacheView;
public void clear() {
if (null != mCacheView) {
mCacheView.clear();
mCacheView = null;
}
}
public void removeCacheView(int position) {
if (mCacheView != null && position < mCacheView.size()) {
mCacheView.removeAt(position);
}
}
public interface OnCallBackActivity {
/**
* Close Activity
*/
void onActivityBackPressed();
}
public PictureSimpleFragmentAdapter(PictureSelectionConfig config,
OnCallBackActivity onBackPressed) {
super();
this.config = config;
this.onBackPressed = onBackPressed;
this.mCacheView = new SparseArray<>();
}
/**
* bind data
*
* @param data
*/
public void bindData(List<LocalMedia> data) {
this.data = data;
}
/**
* get data
*
* @return
*/
public List<LocalMedia> getData() {
return data == null ? new ArrayList<>() : data;
}
public int getSize() {
return data == null ? 0 : data.size();
}
public void remove(int currentItem) {
if (getSize() > currentItem) {
data.remove(currentItem);
}
}
public LocalMedia getItem(int position) {
return getSize() > 0 && position < getSize() ? data.get(position) : null;
}
@Override
public int getCount() {
return data != null ? data.size() : 0;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
(container).removeView((View) object);
if (mCacheView.size() > MAX_CACHE_SIZE) {
mCacheView.remove(position);
}
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
@Override
public boolean isViewFromObject(@NotNull View view, @NotNull Object object) {
return view == object;
}
@NotNull
@Override
public Object instantiateItem(@NotNull ViewGroup container, int position) {
View contentView = mCacheView.get(position);
if (contentView == null) {
contentView = LayoutInflater.from(container.getContext())
.inflate(R.layout.picture_image_preview, container, false);
mCacheView.put(position, contentView);
}
PhotoView imageView = contentView.findViewById(R.id.preview_image);
SubsamplingScaleImageView longImg = contentView.findViewById(R.id.longImg);
ImageView ivPlay = contentView.findViewById(R.id.iv_play);
LocalMedia media = getItem(position);
if (media != null) {
final String mimeType = media.getMimeType();
final String path;
if (media.isCut() && !media.isCompressed()) {
path = media.getCutPath();
} else if (media.isCompressed() || (media.isCut() && media.isCompressed())) {
path = media.getCompressPath();
} else {
path = media.getPath();
}
boolean isGif = PictureMimeType.isGif(mimeType);
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
ivPlay.setVisibility(isHasVideo ? View.VISIBLE : View.GONE);
ivPlay.setOnClickListener(v -> {
if (PictureSelectionConfig.customVideoPlayCallback != null) {
PictureSelectionConfig.customVideoPlayCallback.startPlayVideo(media);
} else {
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putBoolean(PictureConfig.EXTRA_PREVIEW_VIDEO, true);
bundle.putString(PictureConfig.EXTRA_VIDEO_PATH, path);
intent.putExtras(bundle);
JumpUtils.startPictureVideoPlayActivity(container.getContext(), bundle, PictureConfig.PREVIEW_VIDEO_CODE);
}
});
boolean eqLongImg = MediaUtils.isLongImg(media);
imageView.setVisibility(eqLongImg && !isGif ? View.GONE : View.VISIBLE);
imageView.setOnViewTapListener((view, x, y) -> {
if (onBackPressed != null) {
onBackPressed.onActivityBackPressed();
}
});
longImg.setVisibility(eqLongImg && !isGif ? View.VISIBLE : View.GONE);
longImg.setOnClickListener(v -> {
if (onBackPressed != null) {
onBackPressed.onActivityBackPressed();
}
});
if (isGif && !media.isCompressed()) {
if (config != null && PictureSelectionConfig.imageEngine != null) {
PictureSelectionConfig.imageEngine.loadAsGifImage
(contentView.getContext(), path, imageView);
}
} else {
if (config != null && PictureSelectionConfig.imageEngine != null) {
if (eqLongImg) {
displayLongPic(PictureMimeType.isContent(path)
? Uri.parse(path) : Uri.fromFile(new File(path)), longImg);
} else {
PictureSelectionConfig.imageEngine.loadImage
(contentView.getContext(), path, imageView);
}
}
}
}
(container).addView(contentView, 0);
return contentView;
}
/**
* load long image
*
* @param uri
* @param longImg
*/
private void displayLongPic(Uri uri, SubsamplingScaleImageView longImg) {
longImg.setQuickScaleEnabled(true);
longImg.setZoomEnabled(true);
longImg.setPanEnabled(true);
longImg.setDoubleTapZoomDuration(100);
longImg.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
longImg.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
longImg.setImage(ImageSource.uri(uri), new ImageViewState(0, new PointF(0, 0), 0));
}
}

View File

@ -1,114 +0,0 @@
package com.luck.picture.lib.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2019-11-30 20:50
* @describeWeChat style selected after image preview
*/
public class PictureWeChatPreviewGalleryAdapter
extends RecyclerView.Adapter<PictureWeChatPreviewGalleryAdapter.ViewHolder> {
private List<LocalMedia> list;
private PictureSelectionConfig config;
public PictureWeChatPreviewGalleryAdapter(PictureSelectionConfig config) {
super();
this.config = config;
}
public void setNewData(List<LocalMedia> data) {
this.list = data == null ? new ArrayList<>() : data;
notifyDataSetChanged();
}
public void addSingleMediaToData(LocalMedia media) {
if (this.list != null) {
list.clear();
list.add(media);
notifyDataSetChanged();
}
}
public void removeMediaToData(LocalMedia media) {
if (this.list != null && this.list.size() > 0) {
this.list.remove(media);
notifyDataSetChanged();
}
}
public boolean isDataEmpty() {
return list == null || list.size() == 0;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.picture_wechat_preview_gallery, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
LocalMedia item = getItem(position);
if (item != null) {
holder.viewBorder.setVisibility(item.isChecked() ? View.VISIBLE : View.GONE);
if (config != null && PictureSelectionConfig.imageEngine != null) {
PictureSelectionConfig.imageEngine.loadImage(holder.itemView.getContext(), item.getPath(), holder.ivImage);
}
holder.ivPlay.setVisibility(PictureMimeType.isHasVideo(item.getMimeType()) ? View.VISIBLE : View.GONE);
holder.itemView.setOnClickListener(v -> {
if (listener != null && holder.getAdapterPosition() >= 0) {
listener.onItemClick(holder.getAdapterPosition(), getItem(position), v);
}
});
}
}
public LocalMedia getItem(int position) {
return list != null && list.size() > 0 ? list.get(position) : null;
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivImage;
ImageView ivPlay;
View viewBorder;
public ViewHolder(View itemView) {
super(itemView);
ivImage = itemView.findViewById(R.id.ivImage);
ivPlay = itemView.findViewById(R.id.ivPlay);
viewBorder = itemView.findViewById(R.id.viewBorder);
}
}
private OnItemClickListener listener;
public void setItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
public interface OnItemClickListener {
void onItemClick(int position, LocalMedia media, View v);
}
@Override
public int getItemCount() {
return list != null ? list.size() : 0;
}
}

View File

@ -1,31 +0,0 @@
package com.luck.picture.lib.animators;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
* @authorluck
* @date2020-04-18 14:11
* @describeAlphaInAnimationAdapter
*/
public class AlphaInAnimationAdapter extends BaseAnimationAdapter {
private static final float DEFAULT_ALPHA_FROM = 0f;
private final float mFrom;
public AlphaInAnimationAdapter(RecyclerView.Adapter adapter) {
this(adapter, DEFAULT_ALPHA_FROM);
}
public AlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
super(adapter);
mFrom = from;
}
@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)};
}
}

View File

@ -1,23 +0,0 @@
package com.luck.picture.lib.animators;
/**
* @authorluck
* @date2020-04-18 15:21
* @describeAnimationType
*/
public class AnimationType {
/**
* default animation
*/
public final static int DEFAULT_ANIMATION = -1;
/**
* alpha animation
*/
public final static int ALPHA_IN_ANIMATION = 1;
/**
* slide in bottom animation
*/
public final static int SLIDE_IN_BOTTOM_ANIMATION = 2;
}

View File

@ -1,127 +0,0 @@
package com.luck.picture.lib.animators;
import android.animation.Animator;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import androidx.recyclerview.widget.RecyclerView;
/**
* @authorluck
* @date2020-04-18 14:12
* @describeBaseAnimationAdapter
*/
public abstract class BaseAnimationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerView.Adapter<RecyclerView.ViewHolder> mAdapter;
private int mDuration = 250;
private Interpolator mInterpolator = new LinearInterpolator();
private int mLastPosition = -1;
private boolean isFirstOnly = true;
public BaseAnimationAdapter(RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
mAdapter = adapter;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return mAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
super.registerAdapterDataObserver(observer);
mAdapter.registerAdapterDataObserver(observer);
}
@Override
public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
super.unregisterAdapterDataObserver(observer);
mAdapter.unregisterAdapterDataObserver(observer);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mAdapter.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
mAdapter.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
mAdapter.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
mAdapter.onViewDetachedFromWindow(holder);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
mAdapter.onBindViewHolder(holder, position);
int adapterPosition = holder.getAdapterPosition();
if (!isFirstOnly || adapterPosition > mLastPosition) {
for (Animator anim : getAnimators(holder.itemView)) {
anim.setDuration(mDuration).start();
anim.setInterpolator(mInterpolator);
}
mLastPosition = adapterPosition;
} else {
ViewHelper.clear(holder.itemView);
}
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
mAdapter.onViewRecycled(holder);
super.onViewRecycled(holder);
}
@Override
public int getItemCount() {
return mAdapter.getItemCount();
}
public void setDuration(int duration) {
mDuration = duration;
}
public void setInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
}
public void setStartPosition(int start) {
mLastPosition = start;
}
protected abstract Animator[] getAnimators(View view);
public void setFirstOnly(boolean firstOnly) {
isFirstOnly = firstOnly;
}
@Override
public int getItemViewType(int position) {
return mAdapter.getItemViewType(position);
}
public RecyclerView.Adapter<RecyclerView.ViewHolder> getWrappedAdapter() {
return mAdapter;
}
@Override
public long getItemId(int position) {
return mAdapter.getItemId(position);
}
}

View File

@ -1,26 +0,0 @@
package com.luck.picture.lib.animators;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
* @authorluck
* @date2020-04-18 14:19
* @describeSlideInBottomAnimationAdapter
*/
public class SlideInBottomAnimationAdapter extends BaseAnimationAdapter {
public SlideInBottomAnimationAdapter(RecyclerView.Adapter adapter) {
super(adapter);
}
@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}
}

View File

@ -1,26 +0,0 @@
package com.luck.picture.lib.animators;
import android.view.View;
import androidx.core.view.ViewCompat;
/**
* @authorluck
* @date2020-04-18 14:13
* @describeViewHelper
*/
public final class ViewHelper {
public static void clear(View v) {
v.setAlpha(1);
v.setScaleY(1);
v.setScaleX(1);
v.setTranslationY(0);
v.setTranslationX(0);
v.setRotation(0);
v.setRotationY(0);
v.setRotationX(0);
v.setPivotY(v.getMeasuredHeight() / 2);
v.setPivotX(v.getMeasuredWidth() / 2);
ViewCompat.animate(v).setInterpolator(null).setStartDelay(0);
}
}

View File

@ -1,26 +0,0 @@
package com.luck.picture.lib.app;
import android.content.Context;
import com.luck.picture.lib.engine.PictureSelectorEngine;
/**
* @authorluck
* @date2019-12-03 15:14
* @describeIApp
*/
public interface IApp {
/**
* Application
*
* @return
*/
Context getAppContext();
/**
* PictureSelectorEngine
*
* @return
*/
PictureSelectorEngine getPictureSelectorEngine();
}

View File

@ -1,56 +0,0 @@
package com.luck.picture.lib.app;
import android.content.Context;
import com.luck.picture.lib.engine.PictureSelectorEngine;
/**
* @authorluck
* @date2019-12-03 15:12
* @describePictureAppMaster
*/
public class PictureAppMaster implements IApp {
@Override
public Context getAppContext() {
if (app == null) {
return null;
}
return app.getAppContext();
}
@Override
public PictureSelectorEngine getPictureSelectorEngine() {
if (app == null) {
return null;
}
return app.getPictureSelectorEngine();
}
private PictureAppMaster() {
}
private static PictureAppMaster mInstance;
public static PictureAppMaster getInstance() {
if (mInstance == null) {
synchronized (PictureAppMaster.class) {
if (mInstance == null) {
mInstance = new PictureAppMaster();
}
}
}
return mInstance;
}
private IApp app;
public void setApp(IApp app) {
this.app = app;
}
public IApp getApp() {
return app;
}
}

View File

@ -1,14 +0,0 @@
package com.luck.picture.lib.broadcast;
/**
* @authorluck
* @date2019-11-20 14:01
* @describe广播Action
*/
public class BroadcastAction {
/**
* 外部预览界面删除图片Action
*/
public static final String ACTION_DELETE_PREVIEW_POSITION = "com.luck.picture.lib.action.delete_preview_position";
}

View File

@ -1,250 +0,0 @@
package com.luck.picture.lib.broadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @authorluck
* @date2019-11-20 13:45
* @describe本地广播
*/
public class BroadcastManager {
private static final String TAG = BroadcastManager.class.getSimpleName();
private LocalBroadcastManager localBroadcastManager;
private Intent intent;
private String action;
public static BroadcastManager getInstance(Context ctx) {
BroadcastManager broadcastManager = new BroadcastManager();
broadcastManager.localBroadcastManager = LocalBroadcastManager.getInstance(ctx.getApplicationContext());
return broadcastManager;
}
public BroadcastManager intent(Intent intent) {
this.intent = intent;
return this;
}
public BroadcastManager action(String action) {
this.action = action;
return this;
}
public BroadcastManager extras(Bundle bundle) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtras(bundle);
return this;
}
public BroadcastManager put(String key, ArrayList<? extends Parcelable> value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, Parcelable[] value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, Parcelable value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, float value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, double value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, long value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, boolean value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, int value) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, value);
return this;
}
public BroadcastManager put(String key, String str) {
createIntent();
if (intent == null) {
Log.e(TAG, "intent create failed");
return this;
}
intent.putExtra(key, str);
return this;
}
private void createIntent() {
if (intent == null) {
Log.d(TAG, "intent is not created");
}
if (intent == null) {
if (!TextUtils.isEmpty(action)) {
intent = new Intent(action);
}
Log.d(TAG, "intent created with action");
}
}
public void broadcast() {
createIntent();
if (intent == null) {
return;
}
if (action == null) {
return;
}
intent.setAction(action);
if (null != localBroadcastManager) {
localBroadcastManager.sendBroadcast(intent);
}
}
public void registerReceiver(BroadcastReceiver br, List<String> actions) {
if (null == br || null == actions) {
return;
}
IntentFilter iFilter = new IntentFilter();
if (actions != null) {
for (String action : actions) {
iFilter.addAction(action);
}
}
if (null != localBroadcastManager) {
localBroadcastManager.registerReceiver(br, iFilter);
}
}
public void registerReceiver(BroadcastReceiver br, String... actions) {
if (actions == null || actions.length <= 0) {
return;
}
registerReceiver(br, Arrays.asList(actions));
}
/**
* @param br
*/
public void unregisterReceiver(BroadcastReceiver br) {
if (null == br) {
return;
}
try {
localBroadcastManager.unregisterReceiver(br);
} catch (Exception e) {
}
}
/**
* @param br
* @param actions 至少传入一个
*/
public void unregisterReceiver(BroadcastReceiver br, @NonNull String... actions) {
unregisterReceiver(br);
}
}

View File

@ -1,79 +0,0 @@
package com.luck.picture.lib.camera;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
/**
* =====================================
* : 陈嘉桐
* 1.1.4
* 创建日期2017/6/8
*
* =====================================
*/
public class CheckPermission {
public static final int STATE_RECORDING = -1;
public static final int STATE_NO_PERMISSION = -2;
public static final int STATE_SUCCESS = 1;
/**
* 用于检测是否具有录音权限
*
* @return
*/
public static int getRecordState() {
int minBuffer = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat
.ENCODING_PCM_16BIT);
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat
.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, (minBuffer * 100));
short[] point = new short[minBuffer];
int readSize = 0;
try {
audioRecord.startRecording();//检测是否可以进入初始化状态
} catch (Exception e) {
if (audioRecord != null) {
audioRecord.release();
audioRecord = null;
}
return STATE_NO_PERMISSION;
}
if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
//6.0以下机型都会返回此状态故使用时需要判断bulid版本
//检测是否在录音中
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
return STATE_RECORDING;
} else {
//检测是否可以获取录音结果
readSize = audioRecord.read(point, 0, point.length);
if (readSize <= 0) {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
return STATE_NO_PERMISSION;
} else {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
return STATE_SUCCESS;
}
}
}
}

View File

@ -1,547 +0,0 @@
package com.luck.picture.lib.camera;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.net.Uri;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.VideoCapture;
import androidx.camera.view.CameraView;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import com.luck.picture.lib.PictureMediaScannerConnection;
import com.luck.picture.lib.R;
import com.luck.picture.lib.camera.listener.CameraListener;
import com.luck.picture.lib.camera.listener.CaptureListener;
import com.luck.picture.lib.camera.listener.ClickListener;
import com.luck.picture.lib.camera.listener.ImageCallbackListener;
import com.luck.picture.lib.camera.listener.TypeListener;
import com.luck.picture.lib.camera.view.CaptureLayout;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.thread.PictureThreadUtils;
import com.luck.picture.lib.tools.AndroidQTransformUtils;
import com.luck.picture.lib.tools.DateUtils;
import com.luck.picture.lib.tools.MediaUtils;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.StringUtils;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
/**
* @authorluck
* @date2020-01-04 13:41
* @describe自定义相机View
*/
public class CustomCameraView extends RelativeLayout {
/**
* 只能拍照
*/
public static final int BUTTON_STATE_ONLY_CAPTURE = 0x101;
/**
* 只能录像
*/
public static final int BUTTON_STATE_ONLY_RECORDER = 0x102;
/**
* 两者都可以
*/
public static final int BUTTON_STATE_BOTH = 0x103;
/**
* 闪关灯状态
*/
private static final int TYPE_FLASH_AUTO = 0x021;
private static final int TYPE_FLASH_ON = 0x022;
private static final int TYPE_FLASH_OFF = 0x023;
private int type_flash = TYPE_FLASH_OFF;
private PictureSelectionConfig mConfig;
/**
* 回调监听
*/
private CameraListener mCameraListener;
private ClickListener mOnClickListener;
private ImageCallbackListener mImageCallbackListener;
private androidx.camera.view.CameraView mCameraView;
private ImageView mImagePreview;
private ImageView mSwitchCamera;
private ImageView mFlashLamp;
private CaptureLayout mCaptureLayout;
private MediaPlayer mMediaPlayer;
private TextureView mTextureView;
private long recordTime = 0;
private File mVideoFile;
private File mPhotoFile;
public CustomCameraView(Context context) {
this(context, null);
}
public CustomCameraView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public void initView() {
setWillNotDraw(false);
setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_black));
View view = LayoutInflater.from(getContext()).inflate(R.layout.picture_camera_view, this);
mCameraView = view.findViewById(R.id.cameraView);
mCameraView.enableTorch(true);
mTextureView = view.findViewById(R.id.video_play_preview);
mImagePreview = view.findViewById(R.id.image_preview);
mSwitchCamera = view.findViewById(R.id.image_switch);
mSwitchCamera.setImageResource(R.drawable.picture_ic_camera);
mFlashLamp = view.findViewById(R.id.image_flash);
setFlashRes();
mFlashLamp.setOnClickListener(v -> {
type_flash++;
if (type_flash > 0x023)
type_flash = TYPE_FLASH_AUTO;
setFlashRes();
});
mCaptureLayout = view.findViewById(R.id.capture_layout);
mCaptureLayout.setDuration(15 * 1000);
//切换摄像头
mSwitchCamera.setOnClickListener(v -> mCameraView.toggleCamera());
//拍照 录像
mCaptureLayout.setCaptureListener(new CaptureListener() {
@Override
public void takePictures() {
mSwitchCamera.setVisibility(INVISIBLE);
mFlashLamp.setVisibility(INVISIBLE);
mCameraView.setCaptureMode(androidx.camera.view.CameraView.CaptureMode.IMAGE);
File imageOutFile = createImageFile();
if (imageOutFile == null) {
return;
}
mPhotoFile = imageOutFile;
mCameraView.takePicture(imageOutFile, ContextCompat.getMainExecutor(getContext()),
new MyImageResultCallback(getContext(), mConfig, imageOutFile,
mImagePreview, mCaptureLayout, mImageCallbackListener, mCameraListener));
}
@Override
public void recordStart() {
mSwitchCamera.setVisibility(INVISIBLE);
mFlashLamp.setVisibility(INVISIBLE);
mCameraView.setCaptureMode(androidx.camera.view.CameraView.CaptureMode.VIDEO);
mCameraView.startRecording(createVideoFile(), ContextCompat.getMainExecutor(getContext()),
new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(@NonNull File file) {
mVideoFile = file;
if (recordTime < 1500 && mVideoFile.exists() && mVideoFile.delete()) {
return;
}
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<Boolean>() {
@Override
public Boolean doInBackground() {
return AndroidQTransformUtils.copyPathToDCIM(getContext(),
file, Uri.parse(mConfig.cameraPath));
}
@Override
public void onSuccess(Boolean result) {
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
}
});
}
mTextureView.setVisibility(View.VISIBLE);
mCameraView.setVisibility(View.INVISIBLE);
if (mTextureView.isAvailable()) {
startVideoPlay(mVideoFile);
} else {
mTextureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
@Override
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
if (mCameraListener != null) {
mCameraListener.onError(videoCaptureError, message, cause);
}
}
});
}
@Override
public void recordShort(final long time) {
recordTime = time;
mSwitchCamera.setVisibility(VISIBLE);
mFlashLamp.setVisibility(VISIBLE);
mCaptureLayout.resetCaptureLayout();
mCaptureLayout.setTextWithAnimation(getContext().getString(R.string.picture_recording_time_is_short));
mCameraView.stopRecording();
}
@Override
public void recordEnd(long time) {
recordTime = time;
mCameraView.stopRecording();
}
@Override
public void recordZoom(float zoom) {
}
@Override
public void recordError() {
if (mCameraListener != null) {
mCameraListener.onError(0, "An unknown error", null);
}
}
});
//确认 取消
mCaptureLayout.setTypeListener(new TypeListener() {
@Override
public void cancel() {
stopVideoPlay();
resetState();
}
@Override
public void confirm() {
if (mCameraView.getCaptureMode() == androidx.camera.view.CameraView.CaptureMode.VIDEO) {
if (mVideoFile == null) {
return;
}
stopVideoPlay();
if (mCameraListener != null || !mVideoFile.exists()) {
mCameraListener.onRecordSuccess(mVideoFile);
}
} else {
if (mPhotoFile == null || !mPhotoFile.exists()) {
return;
}
mImagePreview.setVisibility(INVISIBLE);
if (mCameraListener != null) {
mCameraListener.onPictureSuccess(mPhotoFile);
}
}
}
});
mCaptureLayout.setLeftClickListener(() -> {
if (mOnClickListener != null) {
mOnClickListener.onClick();
}
});
}
/**
* 拍照回调
*/
private static class MyImageResultCallback implements ImageCapture.OnImageSavedCallback {
private WeakReference<Context> mContextReference;
private WeakReference<PictureSelectionConfig> mConfigReference;
private WeakReference<File> mFileReference;
private WeakReference<ImageView> mImagePreviewReference;
private WeakReference<CaptureLayout> mCaptureLayoutReference;
private WeakReference<ImageCallbackListener> mImageCallbackListenerReference;
private WeakReference<CameraListener> mCameraListenerReference;
public MyImageResultCallback(Context context, PictureSelectionConfig config,
File imageOutFile, ImageView imagePreview,
CaptureLayout captureLayout, ImageCallbackListener imageCallbackListener,
CameraListener cameraListener) {
super();
this.mContextReference = new WeakReference<>(context);
this.mConfigReference = new WeakReference<>(config);
this.mFileReference = new WeakReference<>(imageOutFile);
this.mImagePreviewReference = new WeakReference<>(imagePreview);
this.mCaptureLayoutReference = new WeakReference<>(captureLayout);
this.mImageCallbackListenerReference = new WeakReference<>(imageCallbackListener);
this.mCameraListenerReference = new WeakReference<>(cameraListener);
}
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
if (mConfigReference.get() != null) {
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfigReference.get().cameraPath)) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<Boolean>() {
@Override
public Boolean doInBackground() {
return AndroidQTransformUtils.copyPathToDCIM(mContextReference.get(),
mFileReference.get(), Uri.parse(mConfigReference.get().cameraPath));
}
@Override
public void onSuccess(Boolean result) {
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
}
});
}
}
if (mImageCallbackListenerReference.get() != null
&& mFileReference.get() != null
&& mImagePreviewReference.get() != null) {
mImageCallbackListenerReference.get().onLoadImage(mFileReference.get(), mImagePreviewReference.get());
}
if (mImagePreviewReference.get() != null) {
mImagePreviewReference.get().setVisibility(View.VISIBLE);
}
if (mCaptureLayoutReference.get() != null) {
mCaptureLayoutReference.get().startTypeBtnAnimator();
}
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
if (mCameraListenerReference.get() != null) {
mCameraListenerReference.get().onError(exception.getImageCaptureError(), exception.getMessage(), exception.getCause());
}
}
}
private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
startVideoPlay(mVideoFile);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
public File createImageFile() {
if (SdkVersionUtils.checkedAndroid_Q()) {
String diskCacheDir = PictureFileUtils.getDiskCacheDir(getContext());
File rootDir = new File(diskCacheDir);
if (!rootDir.exists() && rootDir.mkdirs()) {
}
boolean isOutFileNameEmpty = TextUtils.isEmpty(mConfig.cameraFileName);
String suffix = TextUtils.isEmpty(mConfig.suffixType) ? PictureFileUtils.POSTFIX : mConfig.suffixType;
String newFileImageName = isOutFileNameEmpty ? DateUtils.getCreateFileName("IMG_") + suffix : mConfig.cameraFileName;
File cameraFile = new File(rootDir, newFileImageName);
Uri outUri = getOutUri(PictureMimeType.ofImage());
if (outUri != null) {
mConfig.cameraPath = outUri.toString();
}
return cameraFile;
} else {
String cameraFileName = "";
if (!TextUtils.isEmpty(mConfig.cameraFileName)) {
boolean isSuffixOfImage = PictureMimeType.isSuffixOfImage(mConfig.cameraFileName);
mConfig.cameraFileName = !isSuffixOfImage ? StringUtils.renameSuffix(mConfig.cameraFileName, PictureMimeType.JPEG) : mConfig.cameraFileName;
cameraFileName = mConfig.camera ? mConfig.cameraFileName : StringUtils.rename(mConfig.cameraFileName);
}
File cameraFile = PictureFileUtils.createCameraFile(getContext(),
PictureMimeType.ofImage(), cameraFileName, mConfig.suffixType, mConfig.outPutCameraPath);
if (cameraFile != null) {
mConfig.cameraPath = cameraFile.getAbsolutePath();
}
return cameraFile;
}
}
public File createVideoFile() {
if (SdkVersionUtils.checkedAndroid_Q()) {
String diskCacheDir = PictureFileUtils.getVideoDiskCacheDir(getContext());
File rootDir = new File(diskCacheDir);
if (!rootDir.exists() && rootDir.mkdirs()) {
}
boolean isOutFileNameEmpty = TextUtils.isEmpty(mConfig.cameraFileName);
String suffix = TextUtils.isEmpty(mConfig.suffixType) ? PictureMimeType.MP4 : mConfig.suffixType;
String newFileImageName = isOutFileNameEmpty ? DateUtils.getCreateFileName("VID_") + suffix : mConfig.cameraFileName;
File cameraFile = new File(rootDir, newFileImageName);
Uri outUri = getOutUri(PictureMimeType.ofVideo());
if (outUri != null) {
mConfig.cameraPath = outUri.toString();
}
return cameraFile;
} else {
String cameraFileName = "";
if (!TextUtils.isEmpty(mConfig.cameraFileName)) {
boolean isSuffixOfImage = PictureMimeType.isSuffixOfImage(mConfig.cameraFileName);
mConfig.cameraFileName = !isSuffixOfImage ? StringUtils
.renameSuffix(mConfig.cameraFileName, PictureMimeType.MP4) : mConfig.cameraFileName;
cameraFileName = mConfig.camera ? mConfig.cameraFileName : StringUtils.rename(mConfig.cameraFileName);
}
File cameraFile = PictureFileUtils.createCameraFile(getContext(),
PictureMimeType.ofVideo(), cameraFileName, mConfig.suffixType, mConfig.outPutCameraPath);
mConfig.cameraPath = cameraFile.getAbsolutePath();
return cameraFile;
}
}
private Uri getOutUri(int type) {
return type == PictureMimeType.ofVideo()
? MediaUtils.createVideoUri(getContext(), mConfig.suffixType) : MediaUtils.createImageUri(getContext(), mConfig.suffixType);
}
public void setCameraListener(CameraListener cameraListener) {
this.mCameraListener = cameraListener;
}
public void setPictureSelectionConfig(PictureSelectionConfig config) {
this.mConfig = config;
}
public void setBindToLifecycle(LifecycleOwner lifecycleOwner) {
mCameraView.bindToLifecycle(lifecycleOwner);
lifecycleOwner.getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> {
});
}
/**
* 设置录制视频最大时长
*/
public void setRecordVideoMaxTime(int maxDurationTime) {
mCaptureLayout.setDuration(maxDurationTime * 1000);
}
/**
* 设置录制视频最小时长
*/
public void setRecordVideoMinTime(int minDurationTime) {
mCaptureLayout.setMinDuration(minDurationTime * 1000);
}
/**
* 关闭相机界面按钮
*
* @param clickListener
*/
public void setOnClickListener(ClickListener clickListener) {
this.mOnClickListener = clickListener;
}
public void setImageCallbackListener(ImageCallbackListener mImageCallbackListener) {
this.mImageCallbackListener = mImageCallbackListener;
}
private void setFlashRes() {
switch (type_flash) {
case TYPE_FLASH_AUTO:
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_auto);
mCameraView.setFlash(ImageCapture.FLASH_MODE_AUTO);
break;
case TYPE_FLASH_ON:
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_on);
mCameraView.setFlash(ImageCapture.FLASH_MODE_ON);
break;
case TYPE_FLASH_OFF:
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_off);
mCameraView.setFlash(ImageCapture.FLASH_MODE_OFF);
break;
}
}
public CameraView getCameraView() {
return mCameraView;
}
public CaptureLayout getCaptureLayout() {
return mCaptureLayout;
}
/**
* 重置状态
*/
private void resetState() {
if (mCameraView.getCaptureMode() == androidx.camera.view.CameraView.CaptureMode.VIDEO) {
if (mCameraView.isRecording()) {
mCameraView.stopRecording();
}
if (mVideoFile != null && mVideoFile.exists()) {
mVideoFile.delete();
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
getContext().getContentResolver().delete(Uri.parse(mConfig.cameraPath), null, null);
} else {
new PictureMediaScannerConnection(getContext(), mVideoFile.getAbsolutePath());
}
}
} else {
mImagePreview.setVisibility(INVISIBLE);
if (mPhotoFile != null && mPhotoFile.exists()) {
mPhotoFile.delete();
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
getContext().getContentResolver().delete(Uri.parse(mConfig.cameraPath), null, null);
} else {
new PictureMediaScannerConnection(getContext(), mPhotoFile.getAbsolutePath());
}
}
}
mSwitchCamera.setVisibility(VISIBLE);
mFlashLamp.setVisibility(VISIBLE);
mCameraView.setVisibility(View.VISIBLE);
mCaptureLayout.resetCaptureLayout();
}
/**
* 开始循环播放视频
*
* @param videoFile
*/
private void startVideoPlay(File videoFile) {
try {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
}
mMediaPlayer.setDataSource(videoFile.getAbsolutePath());
mMediaPlayer.setSurface(new Surface(mTextureView.getSurfaceTexture()));
mMediaPlayer.setLooping(true);
mMediaPlayer.setOnPreparedListener(mp -> {
mp.start();
float ratio = mp.getVideoWidth() * 1f / mp.getVideoHeight();
int width1 = mTextureView.getWidth();
ViewGroup.LayoutParams layoutParams = mTextureView.getLayoutParams();
layoutParams.height = (int) (width1 / ratio);
mTextureView.setLayoutParams(layoutParams);
});
mMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 停止视频播放
*/
private void stopVideoPlay() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
mTextureView.setVisibility(View.GONE);
}
}

View File

@ -1,33 +0,0 @@
package com.luck.picture.lib.camera.listener;
import androidx.annotation.NonNull;
import java.io.File;
/**
* @authorluck
* @date2020-01-04 13:38
* @describe相机回调监听
*/
public interface CameraListener {
/**
* 拍照成功返回
*
* @param file
*/
void onPictureSuccess(@NonNull File file);
/**
* 录像成功返回
*
* @param file
*/
void onRecordSuccess(@NonNull File file);
/**
* 使用相机出错
*
* @param file
*/
void onError(int videoCaptureError, String message, Throwable cause);
}

View File

@ -1,19 +0,0 @@
package com.luck.picture.lib.camera.listener;
/**
* @authorluck
* @date2020-01-04 13:56
*/
public interface CaptureListener {
void takePictures();
void recordShort(long time);
void recordStart();
void recordEnd(long time);
void recordZoom(float zoom);
void recordError();
}

View File

@ -1,10 +0,0 @@
package com.luck.picture.lib.camera.listener;
/**
* @authorluck
* @date2020-01-04 13:45
* @describe点击事件监听
*/
public interface ClickListener {
void onClick();
}

View File

@ -1,20 +0,0 @@
package com.luck.picture.lib.camera.listener;
import android.widget.ImageView;
import java.io.File;
/**
* @authorluck
* @date2020-01-04 15:55
* @describe图片加载
*/
public interface ImageCallbackListener {
/**
* 加载图片回调
*
* @param file
* @param imageView
*/
void onLoadImage(File file, ImageView imageView);
}

View File

@ -1,15 +0,0 @@
package com.luck.picture.lib.camera.listener;
/**
* =====================================
* : 陈嘉桐
* 1.1.4
* 创建日期2017/4/25
*
* =====================================
*/
public interface TypeListener {
void cancel();
void confirm();
}

View File

@ -1,379 +0,0 @@
package com.luck.picture.lib.camera.view;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.view.MotionEvent;
import android.view.View;
import com.luck.picture.lib.camera.CustomCameraView;
import com.luck.picture.lib.camera.CheckPermission;
import com.luck.picture.lib.camera.listener.CaptureListener;
import com.luck.picture.lib.tools.DoubleUtils;
/**
* =====================================
* : 陈嘉桐 445263848@qq.com
* 1.1.4
* 创建日期2017/4/25
* 拍照按钮
* =====================================
*/
public class CaptureButton extends View {
private int state; //当前按钮状态
private int button_state; //按钮可执行的功能状态拍照,录制,两者
public static final int STATE_IDLE = 0x001; //空闲状态
public static final int STATE_PRESS = 0x002; //按下状态
public static final int STATE_LONG_PRESS = 0x003; //长按状态
public static final int STATE_RECORDERING = 0x004; //录制状态
public static final int STATE_BAN = 0x005; //禁止状态
private int progress_color = 0xEE16AE16; //进度条颜色
private int outside_color = 0xEEDCDCDC; //外圆背景色
private int inside_color = 0xFFFFFFFF; //内圆背景色
private float event_Y; //Touch_Event_Down时候记录的Y值
private Paint mPaint;
private float strokeWidth; //进度条宽度
private int outside_add_size; //长按外圆半径变大的Size
private int inside_reduce_size; //长安内圆缩小的Size
//中心坐标
private float center_X;
private float center_Y;
private float button_radius; //按钮半径
private float button_outside_radius; //外圆半径
private float button_inside_radius; //内圆半径
private int button_size; //按钮大小
private float progress; //录制视频的进度
private int duration; //录制视频最大时间长度
private int min_duration; //最短录制时间限制
private int recorded_time; //记录当前录制的时间
private RectF rectF;
private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable
private CaptureListener captureLisenter; //按钮回调接口
private RecordCountDownTimer timer; //计时器
public CaptureButton(Context context) {
super(context);
}
public CaptureButton(Context context, int size) {
super(context);
this.button_size = size;
button_radius = size / 2.0f;
button_outside_radius = button_radius;
button_inside_radius = button_radius * 0.75f;
strokeWidth = size / 15;
outside_add_size = size / 8;
inside_reduce_size = size / 8;
mPaint = new Paint();
mPaint.setAntiAlias(true);
progress = 0;
longPressRunnable = new LongPressRunnable();
state = STATE_IDLE; //初始化为空闲状态
button_state = CustomCameraView.BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
duration = 10 * 1000; //默认最长录制时间为10s
min_duration = 1500; //默认最短录制时间为1.5s
center_X = (button_size + outside_add_size * 2) / 2;
center_Y = (button_size + outside_add_size * 2) / 2;
rectF = new RectF(
center_X - (button_radius + outside_add_size - strokeWidth / 2),
center_Y - (button_radius + outside_add_size - strokeWidth / 2),
center_X + (button_radius + outside_add_size - strokeWidth / 2),
center_Y + (button_radius + outside_add_size - strokeWidth / 2));
timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(outside_color); //外圆半透明灰色
canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint);
mPaint.setColor(inside_color); //内圆白色
canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
//如果状态为录制状态则绘制录制进度条
if (state == STATE_RECORDERING) {
mPaint.setColor(progress_color);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(strokeWidth);
canvas.drawArc(rectF, -90, progress, false, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (event.getPointerCount() > 1 || state != STATE_IDLE)
break;
event_Y = event.getY(); //记录Y值
state = STATE_PRESS; //修改当前状态为点击按下
//判断按钮状态是否为可录制状态
if ((button_state == CustomCameraView.BUTTON_STATE_ONLY_RECORDER || button_state == CustomCameraView.BUTTON_STATE_BOTH))
postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
break;
case MotionEvent.ACTION_MOVE:
if (captureLisenter != null
&& state == STATE_RECORDERING
&& (button_state == CustomCameraView.BUTTON_STATE_ONLY_RECORDER || button_state == CustomCameraView.BUTTON_STATE_BOTH)) {
//记录当前Y值与按下时候Y值的差值调用缩放回调接口
captureLisenter.recordZoom(event_Y - event.getY());
}
break;
case MotionEvent.ACTION_UP:
//根据当前按钮的状态进行相应的处理 ----CodeReview---抬起瞬间应该重置状态 当前状态可能为按下和正在录制
//state = STATE_BAN;
handlerPressByState();
break;
}
return true;
}
//当手指松开按钮时候处理的逻辑
private void handlerPressByState() {
removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable
//根据当前状态处理
switch (state) {
//当前是点击按下
case STATE_PRESS:
if (captureLisenter != null && (button_state == CustomCameraView.BUTTON_STATE_ONLY_CAPTURE || button_state ==
CustomCameraView.BUTTON_STATE_BOTH)) {
startCaptureAnimation(button_inside_radius);
} else {
state = STATE_IDLE;
}
break;
// ---CodeReview---当内外圆动画未结束时已经是长按状态 但还没有置为STATE_RECORDERING时 应该也要结束录制 此处是一个bug
case STATE_LONG_PRESS:
//当前是长按状态
case STATE_RECORDERING:
timer.cancel(); //停止计时器
recordEnd(); //录制结束
break;
}
state = STATE_IDLE;
}
//录制结束
public void recordEnd() {
if (captureLisenter != null) {
if (recorded_time < min_duration)
captureLisenter.recordShort(recorded_time);//回调录制时间过短
else
captureLisenter.recordEnd(recorded_time); //回调录制结束
}
resetRecordAnim(); //重制按钮状态
}
//重制状态
private void resetRecordAnim() {
state = STATE_BAN;
progress = 0; //重制进度
invalidate();
//还原按钮初始状态动画
startRecordAnimation(
button_outside_radius,
button_radius,
button_inside_radius,
button_radius * 0.75f
);
}
//内圆动画
private void startCaptureAnimation(float inside_start) {
ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start);
inside_anim.addUpdateListener(animation -> {
button_inside_radius = (float) animation.getAnimatedValue();
invalidate();
});
inside_anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//回调拍照接口
// if (captureLisenter != null) {
// captureLisenter.takePictures();
// }
// 为何拍照完成要将状态掷为禁止此处貌似bug---CodeReview
//state = STATE_BAN;
//state = STATE_IDLE;
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
if (captureLisenter != null) {
captureLisenter.takePictures();
}
// 防止重复点击 状态重置
state = STATE_BAN;
}
});
inside_anim.setDuration(50);
inside_anim.start();
}
//内外圆动画
private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) {
ValueAnimator outside_anim = ValueAnimator.ofFloat(outside_start, outside_end);
ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_end);
//外圆动画监听
outside_anim.addUpdateListener(animation -> {
button_outside_radius = (float) animation.getAnimatedValue();
invalidate();
});
//内圆动画监听
inside_anim.addUpdateListener(animation -> {
button_inside_radius = (float) animation.getAnimatedValue();
invalidate();
});
AnimatorSet set = new AnimatorSet();
//当动画结束后启动录像Runnable并且回调录像开始接口
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (DoubleUtils.isFastDoubleClick()) {
return;
}
//设置为录制状态
if (state == STATE_LONG_PRESS) {
if (captureLisenter != null)
captureLisenter.recordStart();
state = STATE_RECORDERING;
timer.start();
} else {
// 此处动画包括长按起始动画和还原动画 若不是长按状态应该还原状态为空闲---CodeReview
state = STATE_IDLE;
}
}
});
set.playTogether(outside_anim, inside_anim);
set.setDuration(100);
set.start();
}
//更新进度条
private void updateProgress(long millisUntilFinished) {
recorded_time = (int) (duration - millisUntilFinished);
progress = 360f - millisUntilFinished / (float) duration * 360f;
invalidate();
}
//录制视频计时器
private class RecordCountDownTimer extends CountDownTimer {
RecordCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
updateProgress(millisUntilFinished);
}
@Override
public void onFinish() {
//updateProgress(duration);
recordEnd();
}
}
//长按线程
private class LongPressRunnable implements Runnable {
@Override
public void run() {
state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态
//没有录制权限
if (CheckPermission.getRecordState() != CheckPermission.STATE_SUCCESS) {
state = STATE_IDLE;
if (captureLisenter != null) {
captureLisenter.recordError();
return;
}
}
//启动按钮动画外圆变大内圆缩小
startRecordAnimation(
button_outside_radius,
button_outside_radius + outside_add_size,
button_inside_radius,
button_inside_radius - inside_reduce_size
);
}
}
//设置最长录制时间
public void setDuration(int duration) {
this.duration = duration;
timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
}
//设置最短录制时间
public void setMinDuration(int duration) {
this.min_duration = duration;
}
//设置回调接口
public void setCaptureListener(CaptureListener captureListener) {
this.captureLisenter = captureListener;
}
//设置按钮功能拍照和录像
public void setButtonFeatures(int state) {
this.button_state = state;
}
//设置按钮功能拍照和录像
public int getButtonFeatures() {
return button_state;
}
//是否空闲状态
public boolean isIdle() {
return state == STATE_IDLE ? true : false;
}
//设置状态
public void resetState() {
state = STATE_IDLE;
}
}

View File

@ -1,365 +0,0 @@
package com.luck.picture.lib.camera.view;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.luck.picture.lib.R;
import com.luck.picture.lib.camera.listener.CaptureListener;
import com.luck.picture.lib.camera.listener.ClickListener;
import com.luck.picture.lib.camera.listener.TypeListener;
import com.luck.picture.lib.tools.DoubleUtils;
import static com.luck.picture.lib.camera.CustomCameraView.BUTTON_STATE_ONLY_CAPTURE;
import static com.luck.picture.lib.camera.CustomCameraView.BUTTON_STATE_ONLY_RECORDER;
/**
* =====================================
* : 陈嘉桐 445263848@qq.com
* 1.0.4
* 创建日期2017/4/26
* 集成各个控件的布局
* =====================================
*/
public class CaptureLayout extends FrameLayout {
private CaptureListener captureListener; //拍照按钮监听
private TypeListener typeListener; //拍照或录制后接结果按钮监听
private ClickListener leftClickListener; //左边按钮监听
private ClickListener rightClickListener; //右边按钮监听
public void setTypeListener(TypeListener typeListener) {
this.typeListener = typeListener;
}
public void setCaptureListener(CaptureListener captureListener) {
this.captureListener = captureListener;
}
private CaptureButton btn_capture; //拍照按钮
private TypeButton btn_confirm; //确认按钮
private TypeButton btn_cancel; //取消按钮
private ReturnButton btn_return; //返回按钮
private ImageView iv_custom_left; //左边自定义按钮
private ImageView iv_custom_right; //右边自定义按钮
private TextView txt_tip; //提示文本
private int layout_width;
private int layout_height;
private int button_size;
private int iconLeft = 0;
private int iconRight = 0;
public CaptureLayout(Context context) {
this(context, null);
}
public CaptureLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CaptureLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
layout_width = outMetrics.widthPixels;
} else {
layout_width = outMetrics.widthPixels / 2;
}
button_size = (int) (layout_width / 4.5f);
layout_height = button_size + (button_size / 5) * 2 + 100;
initView();
initEvent();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(layout_width, layout_height);
}
public void initEvent() {
//默认TypeButton为隐藏
iv_custom_right.setVisibility(GONE);
btn_cancel.setVisibility(GONE);
btn_confirm.setVisibility(GONE);
}
public void startTypeBtnAnimator() {
//拍照录制结果后的动画
if (this.iconLeft != 0)
iv_custom_left.setVisibility(GONE);
else
btn_return.setVisibility(GONE);
if (this.iconRight != 0)
iv_custom_right.setVisibility(GONE);
btn_capture.setVisibility(GONE);
btn_cancel.setVisibility(VISIBLE);
btn_confirm.setVisibility(VISIBLE);
btn_cancel.setClickable(false);
btn_confirm.setClickable(false);
iv_custom_left.setVisibility(GONE);
ObjectAnimator animator_cancel = ObjectAnimator.ofFloat(btn_cancel, "translationX", layout_width / 4, 0);
ObjectAnimator animator_confirm = ObjectAnimator.ofFloat(btn_confirm, "translationX", -layout_width / 4, 0);
AnimatorSet set = new AnimatorSet();
set.playTogether(animator_cancel, animator_confirm);
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
btn_cancel.setClickable(true);
btn_confirm.setClickable(true);
}
});
set.setDuration(500);
set.start();
}
private void initView() {
setWillNotDraw(false);
//拍照按钮
btn_capture = new CaptureButton(getContext(), button_size);
FrameLayout.LayoutParams btn_capture_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
btn_capture_param.gravity = Gravity.CENTER;
btn_capture.setLayoutParams(btn_capture_param);
btn_capture.setCaptureListener(new CaptureListener() {
@Override
public void takePictures() {
if (captureListener != null) {
captureListener.takePictures();
}
startAlphaAnimation();
}
@Override
public void recordShort(long time) {
if (captureListener != null) {
captureListener.recordShort(time);
}
}
@Override
public void recordStart() {
if (captureListener != null) {
captureListener.recordStart();
}
startAlphaAnimation();
}
@Override
public void recordEnd(long time) {
if (captureListener != null) {
captureListener.recordEnd(time);
}
startTypeBtnAnimator();
}
@Override
public void recordZoom(float zoom) {
if (captureListener != null) {
captureListener.recordZoom(zoom);
}
}
@Override
public void recordError() {
if (captureListener != null) {
captureListener.recordError();
}
}
});
//取消按钮
btn_cancel = new TypeButton(getContext(), TypeButton.TYPE_CANCEL, button_size);
final LayoutParams btn_cancel_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
btn_cancel_param.gravity = Gravity.CENTER_VERTICAL;
btn_cancel_param.setMargins((layout_width / 4) - button_size / 2, 0, 0, 0);
btn_cancel.setLayoutParams(btn_cancel_param);
btn_cancel.setOnClickListener(view -> {
if (typeListener != null) {
typeListener.cancel();
}
});
//确认按钮
btn_confirm = new TypeButton(getContext(), TypeButton.TYPE_CONFIRM, button_size);
LayoutParams btn_confirm_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
btn_confirm_param.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
btn_confirm_param.setMargins(0, 0, (layout_width / 4) - button_size / 2, 0);
btn_confirm.setLayoutParams(btn_confirm_param);
btn_confirm.setOnClickListener(view -> {
if (typeListener != null) {
typeListener.confirm();
}
});
//返回按钮
btn_return = new ReturnButton(getContext(), (int) (button_size / 2.5f));
LayoutParams btn_return_param = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
btn_return_param.gravity = Gravity.CENTER_VERTICAL;
btn_return_param.setMargins(layout_width / 6, 0, 0, 0);
btn_return.setLayoutParams(btn_return_param);
btn_return.setOnClickListener(v -> {
if (leftClickListener != null) {
leftClickListener.onClick();
}
});
//左边自定义按钮
iv_custom_left = new ImageView(getContext());
LayoutParams iv_custom_param_left = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f));
iv_custom_param_left.gravity = Gravity.CENTER_VERTICAL;
iv_custom_param_left.setMargins(layout_width / 6, 0, 0, 0);
iv_custom_left.setLayoutParams(iv_custom_param_left);
iv_custom_left.setOnClickListener(v -> {
if (leftClickListener != null) {
leftClickListener.onClick();
}
});
//右边自定义按钮
iv_custom_right = new ImageView(getContext());
LayoutParams iv_custom_param_right = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f));
iv_custom_param_right.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
iv_custom_param_right.setMargins(0, 0, layout_width / 6, 0);
iv_custom_right.setLayoutParams(iv_custom_param_right);
iv_custom_right.setOnClickListener(v -> {
if (rightClickListener != null) {
rightClickListener.onClick();
}
});
txt_tip = new TextView(getContext());
LayoutParams txt_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
txt_param.gravity = Gravity.CENTER_HORIZONTAL;
txt_param.setMargins(0, 0, 0, 0);
txt_tip.setText(getCaptureTip());
txt_tip.setTextColor(0xFFFFFFFF);
txt_tip.setGravity(Gravity.CENTER);
txt_tip.setLayoutParams(txt_param);
this.addView(btn_capture);
this.addView(btn_cancel);
this.addView(btn_confirm);
this.addView(btn_return);
this.addView(iv_custom_left);
this.addView(iv_custom_right);
this.addView(txt_tip);
}
private String getCaptureTip() {
int buttonFeatures = btn_capture.getButtonFeatures();
switch (buttonFeatures) {
case BUTTON_STATE_ONLY_CAPTURE:
return getContext().getString(R.string.picture_photo_pictures);
case BUTTON_STATE_ONLY_RECORDER:
return getContext().getString(R.string.picture_photo_recording);
default:
return getContext().getString(R.string.picture_photo_camera);
}
}
public void resetCaptureLayout() {
btn_capture.resetState();
btn_cancel.setVisibility(GONE);
btn_confirm.setVisibility(GONE);
btn_capture.setVisibility(VISIBLE);
txt_tip.setText(getCaptureTip());
txt_tip.setVisibility(View.VISIBLE);
if (this.iconLeft != 0)
iv_custom_left.setVisibility(VISIBLE);
else
btn_return.setVisibility(VISIBLE);
if (this.iconRight != 0)
iv_custom_right.setVisibility(VISIBLE);
}
public void startAlphaAnimation() {
txt_tip.setVisibility(View.INVISIBLE);
}
public void setTextWithAnimation(String tip) {
txt_tip.setText(tip);
ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 0f, 1f, 1f, 0f);
animator_txt_tip.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
txt_tip.setText(getCaptureTip());
txt_tip.setAlpha(1f);
}
});
animator_txt_tip.setDuration(2500);
animator_txt_tip.start();
}
public void setDuration(int duration) {
btn_capture.setDuration(duration);
}
public void setMinDuration(int duration) {
btn_capture.setMinDuration(duration);
}
public void setButtonFeatures(int state) {
btn_capture.setButtonFeatures(state);
txt_tip.setText(getCaptureTip());
}
public void setTip(String tip) {
txt_tip.setText(tip);
}
public void showTip() {
txt_tip.setVisibility(VISIBLE);
}
public void setIconSrc(int iconLeft, int iconRight) {
this.iconLeft = iconLeft;
this.iconRight = iconRight;
if (this.iconLeft != 0) {
iv_custom_left.setImageResource(iconLeft);
iv_custom_left.setVisibility(VISIBLE);
btn_return.setVisibility(GONE);
} else {
iv_custom_left.setVisibility(GONE);
btn_return.setVisibility(VISIBLE);
}
if (this.iconRight != 0) {
iv_custom_right.setImageResource(iconRight);
iv_custom_right.setVisibility(VISIBLE);
} else {
iv_custom_right.setVisibility(GONE);
}
}
public void setLeftClickListener(ClickListener leftClickListener) {
this.leftClickListener = leftClickListener;
}
public void setRightClickListener(ClickListener rightClickListener) {
this.rightClickListener = rightClickListener;
}
}

View File

@ -1,63 +0,0 @@
package com.luck.picture.lib.camera.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.View;
/**
* =====================================
* : 陈嘉桐 445263848@qq.com
* 1.0.4
* 创建日期2017/4/26
* 向下箭头的退出按钮
* =====================================
*/
public class ReturnButton extends View {
private int size;
private int center_X;
private int center_Y;
private float strokeWidth;
private Paint paint;
Path path;
public ReturnButton(Context context, int size) {
this(context);
this.size = size;
center_X = size / 2;
center_Y = size / 2;
strokeWidth = size / 15f;
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
path = new Path();
}
public ReturnButton(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(size, size / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.moveTo(strokeWidth, strokeWidth / 2);
path.lineTo(center_X, center_Y - strokeWidth / 2);
path.lineTo(size - strokeWidth, strokeWidth / 2);
canvas.drawPath(path, paint);
}
}

View File

@ -1,109 +0,0 @@
package com.luck.picture.lib.camera.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.View;
/**
* =====================================
* : 陈嘉桐 445263848@qq.com
* 1.0.4
* 创建日期2017/4/26
* 拍照或录制完成后弹出的确认和返回按钮
* =====================================
*/
public class TypeButton extends View{
public static final int TYPE_CANCEL = 0x001;
public static final int TYPE_CONFIRM = 0x002;
private int button_type;
private int button_size;
private float center_X;
private float center_Y;
private float button_radius;
private Paint mPaint;
private Path path;
private float strokeWidth;
private float index;
private RectF rectF;
public TypeButton(Context context) {
super(context);
}
public TypeButton(Context context, int type, int size) {
super(context);
this.button_type = type;
button_size = size;
button_radius = size / 2.0f;
center_X = size / 2.0f;
center_Y = size / 2.0f;
mPaint = new Paint();
path = new Path();
strokeWidth = size / 50f;
index = button_size / 12f;
rectF = new RectF(center_X, center_Y - index, center_X + index * 2, center_Y + index);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(button_size, button_size);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//如果类型为取消则绘制内部为返回箭头
if (button_type == TYPE_CANCEL) {
mPaint.setAntiAlias(true);
mPaint.setColor(0xEEDCDCDC);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(center_X, center_Y, button_radius, mPaint);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(strokeWidth);
path.moveTo(center_X - index / 7, center_Y + index);
path.lineTo(center_X + index, center_Y + index);
path.arcTo(rectF, 90, -180);
path.lineTo(center_X - index, center_Y - index);
canvas.drawPath(path, mPaint);
mPaint.setStyle(Paint.Style.FILL);
path.reset();
path.moveTo(center_X - index, (float) (center_Y - index * 1.5));
path.lineTo(center_X - index, (float) (center_Y - index / 2.3));
path.lineTo((float) (center_X - index * 1.6), center_Y - index);
path.close();
canvas.drawPath(path, mPaint);
}
//如果类型为确认则绘制绿色勾
if (button_type == TYPE_CONFIRM) {
mPaint.setAntiAlias(true);
mPaint.setColor(0xFFFFFFFF);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(center_X, center_Y, button_radius, mPaint);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0xFF00CC00);
mPaint.setStrokeWidth(strokeWidth);
path.moveTo(center_X - button_size / 6f, center_Y);
path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 7.7f);
path.lineTo(center_X + button_size / 4.0f, center_Y - button_size / 8.5f);
path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 9.4f);
path.close();
canvas.drawPath(path, mPaint);
}
}
}

View File

@ -1,237 +0,0 @@
package com.luck.picture.lib.compress;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
enum Checker {
SINGLE;
public final static String MIME_TYPE_JPEG = "image/jpeg";
public final static String MIME_TYPE_JPG = "image/jpg";
private static final String TAG = "Luban";
private static final String JPG = ".jpg";
private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
/**
* Determine if it is JPG.
*
* @param is image file input stream
*/
boolean isJPG(InputStream is) {
return isJPG(toByteArray(is));
}
/**
* Determine if it is JPG.
*
* @param is image file mimeType
*/
boolean isJPG(String mimeType) {
if (TextUtils.isEmpty(mimeType)) {
return false;
}
return mimeType.startsWith(MIME_TYPE_JPEG) || mimeType.startsWith(MIME_TYPE_JPG);
}
/**
* Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
*/
int getOrientation(InputStream is) {
return getOrientation(toByteArray(is));
}
private boolean isJPG(byte[] data) {
if (data == null || data.length < 3) {
return false;
}
byte[] signatureB = new byte[]{data[0], data[1], data[2]};
return Arrays.equals(JPEG_SIGNATURE, signatureB);
}
private int getOrientation(byte[] jpeg) {
if (jpeg == null) {
return 0;
}
int offset = 0;
int length = 0;
// ISO/IEC 10918-1:1993(E)
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
int marker = jpeg[offset] & 0xFF;
// Check if the marker is a padding.
if (marker == 0xFF) {
continue;
}
offset++;
// Check if the marker is SOI or TEM.
if (marker == 0xD8 || marker == 0x01) {
continue;
}
// Check if the marker is EOI or SOS.
if (marker == 0xD9 || marker == 0xDA) {
break;
}
// Get the length and check if it is reasonable.
length = pack(jpeg, offset, 2, false);
if (length < 2 || offset + length > jpeg.length) {
Log.e(TAG, "Invalid length");
return 0;
}
// Break if the marker is EXIF in APP1.
if (marker == 0xE1 && length >= 8
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
&& pack(jpeg, offset + 6, 2, false) == 0) {
offset += 8;
length -= 8;
break;
}
// Skip other markers.
offset += length;
length = 0;
}
// JEITA CP-3451 Exif Version 2.2
if (length > 8) {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
Log.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);
// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
Log.e(TAG, "Invalid offset");
return 0;
}
offset += count;
length -= count;
// Get the count and go through all the elements.
count = pack(jpeg, offset - 2, 2, littleEndian);
while (count-- > 0 && length >= 12) {
// Get the tag and check if it is orientation.
tag = pack(jpeg, offset, 2, littleEndian);
if (tag == 0x0112) {
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
switch (orientation) {
case 1:
return 0;
case 3:
return 180;
case 6:
return 90;
case 8:
return 270;
}
Log.e(TAG, "Unsupported orientation");
return 0;
}
offset += 12;
length -= 12;
}
}
Log.e(TAG, "Orientation not found");
return 0;
}
String extSuffix(InputStreamProvider input) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input.open(), null, options);
return options.outMimeType.replace("image/", ".");
} catch (Exception e) {
return JPG;
}
}
String extSuffix(String mimeType) {
try {
if (TextUtils.isEmpty(mimeType)) {
return JPG;
}
return mimeType.startsWith("video") ? mimeType.replace("video/", ".")
: mimeType.replace("image/", ".");
} catch (Exception e) {
return JPG;
}
}
boolean needCompress(int leastCompressSize, String path) {
if (leastCompressSize > 0) {
File source = new File(path);
return source.exists() && source.length() > (leastCompressSize << 10);
}
return true;
}
boolean needCompressToLocalMedia(int leastCompressSize, String path) {
if (leastCompressSize > 0 && !TextUtils.isEmpty(path)) {
File source = new File(path);
return source.exists() && source.length() > (leastCompressSize << 10);
}
return true;
}
private int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}
int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
}
return value;
}
private byte[] toByteArray(InputStream is) {
if (is == null) {
return new byte[0];
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] data = new byte[4096];
try {
while ((read = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, read);
}
} catch (Exception ignored) {
return new byte[0];
} finally {
try {
buffer.close();
} catch (IOException ignored) {
}
}
return buffer.toByteArray();
}
}

View File

@ -1,19 +0,0 @@
package com.luck.picture.lib.compress;
/**
* Created on 2018/1/3 19:43
*
* @author andy
*
* A functional interface (callback) that returns true or false for the given input path should be compressed.
*/
public interface CompressionPredicate {
/**
* Determine the given input path should be compressed and return a boolean.
* @param path input path
* @return the boolean result
*/
boolean apply(String path);
}

View File

@ -1,117 +0,0 @@
package com.luck.picture.lib.compress;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Responsible for starting compress and managing active and cached resources.
*/
class Engine {
private InputStreamProvider srcImg;
private File tagImg;
private int srcWidth;
private int srcHeight;
private boolean focusAlpha;
private static final int DEFAULT_QUALITY = 80;
private int compressQuality;
Engine(InputStreamProvider srcImg, File tagImg, boolean focusAlpha, int compressQuality) throws IOException {
this.tagImg = tagImg;
this.srcImg = srcImg;
this.focusAlpha = focusAlpha;
this.compressQuality = compressQuality <= 0 ? DEFAULT_QUALITY : compressQuality;
if (srcImg.getMedia() != null
&& srcImg.getMedia().getWidth() > 0
&& srcImg.getMedia().getHeight() > 0) {
this.srcWidth = srcImg.getMedia().getWidth();
this.srcHeight = srcImg.getMedia().getHeight();
} else {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 1;
BitmapFactory.decodeStream(srcImg.open(), null, options);
this.srcWidth = options.outWidth;
this.srcHeight = options.outHeight;
}
}
private int computeSize() {
srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;
int longSide = Math.max(srcWidth, srcHeight);
int shortSide = Math.min(srcWidth, srcHeight);
float scale = ((float) shortSide / longSide);
if (scale <= 1 && scale > 0.5625) {
if (longSide < 1664) {
return 1;
} else if (longSide < 4990) {
return 2;
} else if (longSide > 4990 && longSide < 10240) {
return 4;
} else {
return longSide / 1280;
}
} else if (scale <= 0.5625 && scale > 0.5) {
return longSide / 1280 == 0 ? 1 : longSide / 1280;
} else {
return (int) Math.ceil(longSide / (1280.0 / scale));
}
}
private Bitmap rotatingImage(Bitmap bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
File compress() throws IOException {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = computeSize();
Bitmap tagBitmap = BitmapFactory.decodeStream(srcImg.open(), null, options);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
if (srcImg.getMedia() != null && !srcImg.getMedia().isCut()) {
if (Checker.SINGLE.isJPG(srcImg.getMedia().getMimeType())) {
int orientation = srcImg.getMedia().getOrientation();
if (orientation > 0) {
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
orientation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = 270;
break;
default:
break;
}
tagBitmap = rotatingImage(tagBitmap, orientation);
}
}
}
if (tagBitmap != null) {
compressQuality = compressQuality <= 0 || compressQuality > 100 ? DEFAULT_QUALITY : compressQuality;
tagBitmap.compress(focusAlpha ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, compressQuality, stream);
tagBitmap.recycle();
}
FileOutputStream fos = new FileOutputStream(tagImg);
fos.write(stream.toByteArray());
fos.flush();
fos.close();
stream.close();
return tagImg;
}
}

View File

@ -1,34 +0,0 @@
package com.luck.picture.lib.compress;
import java.io.IOException;
import java.io.InputStream;
/**
* Automatically close the previous InputStream when opening a new InputStream,
* and finally need to manually call {@link #close()} to release the resource.
*/
public abstract class InputStreamAdapter implements InputStreamProvider {
private InputStream inputStream;
@Override
public InputStream open() throws IOException {
close();
inputStream = openInternal();
return inputStream;
}
public abstract InputStream openInternal() throws IOException;
@Override
public void close() {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ignore) {
}finally {
inputStream = null;
}
}
}
}

View File

@ -1,23 +0,0 @@
package com.luck.picture.lib.compress;
import com.luck.picture.lib.entity.LocalMedia;
import java.io.IOException;
import java.io.InputStream;
/**
* 通过此接口获取输入流以兼容文件FileProvider方式获取到的图片
* <p>
* Get the input stream through this interface, and obtain the picture using compatible files and FileProvider
*/
public interface InputStreamProvider {
InputStream open() throws IOException;
void close();
String getPath();
LocalMedia getMedia();
}

View File

@ -1,638 +0,0 @@
package com.luck.picture.lib.compress;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.tools.AndroidQTransformUtils;
import com.luck.picture.lib.tools.DateUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings("unused")
public class Luban implements Handler.Callback {
private static final String TAG = "Luban";
private static final int MSG_COMPRESS_SUCCESS = 0;
private static final int MSG_COMPRESS_START = 1;
private static final int MSG_COMPRESS_ERROR = 2;
private String mTargetDir;
private String mNewFileName;
private boolean focusAlpha;
private boolean isCamera;
private int mLeastCompressSize;
private OnRenameListener mRenameListener;
private OnCompressListener mCompressListener;
private CompressionPredicate mCompressionPredicate;
private List<InputStreamProvider> mStreamProviders;
private List<String> mPaths;
private List<LocalMedia> mediaList;
private int index = -1;
private int compressQuality;
private Handler mHandler;
private int dataCount;
private Luban(Builder builder) {
this.mPaths = builder.mPaths;
this.mediaList = builder.mediaList;
this.dataCount = builder.dataCount;
this.mTargetDir = builder.mTargetDir;
this.mNewFileName = builder.mNewFileName;
this.mRenameListener = builder.mRenameListener;
this.mStreamProviders = builder.mStreamProviders;
this.mCompressListener = builder.mCompressListener;
this.mLeastCompressSize = builder.mLeastCompressSize;
this.mCompressionPredicate = builder.mCompressionPredicate;
this.compressQuality = builder.compressQuality;
this.focusAlpha = builder.focusAlpha;
this.isCamera = builder.isCamera;
this.mHandler = new Handler(Looper.getMainLooper(), this);
}
public static Builder with(Context context) {
return new Builder(context);
}
/**
* Returns a file with a cache image name in the private cache directory.
*
* @param context A context.
*/
private File getImageCacheFile(Context context, InputStreamProvider provider, String suffix) {
if (TextUtils.isEmpty(mTargetDir)) {
File imageCacheDir = getImageCacheDir(context);
if (imageCacheDir != null) {
mTargetDir = imageCacheDir.getAbsolutePath();
}
}
String cacheBuilder = "";
try {
LocalMedia media = provider.getMedia();
String encryptionValue = StringUtils.getEncryptionValue(media.getPath(), media.getWidth(), media.getHeight());
if (!TextUtils.isEmpty(encryptionValue) && !media.isCut()) {
cacheBuilder = mTargetDir + "/" +
"IMG_CMP_" +
encryptionValue +
(TextUtils.isEmpty(suffix) ? ".jpg" : suffix);
} else {
cacheBuilder = mTargetDir +
"/" +
DateUtils.getCreateFileName("IMG_CMP_") +
(TextUtils.isEmpty(suffix) ? ".jpg" : suffix);
}
} catch (Exception e) {
e.printStackTrace();
}
return new File(cacheBuilder);
}
private File getImageCustomFile(Context context, String filename) {
if (TextUtils.isEmpty(mTargetDir)) {
mTargetDir = getImageCacheDir(context).getAbsolutePath();
}
String cacheBuilder = mTargetDir + "/" + filename;
return new File(cacheBuilder);
}
/**
* Returns a directory with the given name in the private cache directory of the application to
* use to store retrieved media and thumbnails.
*
* @param context A context.
* @see #getImageCacheDir(Context)
*/
private static File getImageCacheDir(Context context) {
File cacheDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (cacheDir != null) {
if (!cacheDir.mkdirs() && (!cacheDir.exists() || !cacheDir.isDirectory())) {
// File wasn't able to create a directory, or the result exists but not a directory
return null;
}
return cacheDir;
}
if (Log.isLoggable(TAG, Log.ERROR)) {
Log.e(TAG, "default disk cache dir is null");
}
return null;
}
/**
* start asynchronous compress thread
*/
private void launch(final Context context) {
if (mStreamProviders == null || mPaths == null || mStreamProviders.size() == 0 && mCompressListener != null) {
mCompressListener.onError(new NullPointerException("image file cannot be null"));
}
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
// 当前压缩下标
index = -1;
while (iterator.hasNext()) {
final InputStreamProvider path = iterator.next();
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
try {
index++;
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_START));
String newPath;
if (path.open() != null) {
if (path.getMedia().isCompressed()
&& !TextUtils.isEmpty(path.getMedia().getCompressPath())) {
// 压缩过的图片不重复压缩 注意:如果是开启了裁剪 就算压缩过也要重新压缩
boolean exists = !path.getMedia().isCut() && new File(path.getMedia().getCompressPath()).exists();
File result = exists ? new File(path.getMedia().getCompressPath())
: compress(context, path);
newPath = result.getAbsolutePath();
} else {
File result = PictureMimeType.isHasVideo(path.getMedia().getMimeType())
? new File(path.getPath()) : compress(context, path);
newPath = result.getAbsolutePath();
}
} else {
// error
newPath = path.getPath();
}
if (mediaList != null && mediaList.size() > 0) {
LocalMedia media = mediaList.get(index);
boolean isHasHttp = PictureMimeType.isHasHttp(newPath);
boolean isHasVideo = PictureMimeType.isHasVideo(media.getMimeType());
media.setCompressed(!isHasHttp && !isHasVideo);
media.setCompressPath(isHasHttp || isHasVideo ? null : newPath);
media.setAndroidQToPath(SdkVersionUtils.checkedAndroid_Q() ? media.getCompressPath() : null);
boolean isLast = index == mediaList.size() - 1;
if (isLast) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_SUCCESS, mediaList));
}
} else {
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, new IOException()));
}
} catch (IOException e) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, e));
}
});
iterator.remove();
}
}
/**
* start compress and return the file
*/
private File get(InputStreamProvider input, Context context) throws IOException {
try {
return new Engine(input, getImageCacheFile(context, input, Checker.SINGLE.extSuffix(input)), focusAlpha, compressQuality).compress();
} finally {
input.close();
}
}
private List<File> get(Context context) throws IOException {
List<File> results = new ArrayList<>();
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
while (iterator.hasNext()) {
InputStreamProvider provider = iterator.next();
InputStream inputStream = provider.open();
if (inputStream != null) {
if (provider.getMedia().isCompressed()
&& !TextUtils.isEmpty(provider.getMedia().getCompressPath())) {
// 压缩过的图片不重复压缩 注意:如果是开启了裁剪 就算压缩过也要重新压缩
boolean exists = !provider.getMedia().isCut() && new File(provider.getMedia().getCompressPath()).exists();
File oldFile = exists ? new File(provider.getMedia().getCompressPath())
: compress(context, provider);
results.add(oldFile);
} else {
boolean hasVideo = PictureMimeType.isHasVideo(provider.getMedia().getMimeType());
results.add(hasVideo ? new File(provider.getMedia().getPath()) : compress(context, provider));
}
} else {
// error
results.add(new File(provider.getMedia().getPath()));
}
iterator.remove();
}
return results;
}
private File compress(Context context, InputStreamProvider path) throws IOException {
try {
return compressRealLocalMedia(context, path);
} finally {
path.close();
}
}
private File compressReal(Context context, InputStreamProvider path) throws IOException {
File result;
String suffix = Checker.SINGLE.extSuffix(path.getMedia() != null ? path.getMedia().getMimeType() : "");
File outFile = getImageCacheFile(context, path, TextUtils.isEmpty(suffix) ? Checker.SINGLE.extSuffix(path) : suffix);
if (mRenameListener != null) {
String filename = mRenameListener.rename(path.getPath());
outFile = getImageCustomFile(context, filename);
}
if (mCompressionPredicate != null) {
if (mCompressionPredicate.apply(path.getPath())
&& Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath())) {
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
} else {
result = new File(path.getPath());
}
} else {
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
// GIF without compression
result = new File(path.getPath());
} else {
result = Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath()) ?
new Engine(path, outFile, focusAlpha, compressQuality).compress() :
new File(path.getPath());
}
}
return result;
}
private File compressRealLocalMedia(Context context, InputStreamProvider path) throws IOException {
File result = null;
LocalMedia media = path.getMedia();
if (media == null) {
throw new NullPointerException("Luban Compress LocalMedia Can't be empty");
}
String newPath = media.isCut() && !TextUtils.isEmpty(media.getCutPath()) ? media.getCutPath() : media.getRealPath();
String suffix = Checker.SINGLE.extSuffix(media.getMimeType());
File outFile = getImageCacheFile(context, path, TextUtils.isEmpty(suffix) ? Checker.SINGLE.extSuffix(path) : suffix);
String filename = "";
if (!TextUtils.isEmpty(mNewFileName)) {
filename = isCamera || dataCount == 1 ? mNewFileName : StringUtils.rename(mNewFileName);
outFile = getImageCustomFile(context, filename);
}
// 如果文件存在直接返回不处理
if (outFile.exists()) {
return outFile;
}
if (mCompressionPredicate != null) {
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
// GIF without compression
if (SdkVersionUtils.checkedAndroid_Q()) {
if (media.isCut() && !TextUtils.isEmpty(media.getCutPath())) {
result = new File(media.getCutPath());
} else {
String androidQToPath = AndroidQTransformUtils.copyPathToAndroidQ(context, path.getPath(),
media.getWidth(), media.getHeight(), media.getMimeType(), filename);
if (!TextUtils.isEmpty(androidQToPath)) {
result = new File(androidQToPath);
}
}
} else {
result = new File(newPath);
}
} else {
boolean isCompress = Checker.SINGLE.needCompressToLocalMedia(mLeastCompressSize, newPath);
if (mCompressionPredicate.apply(newPath) && isCompress) {
// 压缩
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
} else {
if (isCompress) {
// 压缩
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
}
}
}
} else {
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
// GIF without compression
if (SdkVersionUtils.checkedAndroid_Q()) {
String newFilePath = media.isCut() ? media.getCutPath() :
AndroidQTransformUtils.copyPathToAndroidQ(context,
path.getPath(), media.getWidth(), media.getHeight(), media.getMimeType(), filename);
if (!TextUtils.isEmpty(newFilePath)) {
result = new File(newFilePath);
}
} else {
result = new File(newPath);
}
} else {
boolean isCompress = Checker.SINGLE.needCompressToLocalMedia(mLeastCompressSize, newPath);
if (isCompress) {
// 压缩
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
}
}
}
return result;
}
@Override
public boolean handleMessage(Message msg) {
if (mCompressListener == null) return false;
switch (msg.what) {
case MSG_COMPRESS_START:
mCompressListener.onStart();
break;
case MSG_COMPRESS_SUCCESS:
mCompressListener.onSuccess((List<LocalMedia>) msg.obj);
break;
case MSG_COMPRESS_ERROR:
mCompressListener.onError((Throwable) msg.obj);
break;
}
return false;
}
public static class Builder {
private Context context;
private String mTargetDir;
private String mNewFileName;
private boolean focusAlpha;
private boolean isCamera;
private int compressQuality;
private int mLeastCompressSize = 100;
private OnRenameListener mRenameListener;
private OnCompressListener mCompressListener;
private CompressionPredicate mCompressionPredicate;
private List<InputStreamProvider> mStreamProviders;
private List<String> mPaths;
private List<LocalMedia> mediaList;
private int dataCount;
private boolean isAndroidQ;
Builder(Context context) {
this.context = context;
this.mPaths = new ArrayList<>();
this.mediaList = new ArrayList<>();
this.mStreamProviders = new ArrayList<>();
this.isAndroidQ = SdkVersionUtils.checkedAndroid_Q();
}
private Luban build() {
return new Luban(this);
}
public Builder load(InputStreamProvider inputStreamProvider) {
mStreamProviders.add(inputStreamProvider);
return this;
}
/**
* 扩展符合PictureSelector的压缩策略
*
* @param list LocalMedia集合
* @param <T>
* @return
*/
public <T> Builder loadMediaData(List<LocalMedia> list) {
this.mediaList = list;
this.dataCount = list.size();
for (LocalMedia src : list) {
load(src);
}
return this;
}
/**
* 扩展符合PictureSelector的压缩策略
*
* @param media LocalMedia对象
* @param <T>
* @return
*/
private Builder load(final LocalMedia media) {
mStreamProviders.add(new InputStreamAdapter() {
@Override
public InputStream openInternal() throws IOException {
if (PictureMimeType.isContent(media.getPath()) && !media.isCut()) {
if (!TextUtils.isEmpty(media.getAndroidQToPath())) {
return new FileInputStream(media.getAndroidQToPath());
}
return context.getContentResolver().openInputStream(Uri.parse(media.getPath()));
} else {
return PictureMimeType.isHasHttp(media.getPath()) ? null : new FileInputStream(media.isCut() ? media.getCutPath() : media.getPath());
}
}
@Override
public String getPath() {
if (media.isCut()) {
return media.getCutPath();
} else {
return TextUtils.isEmpty(media.getAndroidQToPath()) ? media.getPath() : media.getAndroidQToPath();
}
}
@Override
public LocalMedia getMedia() {
return media;
}
});
return this;
}
public Builder load(final Uri uri) {
mStreamProviders.add(new InputStreamAdapter() {
@Override
public InputStream openInternal() throws IOException {
return context.getContentResolver().openInputStream(uri);
}
@Override
public String getPath() {
return uri.getPath();
}
@Override
public LocalMedia getMedia() {
return null;
}
});
return this;
}
public Builder load(final File file) {
mStreamProviders.add(new InputStreamAdapter() {
@Override
public InputStream openInternal() throws IOException {
return new FileInputStream(file);
}
@Override
public String getPath() {
return file.getAbsolutePath();
}
@Override
public LocalMedia getMedia() {
return null;
}
});
return this;
}
public Builder load(final String string) {
mStreamProviders.add(new InputStreamAdapter() {
@Override
public InputStream openInternal() throws IOException {
return new FileInputStream(string);
}
@Override
public String getPath() {
return string;
}
@Override
public LocalMedia getMedia() {
return null;
}
});
return this;
}
public <T> Builder load(List<T> list) {
for (T src : list) {
if (src instanceof String) {
load((String) src);
} else if (src instanceof File) {
load((File) src);
} else if (src instanceof Uri) {
load((Uri) src);
} else {
throw new IllegalArgumentException("Incoming data type exception, it must be String, File, Uri or Bitmap");
}
}
return this;
}
public Builder putGear(int gear) {
return this;
}
@Deprecated
public Builder setRenameListener(OnRenameListener listener) {
this.mRenameListener = listener;
return this;
}
public Builder setCompressListener(OnCompressListener listener) {
this.mCompressListener = listener;
return this;
}
public Builder setTargetDir(String targetDir) {
this.mTargetDir = targetDir;
return this;
}
public Builder setNewCompressFileName(String newFileName) {
this.mNewFileName = newFileName;
return this;
}
public Builder isCamera(boolean isCamera) {
this.isCamera = isCamera;
return this;
}
/**
* Do I need to keep the image's alpha channel
*
* @param focusAlpha <p> true - to keep alpha channel, the compress speed will be slow. </p>
* <p> false - don't keep alpha channel, it might have a black background.</p>
*/
public Builder setFocusAlpha(boolean focusAlpha) {
this.focusAlpha = focusAlpha;
return this;
}
/**
* Image compressed output quality
*
* @param compressQuality The quality is better than
*/
public Builder setCompressQuality(int compressQuality) {
this.compressQuality = compressQuality;
return this;
}
/**
* do not compress when the origin image file size less than one value
*
* @param size the value of file size, unit KB, default 100K
*/
public Builder ignoreBy(int size) {
this.mLeastCompressSize = size;
return this;
}
/**
* do compress image when return value was true, otherwise, do not compress the image file
*
* @param compressionPredicate A predicate callback that returns true or false for the given input path should be compressed.
*/
public Builder filter(CompressionPredicate compressionPredicate) {
this.mCompressionPredicate = compressionPredicate;
return this;
}
/**
* begin compress image with asynchronous
*/
public void launch() {
build().launch(context);
}
public File get(final String path) throws IOException {
return build().get(new InputStreamAdapter() {
@Override
public InputStream openInternal() throws IOException {
return new FileInputStream(path);
}
@Override
public String getPath() {
return path;
}
@Override
public LocalMedia getMedia() {
return null;
}
}, context);
}
/**
* begin compress image with synchronize
*
* @return the thumb image file list
*/
public List<File> get() throws IOException {
return build().get(context);
}
}
}

View File

@ -1,23 +0,0 @@
package com.luck.picture.lib.compress;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.List;
public interface OnCompressListener {
/**
* Fired when the compression is started, override to handle in your own code
*/
void onStart();
/**
* Fired when a compression returns successfully, override to handle in your own code
*/
void onSuccess(List<LocalMedia> list);
/**
* Fired when a compression fails to complete, override to handle in your own code
*/
void onError(Throwable e);
}

View File

@ -1,22 +0,0 @@
package com.luck.picture.lib.compress;
/**
* Author: zibin
* Datetime: 2018/5/18
* <p>
* 提供修改压缩图片命名接口
* <p>
* A functional interface (callback) that used to rename the file after compress.
*/
public interface OnRenameListener {
/**
* 压缩前调用该方法用于修改压缩后文件名
* <p>
* Call before compression begins.
*
* @param filePath 传入文件路径/ file path
* @return 返回重命名后的字符串/ file name
*/
String rename(String filePath);
}

View File

@ -1,71 +0,0 @@
package com.luck.picture.lib.config;
/**
* @authorluck
* @data2017/5/24 1:00
* @describe : constant
*/
public final class PictureConfig {
public final static int APPLY_STORAGE_PERMISSIONS_CODE = 1;
public final static int APPLY_CAMERA_PERMISSIONS_CODE = 2;
public final static int APPLY_AUDIO_PERMISSIONS_CODE = 3;
public final static int APPLY_RECORD_AUDIO_PERMISSIONS_CODE = 4;
public final static int APPLY_CAMERA_STORAGE_PERMISSIONS_CODE = 5;
public final static String EXTRA_MEDIA_KEY = "mediaKey";
public final static String EXTRA_MEDIA_PATH = "mediaPath";
public final static String EXTRA_AUDIO_PATH = "audioPath";
public final static String EXTRA_VIDEO_PATH = "videoPath";
public final static String EXTRA_PREVIEW_VIDEO = "isExternalPreviewVideo";
public final static String EXTRA_PREVIEW_DELETE_POSITION = "position";
public final static String EXTRA_FC_TAG = "picture";
public final static String EXTRA_RESULT_SELECTION = "extra_result_media";
public final static String EXTRA_PREVIEW_SELECT_LIST = "previewSelectList";
public final static String EXTRA_SELECT_LIST = "selectList";
public final static String EXTRA_COMPLETE_SELECTED = "isCompleteOrSelected";
public final static String EXTRA_CHANGE_SELECTED_DATA = "isChangeSelectedData";
public final static String EXTRA_CHANGE_ORIGINAL = "isOriginal";
public final static String EXTRA_POSITION = "position";
public final static String EXTRA_OLD_CURRENT_LIST_SIZE = "oldCurrentListSize";
public final static String EXTRA_DIRECTORY_PATH = "directory_path";
public final static String EXTRA_BOTTOM_PREVIEW = "bottom_preview";
public final static String EXTRA_CONFIG = "PictureSelectorConfig";
public final static String EXTRA_SHOW_CAMERA = "isShowCamera";
public final static String EXTRA_IS_CURRENT_DIRECTORY = "currentDirectory";
public final static String EXTRA_BUCKET_ID = "bucket_id";
public final static String EXTRA_PAGE = "page";
public final static String EXTRA_DATA_COUNT = "count";
public final static String CAMERA_FACING = "android.intent.extras.CAMERA_FACING";
public final static String EXTRA_ALL_FOLDER_SIZE = "all_folder_size";
public final static String EXTRA_QUICK_CAPTURE = "android.intent.extra.quickCapture";
public final static int MAX_PAGE_SIZE = 60;
public final static int MIN_PAGE_SIZE = 10;
public final static int LOADED = 0;
public final static int NORMAL = -1;
public final static int CAMERA_BEFORE = 1;
public final static int TYPE_ALL = 0;
public final static int TYPE_IMAGE = 1;
public final static int TYPE_VIDEO = 2;
@Deprecated
public final static int TYPE_AUDIO = 3;
public final static int MAX_COMPRESS_SIZE = 100;
public final static int TYPE_CAMERA = 1;
public final static int TYPE_PICTURE = 2;
public final static int SINGLE = 1;
public final static int MULTIPLE = 2;
public final static int PREVIEW_VIDEO_CODE = 166;
public final static int CHOOSE_REQUEST = 188;
public final static int REQUEST_CAMERA = 909;
}

View File

@ -1,345 +0,0 @@
package com.luck.picture.lib.config;
import android.content.Context;
import android.text.TextUtils;
import com.luck.picture.lib.R;
import java.io.File;
/**
* @authorluck
* @date2017-5-24 17:02
* @describePictureMimeType
*/
public final class PictureMimeType {
public static int ofAll() {
return PictureConfig.TYPE_ALL;
}
public static int ofImage() {
return PictureConfig.TYPE_IMAGE;
}
public static int ofVideo() {
return PictureConfig.TYPE_VIDEO;
}
/**
* # No longer maintain audio related functions,
* but can continue to use but there will be phone compatibility issues
* <p>
* 不再维护音频相关功能但可以继续使用但会有机型兼容性问题
*/
@Deprecated
public static int ofAudio() {
return PictureConfig.TYPE_AUDIO;
}
public static String ofPNG() {
return MIME_TYPE_PNG;
}
public static String ofJPEG() {
return MIME_TYPE_JPEG;
}
public static String ofBMP() {
return MIME_TYPE_BMP;
}
public static String ofGIF() {
return MIME_TYPE_GIF;
}
public static String ofWEBP() {
return MIME_TYPE_WEBP;
}
public static String of3GP() {
return MIME_TYPE_3GP;
}
public static String ofMP4() {
return MIME_TYPE_MP4;
}
public static String ofMPEG() {
return MIME_TYPE_MPEG;
}
public static String ofAVI() {
return MIME_TYPE_AVI;
}
private final static String MIME_TYPE_PNG = "image/png";
public final static String MIME_TYPE_JPEG = "image/jpeg";
private final static String MIME_TYPE_JPG = "image/jpg";
private final static String MIME_TYPE_BMP = "image/bmp";
private final static String MIME_TYPE_GIF = "image/gif";
private final static String MIME_TYPE_WEBP = "image/webp";
private final static String MIME_TYPE_3GP = "video/3gp";
private final static String MIME_TYPE_MP4 = "video/mp4";
private final static String MIME_TYPE_MPEG = "video/mpeg";
private final static String MIME_TYPE_AVI = "video/avi";
/**
* isGif
*
* @param mimeType
* @return
*/
public static boolean isGif(String mimeType) {
return mimeType != null && (mimeType.equals("image/gif") || mimeType.equals("image/GIF"));
}
/**
* isVideo
*
* @param mimeType
* @return
*/
public static boolean isHasVideo(String mimeType) {
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_VIDEO);
}
/**
* isVideo
*
* @param url
* @return
*/
public static boolean isUrlHasVideo(String url) {
return url.endsWith(".mp4");
}
/**
* isAudio
*
* @param mimeType
* @return
*/
public static boolean isHasAudio(String mimeType) {
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_AUDIO);
}
/**
* isImage
*
* @param mimeType
* @return
*/
public static boolean isHasImage(String mimeType) {
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_IMAGE);
}
/**
* Determine if it is JPG.
*
* @param is image file mimeType
*/
public static boolean isJPEG(String mimeType) {
if (TextUtils.isEmpty(mimeType)) {
return false;
}
return mimeType.startsWith(MIME_TYPE_JPEG) || mimeType.startsWith(MIME_TYPE_JPG);
}
/**
* Determine if it is JPG.
*
* @param is image file mimeType
*/
public static boolean isJPG(String mimeType) {
if (TextUtils.isEmpty(mimeType)) {
return false;
}
return mimeType.startsWith(MIME_TYPE_JPG);
}
/**
* is Network image
*
* @param path
* @return
*/
public static boolean isHasHttp(String path) {
if (TextUtils.isEmpty(path)) {
return false;
}
return path.startsWith("http")
|| path.startsWith("https")
|| path.startsWith("/http")
|| path.startsWith("/https");
}
/**
* Determine whether the file type is an image or a video
*
* @param cameraMimeType
* @return
*/
public static String getMimeType(int cameraMimeType) {
switch (cameraMimeType) {
case PictureConfig.TYPE_VIDEO:
return MIME_TYPE_VIDEO;
case PictureConfig.TYPE_AUDIO:
return MIME_TYPE_AUDIO;
default:
return MIME_TYPE_IMAGE;
}
}
/**
* Determines if the file name is a picture
*
* @param name
* @return
*/
public static boolean isSuffixOfImage(String name) {
return !TextUtils.isEmpty(name) && name.endsWith(".PNG") || name.endsWith(".png") || name.endsWith(".jpeg")
|| name.endsWith(".gif") || name.endsWith(".GIF") || name.endsWith(".jpg")
|| name.endsWith(".webp") || name.endsWith(".WEBP") || name.endsWith(".JPEG")
|| name.endsWith(".bmp");
}
/**
* Is it the same type
*
* @param oldMimeType
* @param newMimeType
* @return
*/
public static boolean isMimeTypeSame(String oldMimeType, String newMimeType) {
return getMimeType(oldMimeType) == getMimeType(newMimeType);
}
/**
* Get Image mimeType
*
* @param path
* @return
*/
public static String getImageMimeType(String path) {
try {
if (!TextUtils.isEmpty(path)) {
File file = new File(path);
String fileName = file.getName();
int last = fileName.lastIndexOf(".") + 1;
String temp = fileName.substring(last);
return "image/" + temp;
}
} catch (Exception e) {
e.printStackTrace();
return MIME_TYPE_IMAGE;
}
return MIME_TYPE_IMAGE;
}
/**
* Picture or video
*
* @return
*/
public static int getMimeType(String mimeType) {
if (TextUtils.isEmpty(mimeType)) {
return PictureConfig.TYPE_IMAGE;
}
if (mimeType.startsWith(MIME_TYPE_PREFIX_VIDEO)) {
return PictureConfig.TYPE_VIDEO;
} else if (mimeType.startsWith(MIME_TYPE_PREFIX_AUDIO)) {
return PictureConfig.TYPE_AUDIO;
} else {
return PictureConfig.TYPE_IMAGE;
}
}
/**
* Get image suffix
*
* @param mineType
* @return
*/
public static String getLastImgSuffix(String mineType) {
String defaultSuffix = PNG;
try {
int index = mineType.lastIndexOf("/") + 1;
if (index > 0) {
return "." + mineType.substring(index);
}
} catch (Exception e) {
e.printStackTrace();
return defaultSuffix;
}
return defaultSuffix;
}
/**
* is content://
*
* @param url
* @return
*/
public static boolean isContent(String url) {
if (TextUtils.isEmpty(url)) {
return false;
}
return url.startsWith("content://");
}
/**
* Returns an error message by type
*
* @param context
* @param mimeType
* @return
*/
public static String s(Context context, String mimeType) {
Context ctx = context.getApplicationContext();
if (isHasVideo(mimeType)) {
return ctx.getString(R.string.picture_video_error);
} else if (isHasAudio(mimeType)) {
return ctx.getString(R.string.picture_audio_error);
} else {
return ctx.getString(R.string.picture_error);
}
}
public final static String JPEG = ".jpg";
private final static String PNG = ".png";
public final static String MP4 = ".mp4";
public final static String JPEG_Q = "image/jpeg";
public final static String PNG_Q = "image/png";
public final static String MP4_Q = "video/mp4";
public final static String AVI_Q = "video/avi";
public final static String DCIM = "DCIM/Camera";
public final static String CAMERA = "Camera";
public final static String MIME_TYPE_IMAGE = "image/jpeg";
public final static String MIME_TYPE_VIDEO = "video/mp4";
public final static String MIME_TYPE_AUDIO = "audio/mpeg";
private final static String MIME_TYPE_PREFIX_IMAGE = "image";
private final static String MIME_TYPE_PREFIX_VIDEO = "video";
private final static String MIME_TYPE_PREFIX_AUDIO = "audio";
}

View File

@ -1,521 +0,0 @@
package com.luck.picture.lib.config;
import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.ColorInt;
import androidx.annotation.StyleRes;
import com.luck.picture.lib.R;
import com.luck.picture.lib.camera.CustomCameraView;
import com.luck.picture.lib.engine.CacheResourcesEngine;
import com.luck.picture.lib.engine.ImageEngine;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.listener.OnCustomCameraInterfaceListener;
import com.luck.picture.lib.listener.OnResultCallbackListener;
import com.luck.picture.lib.listener.OnVideoSelectedPlayCallback;
import com.luck.picture.lib.style.PictureCropParameterStyle;
import com.luck.picture.lib.style.PictureParameterStyle;
import com.luck.picture.lib.style.PictureWindowAnimationStyle;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2017-05-24 17:02
* @describePictureSelector Config
*/
public final class PictureSelectionConfig implements Parcelable {
public int chooseMode;
public boolean camera;
public boolean isSingleDirectReturn;
public PictureParameterStyle style;
public PictureCropParameterStyle cropStyle;
public PictureWindowAnimationStyle windowAnimationStyle;
public String compressSavePath;
public String suffixType;
public boolean focusAlpha;
public String renameCompressFileName;
public String renameCropFileName;
public String specifiedFormat;
public int requestedOrientation;
public int buttonFeatures;
public boolean isCameraAroundState;
public boolean isAndroidQTransform;
@StyleRes
public int themeStyleId;
public int selectionMode;
public int maxSelectNum;
public int minSelectNum;
public int maxVideoSelectNum;
public int minVideoSelectNum;
public int videoQuality;
public int cropCompressQuality;
public int videoMaxSecond;
public int videoMinSecond;
public int recordVideoSecond;
public int recordVideoMinSecond;
public int minimumCompressSize;
public int imageSpanCount;
public int aspect_ratio_x;
public int aspect_ratio_y;
public int cropWidth;
public int cropHeight;
public int compressQuality;
public float filterFileSize;
public int language;
public boolean isMultipleRecyclerAnimation;
public boolean isMultipleSkipCrop;
public boolean isWeChatStyle;
public boolean isUseCustomCamera;
public boolean zoomAnim;
public boolean isCompress;
public boolean isOriginalControl;
public boolean isCamera;
public boolean isGif;
public boolean enablePreview;
public boolean enPreviewVideo;
public boolean enablePreviewAudio;
public boolean checkNumMode;
public boolean openClickSound;
public boolean enableCrop;
public boolean freeStyleCropEnabled;
public boolean circleDimmedLayer;
@ColorInt
public int circleDimmedColor;
@ColorInt
public int circleDimmedBorderColor;
public int circleStrokeWidth;
public boolean showCropFrame;
public boolean showCropGrid;
public boolean hideBottomControls;
public boolean rotateEnabled;
public boolean scaleEnabled;
public boolean previewEggs;
public boolean synOrAsy;
public boolean returnEmpty;
public boolean isDragFrame;
public boolean isNotPreviewDownload;
public boolean isWithVideoImage;
public UCropOptions uCropOptions;
public static ImageEngine imageEngine;
public static CacheResourcesEngine cacheResourcesEngine;
public static OnResultCallbackListener listener;
public static OnVideoSelectedPlayCallback customVideoPlayCallback;
public static OnCustomCameraInterfaceListener onCustomCameraInterfaceListener;
public List<LocalMedia> selectionMedias;
public String cameraFileName;
public boolean isCheckOriginalImage;
@Deprecated
public int overrideWidth;
@Deprecated
public int overrideHeight;
@Deprecated
public float sizeMultiplier;
@Deprecated
public boolean isChangeStatusBarFontColor;
@Deprecated
public boolean isOpenStyleNumComplete;
@Deprecated
public boolean isOpenStyleCheckNumMode;
@Deprecated
public int titleBarBackgroundColor;
@Deprecated
public int pictureStatusBarColor;
@Deprecated
public int cropTitleBarBackgroundColor;
@Deprecated
public int cropStatusBarColorPrimaryDark;
@Deprecated
public int cropTitleColor;
@Deprecated
public int upResId;
@Deprecated
public int downResId;
public String outPutCameraPath;
public String originalPath;
public String cameraPath;
public int cameraMimeType;
public int pageSize;
public boolean isPageStrategy;
public boolean isFilterInvalidFile;
public boolean isMaxSelectEnabledMask;
public int animationMode;
public boolean isAutomaticTitleRecyclerTop;
public boolean isCallbackMode;
public boolean isAndroidQChangeWH;
public boolean isAndroidQChangeVideoWH;
public boolean isQuickCapture;
/**
* 内测专用###########
*/
public boolean isFallbackVersion;
public boolean isFallbackVersion2;
public boolean isFallbackVersion3;
protected void initDefaultValue() {
chooseMode = PictureMimeType.ofImage();
camera = false;
themeStyleId = R.style.picture_default_style;
selectionMode = PictureConfig.MULTIPLE;
maxSelectNum = 9;
minSelectNum = 0;
maxVideoSelectNum = 0;
minVideoSelectNum = 0;
videoQuality = 1;
language = -1;
cropCompressQuality = 90;
videoMaxSecond = 0;
videoMinSecond = 0;
filterFileSize = -1;
recordVideoSecond = 60;
recordVideoMinSecond = 0;
compressQuality = 80;
minimumCompressSize = PictureConfig.MAX_COMPRESS_SIZE;
imageSpanCount = 4;
isCompress = false;
isOriginalControl = false;
aspect_ratio_x = 0;
aspect_ratio_y = 0;
cropWidth = 0;
cropHeight = 0;
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
buttonFeatures = CustomCameraView.BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
isCameraAroundState = false;
isWithVideoImage = false;
isAndroidQTransform = true;
isCamera = true;
isGif = false;
focusAlpha = false;
isCheckOriginalImage = false;
isSingleDirectReturn = false;
enablePreview = true;
enPreviewVideo = true;
enablePreviewAudio = true;
checkNumMode = false;
isNotPreviewDownload = false;
openClickSound = false;
isFallbackVersion = false;
isFallbackVersion2 = true;
isFallbackVersion3 = true;
enableCrop = false;
isWeChatStyle = false;
isUseCustomCamera = false;
isMultipleSkipCrop = true;
isMultipleRecyclerAnimation = true;
freeStyleCropEnabled = false;
circleDimmedLayer = false;
showCropFrame = true;
showCropGrid = true;
hideBottomControls = true;
rotateEnabled = true;
scaleEnabled = true;
previewEggs = false;
returnEmpty = false;
synOrAsy = true;
zoomAnim = true;
circleDimmedColor = 0;
circleDimmedBorderColor = 0;
circleStrokeWidth = 1;
isDragFrame = true;
compressSavePath = "";
suffixType = "";
cameraFileName = "";
specifiedFormat = "";
renameCompressFileName = "";
renameCropFileName = "";
selectionMedias = new ArrayList<>();
uCropOptions = null;
style = null;
cropStyle = null;
windowAnimationStyle = null;
titleBarBackgroundColor = 0;
pictureStatusBarColor = 0;
cropTitleBarBackgroundColor = 0;
cropStatusBarColorPrimaryDark = 0;
cropTitleColor = 0;
upResId = 0;
downResId = 0;
isChangeStatusBarFontColor = false;
isOpenStyleNumComplete = false;
isOpenStyleCheckNumMode = false;
outPutCameraPath = "";
sizeMultiplier = 0.5f;
overrideWidth = 0;
overrideHeight = 0;
originalPath = "";
cameraPath = "";
cameraMimeType = -1;
pageSize = PictureConfig.MAX_PAGE_SIZE;
isPageStrategy = true;
isFilterInvalidFile = false;
isMaxSelectEnabledMask = false;
animationMode = -1;
isAutomaticTitleRecyclerTop = true;
isCallbackMode = false;
isAndroidQChangeWH = true;
isAndroidQChangeVideoWH = false;
isQuickCapture = true;
}
public static PictureSelectionConfig getInstance() {
return InstanceHolder.INSTANCE;
}
public static PictureSelectionConfig getCleanInstance() {
PictureSelectionConfig selectionSpec = getInstance();
selectionSpec.initDefaultValue();
return selectionSpec;
}
private static final class InstanceHolder {
private static final PictureSelectionConfig INSTANCE = new PictureSelectionConfig();
}
public PictureSelectionConfig() {
}
/**
* 释放监听器
*/
public static void destroy() {
PictureSelectionConfig.listener = null;
PictureSelectionConfig.customVideoPlayCallback = null;
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
PictureSelectionConfig.cacheResourcesEngine = null;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.chooseMode);
dest.writeByte(this.camera ? (byte) 1 : (byte) 0);
dest.writeByte(this.isSingleDirectReturn ? (byte) 1 : (byte) 0);
dest.writeParcelable(this.style, flags);
dest.writeParcelable(this.cropStyle, flags);
dest.writeParcelable(this.windowAnimationStyle, flags);
dest.writeString(this.compressSavePath);
dest.writeString(this.suffixType);
dest.writeByte(this.focusAlpha ? (byte) 1 : (byte) 0);
dest.writeString(this.renameCompressFileName);
dest.writeString(this.renameCropFileName);
dest.writeString(this.specifiedFormat);
dest.writeInt(this.requestedOrientation);
dest.writeInt(this.buttonFeatures);
dest.writeByte(this.isCameraAroundState ? (byte) 1 : (byte) 0);
dest.writeByte(this.isAndroidQTransform ? (byte) 1 : (byte) 0);
dest.writeInt(this.themeStyleId);
dest.writeInt(this.selectionMode);
dest.writeInt(this.maxSelectNum);
dest.writeInt(this.minSelectNum);
dest.writeInt(this.maxVideoSelectNum);
dest.writeInt(this.minVideoSelectNum);
dest.writeInt(this.videoQuality);
dest.writeInt(this.cropCompressQuality);
dest.writeInt(this.videoMaxSecond);
dest.writeInt(this.videoMinSecond);
dest.writeInt(this.recordVideoSecond);
dest.writeInt(this.recordVideoMinSecond);
dest.writeInt(this.minimumCompressSize);
dest.writeInt(this.imageSpanCount);
dest.writeInt(this.aspect_ratio_x);
dest.writeInt(this.aspect_ratio_y);
dest.writeInt(this.cropWidth);
dest.writeInt(this.cropHeight);
dest.writeInt(this.compressQuality);
dest.writeFloat(this.filterFileSize);
dest.writeInt(this.language);
dest.writeByte(this.isMultipleRecyclerAnimation ? (byte) 1 : (byte) 0);
dest.writeByte(this.isMultipleSkipCrop ? (byte) 1 : (byte) 0);
dest.writeByte(this.isWeChatStyle ? (byte) 1 : (byte) 0);
dest.writeByte(this.isUseCustomCamera ? (byte) 1 : (byte) 0);
dest.writeByte(this.zoomAnim ? (byte) 1 : (byte) 0);
dest.writeByte(this.isCompress ? (byte) 1 : (byte) 0);
dest.writeByte(this.isOriginalControl ? (byte) 1 : (byte) 0);
dest.writeByte(this.isCamera ? (byte) 1 : (byte) 0);
dest.writeByte(this.isGif ? (byte) 1 : (byte) 0);
dest.writeByte(this.enablePreview ? (byte) 1 : (byte) 0);
dest.writeByte(this.enPreviewVideo ? (byte) 1 : (byte) 0);
dest.writeByte(this.enablePreviewAudio ? (byte) 1 : (byte) 0);
dest.writeByte(this.checkNumMode ? (byte) 1 : (byte) 0);
dest.writeByte(this.openClickSound ? (byte) 1 : (byte) 0);
dest.writeByte(this.enableCrop ? (byte) 1 : (byte) 0);
dest.writeByte(this.freeStyleCropEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(this.circleDimmedLayer ? (byte) 1 : (byte) 0);
dest.writeInt(this.circleDimmedColor);
dest.writeInt(this.circleDimmedBorderColor);
dest.writeInt(this.circleStrokeWidth);
dest.writeByte(this.showCropFrame ? (byte) 1 : (byte) 0);
dest.writeByte(this.showCropGrid ? (byte) 1 : (byte) 0);
dest.writeByte(this.hideBottomControls ? (byte) 1 : (byte) 0);
dest.writeByte(this.rotateEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(this.scaleEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(this.previewEggs ? (byte) 1 : (byte) 0);
dest.writeByte(this.synOrAsy ? (byte) 1 : (byte) 0);
dest.writeByte(this.returnEmpty ? (byte) 1 : (byte) 0);
dest.writeByte(this.isDragFrame ? (byte) 1 : (byte) 0);
dest.writeByte(this.isNotPreviewDownload ? (byte) 1 : (byte) 0);
dest.writeByte(this.isWithVideoImage ? (byte) 1 : (byte) 0);
dest.writeParcelable(this.uCropOptions, flags);
dest.writeTypedList(this.selectionMedias);
dest.writeString(this.cameraFileName);
dest.writeByte(this.isCheckOriginalImage ? (byte) 1 : (byte) 0);
dest.writeInt(this.overrideWidth);
dest.writeInt(this.overrideHeight);
dest.writeFloat(this.sizeMultiplier);
dest.writeByte(this.isChangeStatusBarFontColor ? (byte) 1 : (byte) 0);
dest.writeByte(this.isOpenStyleNumComplete ? (byte) 1 : (byte) 0);
dest.writeByte(this.isOpenStyleCheckNumMode ? (byte) 1 : (byte) 0);
dest.writeInt(this.titleBarBackgroundColor);
dest.writeInt(this.pictureStatusBarColor);
dest.writeInt(this.cropTitleBarBackgroundColor);
dest.writeInt(this.cropStatusBarColorPrimaryDark);
dest.writeInt(this.cropTitleColor);
dest.writeInt(this.upResId);
dest.writeInt(this.downResId);
dest.writeString(this.outPutCameraPath);
dest.writeString(this.originalPath);
dest.writeString(this.cameraPath);
dest.writeInt(this.cameraMimeType);
dest.writeInt(this.pageSize);
dest.writeByte(this.isPageStrategy ? (byte) 1 : (byte) 0);
dest.writeByte(this.isFilterInvalidFile ? (byte) 1 : (byte) 0);
dest.writeByte(this.isMaxSelectEnabledMask ? (byte) 1 : (byte) 0);
dest.writeInt(this.animationMode);
dest.writeByte(this.isAutomaticTitleRecyclerTop ? (byte) 1 : (byte) 0);
dest.writeByte(this.isCallbackMode ? (byte) 1 : (byte) 0);
dest.writeByte(this.isAndroidQChangeWH ? (byte) 1 : (byte) 0);
dest.writeByte(this.isAndroidQChangeVideoWH ? (byte) 1 : (byte) 0);
dest.writeByte(this.isQuickCapture ? (byte) 1 : (byte) 0);
dest.writeByte(this.isFallbackVersion ? (byte) 1 : (byte) 0);
dest.writeByte(this.isFallbackVersion2 ? (byte) 1 : (byte) 0);
dest.writeByte(this.isFallbackVersion3 ? (byte) 1 : (byte) 0);
}
protected PictureSelectionConfig(Parcel in) {
this.chooseMode = in.readInt();
this.camera = in.readByte() != 0;
this.isSingleDirectReturn = in.readByte() != 0;
this.style = in.readParcelable(PictureParameterStyle.class.getClassLoader());
this.cropStyle = in.readParcelable(PictureCropParameterStyle.class.getClassLoader());
this.windowAnimationStyle = in.readParcelable(PictureWindowAnimationStyle.class.getClassLoader());
this.compressSavePath = in.readString();
this.suffixType = in.readString();
this.focusAlpha = in.readByte() != 0;
this.renameCompressFileName = in.readString();
this.renameCropFileName = in.readString();
this.specifiedFormat = in.readString();
this.requestedOrientation = in.readInt();
this.buttonFeatures = in.readInt();
this.isCameraAroundState = in.readByte() != 0;
this.isAndroidQTransform = in.readByte() != 0;
this.themeStyleId = in.readInt();
this.selectionMode = in.readInt();
this.maxSelectNum = in.readInt();
this.minSelectNum = in.readInt();
this.maxVideoSelectNum = in.readInt();
this.minVideoSelectNum = in.readInt();
this.videoQuality = in.readInt();
this.cropCompressQuality = in.readInt();
this.videoMaxSecond = in.readInt();
this.videoMinSecond = in.readInt();
this.recordVideoSecond = in.readInt();
this.recordVideoMinSecond = in.readInt();
this.minimumCompressSize = in.readInt();
this.imageSpanCount = in.readInt();
this.aspect_ratio_x = in.readInt();
this.aspect_ratio_y = in.readInt();
this.cropWidth = in.readInt();
this.cropHeight = in.readInt();
this.compressQuality = in.readInt();
this.filterFileSize = in.readFloat();
this.language = in.readInt();
this.isMultipleRecyclerAnimation = in.readByte() != 0;
this.isMultipleSkipCrop = in.readByte() != 0;
this.isWeChatStyle = in.readByte() != 0;
this.isUseCustomCamera = in.readByte() != 0;
this.zoomAnim = in.readByte() != 0;
this.isCompress = in.readByte() != 0;
this.isOriginalControl = in.readByte() != 0;
this.isCamera = in.readByte() != 0;
this.isGif = in.readByte() != 0;
this.enablePreview = in.readByte() != 0;
this.enPreviewVideo = in.readByte() != 0;
this.enablePreviewAudio = in.readByte() != 0;
this.checkNumMode = in.readByte() != 0;
this.openClickSound = in.readByte() != 0;
this.enableCrop = in.readByte() != 0;
this.freeStyleCropEnabled = in.readByte() != 0;
this.circleDimmedLayer = in.readByte() != 0;
this.circleDimmedColor = in.readInt();
this.circleDimmedBorderColor = in.readInt();
this.circleStrokeWidth = in.readInt();
this.showCropFrame = in.readByte() != 0;
this.showCropGrid = in.readByte() != 0;
this.hideBottomControls = in.readByte() != 0;
this.rotateEnabled = in.readByte() != 0;
this.scaleEnabled = in.readByte() != 0;
this.previewEggs = in.readByte() != 0;
this.synOrAsy = in.readByte() != 0;
this.returnEmpty = in.readByte() != 0;
this.isDragFrame = in.readByte() != 0;
this.isNotPreviewDownload = in.readByte() != 0;
this.isWithVideoImage = in.readByte() != 0;
this.uCropOptions = in.readParcelable(UCropOptions.class.getClassLoader());
this.selectionMedias = in.createTypedArrayList(LocalMedia.CREATOR);
this.cameraFileName = in.readString();
this.isCheckOriginalImage = in.readByte() != 0;
this.overrideWidth = in.readInt();
this.overrideHeight = in.readInt();
this.sizeMultiplier = in.readFloat();
this.isChangeStatusBarFontColor = in.readByte() != 0;
this.isOpenStyleNumComplete = in.readByte() != 0;
this.isOpenStyleCheckNumMode = in.readByte() != 0;
this.titleBarBackgroundColor = in.readInt();
this.pictureStatusBarColor = in.readInt();
this.cropTitleBarBackgroundColor = in.readInt();
this.cropStatusBarColorPrimaryDark = in.readInt();
this.cropTitleColor = in.readInt();
this.upResId = in.readInt();
this.downResId = in.readInt();
this.outPutCameraPath = in.readString();
this.originalPath = in.readString();
this.cameraPath = in.readString();
this.cameraMimeType = in.readInt();
this.pageSize = in.readInt();
this.isPageStrategy = in.readByte() != 0;
this.isFilterInvalidFile = in.readByte() != 0;
this.isMaxSelectEnabledMask = in.readByte() != 0;
this.animationMode = in.readInt();
this.isAutomaticTitleRecyclerTop = in.readByte() != 0;
this.isCallbackMode = in.readByte() != 0;
this.isAndroidQChangeWH = in.readByte() != 0;
this.isAndroidQChangeVideoWH = in.readByte() != 0;
this.isQuickCapture = in.readByte() != 0;
this.isFallbackVersion = in.readByte() != 0;
this.isFallbackVersion2 = in.readByte() != 0;
this.isFallbackVersion3 = in.readByte() != 0;
}
public static final Creator<PictureSelectionConfig> CREATOR = new Creator<PictureSelectionConfig>() {
@Override
public PictureSelectionConfig createFromParcel(Parcel source) {
return new PictureSelectionConfig(source);
}
@Override
public PictureSelectionConfig[] newArray(int size) {
return new PictureSelectionConfig[size];
}
};
}

View File

@ -1,41 +0,0 @@
package com.luck.picture.lib.config;
import android.os.Parcel;
import android.os.Parcelable;
import com.yalantis.ucrop.UCrop;
/**
* @authorluck
* @date2020-01-09 13:33
* @describe UCrop Configuration items
*/
public class UCropOptions extends UCrop.Options implements Parcelable {
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
public UCropOptions() {
}
protected UCropOptions(Parcel in) {
}
public static final Parcelable.Creator<UCropOptions> CREATOR = new Parcelable.Creator<UCropOptions>() {
@Override
public UCropOptions createFromParcel(Parcel source) {
return new UCropOptions(source);
}
@Override
public UCropOptions[] newArray(int size) {
return new UCropOptions[size];
}
};
}

View File

@ -1,207 +0,0 @@
package com.luck.picture.lib.crash;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import androidx.annotation.NonNull;
import com.luck.picture.lib.app.PictureAppMaster;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* @authorluck
* @date2019-12-03 14:53
* @describePictureSelector Crash Log collection class
*/
public class PictureSelectorCrashUtils {
private static boolean mInitialized;
private static String defaultDir;
private static String dir;
private static String versionName;
private static int versionCode;
private static final String FILE_SEP = System.getProperty("file.separator");
private static final Format FORMAT = new SimpleDateFormat("MM-dd HH-mm-ss", Locale.getDefault());
private static final String CRASH_HEAD;
private static final Thread.UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER;
static {
try {
PackageInfo pi = PictureAppMaster.getInstance().getAppContext()
.getPackageManager()
.getPackageInfo(PictureAppMaster.getInstance().getAppContext().getPackageName(), 0);
if (pi != null) {
versionName = pi.versionName;
versionCode = pi.versionCode;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
CRASH_HEAD = "\n************* Crash Log Head ****************" +
"\nDevice Manufacturer: " + Build.MANUFACTURER + // 设备厂商
"\nDevice Model : " + Build.MODEL + // 设备型号
"\nAndroid Version : " + Build.VERSION.RELEASE + // 系统版本
"\nAndroid SDK : " + Build.VERSION.SDK_INT + // SDK版本
"\nApp VersionName : " + versionName +
"\nApp VersionCode : " + versionCode +
"\n************* Crash Log Head ****************\n\n";
UNCAUGHT_EXCEPTION_HANDLER = new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(final Thread t, final Throwable e) {
if (mFinishAppListener != null) {
mFinishAppListener.onFinishApp(t, e);
}
Date now = new Date(System.currentTimeMillis());
String fileName = FORMAT.format(now) + ".txt";
final String fullPath = (dir == null ? defaultDir : dir) + fileName;
if (createOrExistsFile(fullPath)) {
PrintWriter pw = null;
try {
pw = new PrintWriter(new FileWriter(fullPath, false));
pw.write(CRASH_HEAD);
e.printStackTrace(pw);
Throwable cause = e.getCause();
while (cause != null) {
cause.printStackTrace(pw);
cause = cause.getCause();
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
}
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
};
}
private PictureSelectorCrashUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 初始化
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
*
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
*/
public static boolean init() {
return init("", null);
}
/**
* 初始化
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
*
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
*/
public static boolean init(CrashAppListener listener) {
return init("", listener);
}
/**
* 初始化
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
*
* @param crashDir 崩溃文件存储目录
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
*/
public static boolean init(@NonNull final File crashDir) {
return init(crashDir.getAbsolutePath() + FILE_SEP, null);
}
/**
* 初始化
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
*
* @param crashDir 崩溃文件存储目录
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
*/
public static boolean init(final String crashDir, CrashAppListener listener) {
mFinishAppListener = listener;
if (isSpace(crashDir)) {
dir = null;
} else {
dir = crashDir.endsWith(FILE_SEP) ? dir : dir + FILE_SEP;
}
if (mInitialized) {
return true;
}
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
&& PictureAppMaster.getInstance().getAppContext().getExternalCacheDir() != null) {
defaultDir = PictureAppMaster.getInstance().getAppContext().getExternalCacheDir() + FILE_SEP + "crash" + FILE_SEP;
} else {
defaultDir = PictureAppMaster.getInstance().getAppContext().getCacheDir() + FILE_SEP + "crash" + FILE_SEP;
}
Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
return mInitialized = true;
}
private static boolean createOrExistsFile(String filePath) {
File file = new File(filePath);
if (file.exists()) {
return file.isFile();
}
if (!createOrExistsDir(file.getParentFile())) {
return false;
}
try {
return file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
private static boolean createOrExistsDir(File file) {
return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
}
private static boolean isSpace(String s) {
if (s == null) {
return true;
}
for (int i = 0, len = s.length(); i < len; ++i) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
private static CrashAppListener mFinishAppListener = null;
public static void setCrashListener(CrashAppListener crashListener) {
mFinishAppListener = crashListener;
}
public interface CrashAppListener {
void onFinishApp(final Thread t, final Throwable e);
}
}

View File

@ -1,46 +0,0 @@
package com.luck.picture.lib.decoration;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
* @authorluck
* @data2016/12/27 下午23:50
* @describe:GridSpacingItemDecoration
*/
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
}
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 2018.
* AuthorZhao
* Emailjoeyzhao1005@gmail.com
*/
package com.luck.picture.lib.decoration;
import android.content.Context;
import android.util.AttributeSet;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by luck on 2017/12/4.
* <p>
* RecyclerView BugIndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter的解决方案
*/
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
public WrapContentLinearLayoutManager(Context context) {
super(context);
}
public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}

View File

@ -1,110 +0,0 @@
package com.luck.picture.lib.dialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.luck.picture.lib.R;
import com.luck.picture.lib.listener.OnItemClickListener;
import com.luck.picture.lib.tools.ScreenUtils;
/**
* @authorluck
* @date2019-12-12 16:39
* @describePhotoSelectedDialog
*/
public class PhotoItemSelectedDialog extends DialogFragment implements View.OnClickListener {
public static final int IMAGE_CAMERA = 0;
public static final int VIDEO_CAMERA = 1;
private TextView tvPicturePhoto, tvPictureVideo, tvPictureCancel;
public static PhotoItemSelectedDialog newInstance() {
PhotoItemSelectedDialog selectedDialog = new PhotoItemSelectedDialog();
return selectedDialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (getDialog() != null) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
if (getDialog().getWindow() != null) {
getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
}
}
return inflater.inflate(R.layout.picture_dialog_camera_selected, container);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tvPicturePhoto = view.findViewById(R.id.picture_tv_photo);
tvPictureVideo = view.findViewById(R.id.picture_tv_video);
tvPictureCancel = view.findViewById(R.id.picture_tv_cancel);
tvPictureVideo.setOnClickListener(this);
tvPicturePhoto.setOnClickListener(this);
tvPictureCancel.setOnClickListener(this);
}
@Override
public void onStart() {
super.onStart();
initDialogStyle();
}
/**
* DialogFragment Style
*/
private void initDialogStyle() {
Dialog dialog = getDialog();
if (dialog != null) {
Window window = dialog.getWindow();
if (window != null) {
window.setLayout(ScreenUtils.getScreenWidth(getContext()), RelativeLayout.LayoutParams.WRAP_CONTENT);
window.setGravity(Gravity.BOTTOM);
window.setWindowAnimations(R.style.PictureThemeDialogFragmentAnim);
}
}
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@Override
public void onClick(View v) {
int id = v.getId();
if (onItemClickListener != null) {
if (id == R.id.picture_tv_photo) {
onItemClickListener.onItemClick(v, IMAGE_CAMERA);
}
if (id == R.id.picture_tv_video) {
onItemClickListener.onItemClick(v, VIDEO_CAMERA);
}
}
dismissAllowingStateLoss();
}
@Override
public void show(FragmentManager manager, String tag) {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
}

View File

@ -1,24 +0,0 @@
package com.luck.picture.lib.dialog;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import com.luck.picture.lib.R;
public class PictureCustomDialog extends Dialog {
public PictureCustomDialog(Context context, int layout) {
super(context, R.style.Picture_Theme_Dialog);
setContentView(layout);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
}

View File

@ -1,26 +0,0 @@
package com.luck.picture.lib.dialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.Window;
import com.luck.picture.lib.R;
public class PictureLoadingDialog extends Dialog {
public PictureLoadingDialog(Context context) {
super(context, R.style.Picture_Theme_AlertDialog);
setCancelable(true);
setCanceledOnTouchOutside(false);
Window window = getWindow();
window.setWindowAnimations(R.style.PictureThemeDialogWindowStyle);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.picture_alert_dialog);
}
}

View File

@ -1,18 +0,0 @@
package com.luck.picture.lib.engine;
import android.content.Context;
/**
* @authorluck
* @date2020-03-24 09:36
* @describeCacheResourcesEngine
*/
public interface CacheResourcesEngine {
/**
* Get the cache path
*
* @param context
* @param url
*/
String onCachePath(Context context, String url);
}

View File

@ -1,72 +0,0 @@
package com.luck.picture.lib.engine;
import android.content.Context;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import com.luck.picture.lib.listener.OnImageCompleteCallback;
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
/**
* @authorluck
* @date2019-11-13 16:59
* @describeImageEngine
*/
public interface ImageEngine {
/**
* Loading image
*
* @param context
* @param url
* @param imageView
*/
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
/**
* Loading image
*
* @param context
* @param url
* @param imageView
*/
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, SubsamplingScaleImageView longImageView, OnImageCompleteCallback callback);
/**
* Load network long graph adaption
*
* @param context
* @param url
* @param imageView
*/
@Deprecated
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, SubsamplingScaleImageView longImageView);
/**
* Load album catalog pictures
*
* @param context
* @param url
* @param imageView
*/
void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
/**
* Load GIF image
*
* @param context
* @param url
* @param imageView
*/
void loadAsGifImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
/**
* Load picture list picture
*
* @param context
* @param url
* @param imageView
*/
void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
}

View File

@ -1,26 +0,0 @@
package com.luck.picture.lib.engine;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.listener.OnResultCallbackListener;
/**
* @authorluck
* @date2020/4/22 11:36 AM
* @describePictureSelectorEngine
*/
public interface PictureSelectorEngine {
/**
* Create ImageLoad Engine
*
* @return
*/
ImageEngine createEngine();
/**
* Create Result Listener
*
* @return
*/
OnResultCallbackListener<LocalMedia> getResultCallbackListener();
}

View File

@ -1,471 +0,0 @@
package com.luck.picture.lib.entity;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import com.luck.picture.lib.config.PictureConfig;
/**
* @authorluck
* @date2017-5-24 16:21
* @describeMedia Entity
*/
public class LocalMedia implements Parcelable {
/**
* file to ID
*/
private long id;
/**
* original path
*/
private String path;
/**
* The real pathBut you can't get access from AndroidQ
* <p>
* It could be empty
* <p/>
*/
private String realPath;
/**
* # Check the original button to get the return value
* original path
*/
private String originalPath;
/**
* compress path
*/
private String compressPath;
/**
* cut path
*/
private String cutPath;
/**
* Note: this field is only returned in Android Q version
* <p>
* Android Q image or video path
*/
private String androidQToPath;
/**
* video duration
*/
private long duration;
/**
* If the selected
* # Internal use
*/
private boolean isChecked;
/**
* If the cut
*/
private boolean isCut;
/**
* media position of list
*/
public int position;
/**
* The media number of qq choose styles
*/
private int num;
/**
* The media resource type
*/
private String mimeType;
/**
* Gallery selection mode
*/
private int chooseModel;
/**
* If the compressed
*/
private boolean compressed;
/**
* image or video width
* <p>
* # If zero occurs, the developer needs to handle it extra
*/
private int width;
/**
* image or video height
* <p>
* # If zero occurs, the developer needs to handle it extra
*/
private int height;
/**
* file size
*/
private long size;
/**
* Whether the original image is displayed
*/
private boolean isOriginal;
/**
* file name
*/
private String fileName;
/**
* Parent Folder Name
*/
private String parentFolderName;
/**
* orientation info
* # For internal use only
*/
private int orientation = -1;
/**
* loadLongImageStatus
* # For internal use only
*/
public int loadLongImageStatus = PictureConfig.NORMAL;
/**
* isLongImage
* # For internal use only
*/
public boolean isLongImage;
/**
* bucketId
*/
private long bucketId = -1;
/**
* isMaxSelectEnabledMask
* # For internal use only
*/
private boolean isMaxSelectEnabledMask;
public LocalMedia() {
}
public LocalMedia(String path, long duration, int chooseModel, String mimeType) {
this.path = path;
this.duration = duration;
this.chooseModel = chooseModel;
this.mimeType = mimeType;
}
public LocalMedia(long id, String path, String fileName, String parentFolderName, long duration, int chooseModel,
String mimeType, int width, int height, long size) {
this.id = id;
this.path = path;
this.fileName = fileName;
this.parentFolderName = parentFolderName;
this.duration = duration;
this.chooseModel = chooseModel;
this.mimeType = mimeType;
this.width = width;
this.height = height;
this.size = size;
}
public LocalMedia(long id, String path, String absolutePath, String fileName, String parentFolderName, long duration, int chooseModel,
String mimeType, int width, int height, long size, long bucketId) {
this.id = id;
this.path = path;
this.realPath = absolutePath;
this.fileName = fileName;
this.parentFolderName = parentFolderName;
this.duration = duration;
this.chooseModel = chooseModel;
this.mimeType = mimeType;
this.width = width;
this.height = height;
this.size = size;
this.bucketId = bucketId;
}
public LocalMedia(String path, long duration,
boolean isChecked, int position, int num, int chooseModel) {
this.path = path;
this.duration = duration;
this.isChecked = isChecked;
this.position = position;
this.num = num;
this.chooseModel = chooseModel;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getCompressPath() {
return compressPath;
}
public void setCompressPath(String compressPath) {
this.compressPath = compressPath;
}
public String getCutPath() {
return cutPath;
}
public void setCutPath(String cutPath) {
this.cutPath = cutPath;
}
public String getAndroidQToPath() {
return androidQToPath;
}
public void setAndroidQToPath(String androidQToPath) {
this.androidQToPath = androidQToPath;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getRealPath() {
return realPath;
}
public void setRealPath(String realPath) {
this.realPath = realPath;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
public boolean isCut() {
return isCut;
}
public void setCut(boolean cut) {
isCut = cut;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getMimeType() {
return TextUtils.isEmpty(mimeType) ? "image/jpeg" : mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public boolean isCompressed() {
return compressed;
}
public void setCompressed(boolean compressed) {
this.compressed = compressed;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getChooseModel() {
return chooseModel;
}
public void setChooseModel(int chooseModel) {
this.chooseModel = chooseModel;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public boolean isOriginal() {
return isOriginal;
}
public void setOriginal(boolean original) {
isOriginal = original;
}
public String getOriginalPath() {
return originalPath;
}
public void setOriginalPath(String originalPath) {
this.originalPath = originalPath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getParentFolderName() {
return parentFolderName;
}
public void setParentFolderName(String parentFolderName) {
this.parentFolderName = parentFolderName;
}
public int getOrientation() {
return orientation;
}
public void setOrientation(int orientation) {
this.orientation = orientation;
}
public long getBucketId() {
return bucketId;
}
public void setBucketId(long bucketId) {
this.bucketId = bucketId;
}
public boolean isMaxSelectEnabledMask() {
return isMaxSelectEnabledMask;
}
public void setMaxSelectEnabledMask(boolean maxSelectEnabledMask) {
isMaxSelectEnabledMask = maxSelectEnabledMask;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(this.id);
dest.writeString(this.path);
dest.writeString(this.realPath);
dest.writeString(this.originalPath);
dest.writeString(this.compressPath);
dest.writeString(this.cutPath);
dest.writeString(this.androidQToPath);
dest.writeLong(this.duration);
dest.writeByte(this.isChecked ? (byte) 1 : (byte) 0);
dest.writeByte(this.isCut ? (byte) 1 : (byte) 0);
dest.writeInt(this.position);
dest.writeInt(this.num);
dest.writeString(this.mimeType);
dest.writeInt(this.chooseModel);
dest.writeByte(this.compressed ? (byte) 1 : (byte) 0);
dest.writeInt(this.width);
dest.writeInt(this.height);
dest.writeLong(this.size);
dest.writeByte(this.isOriginal ? (byte) 1 : (byte) 0);
dest.writeString(this.fileName);
dest.writeString(this.parentFolderName);
dest.writeInt(this.orientation);
dest.writeInt(this.loadLongImageStatus);
dest.writeByte(this.isLongImage ? (byte) 1 : (byte) 0);
dest.writeLong(this.bucketId);
dest.writeByte(this.isMaxSelectEnabledMask ? (byte) 1 : (byte) 0);
}
protected LocalMedia(Parcel in) {
this.id = in.readLong();
this.path = in.readString();
this.realPath = in.readString();
this.originalPath = in.readString();
this.compressPath = in.readString();
this.cutPath = in.readString();
this.androidQToPath = in.readString();
this.duration = in.readLong();
this.isChecked = in.readByte() != 0;
this.isCut = in.readByte() != 0;
this.position = in.readInt();
this.num = in.readInt();
this.mimeType = in.readString();
this.chooseModel = in.readInt();
this.compressed = in.readByte() != 0;
this.width = in.readInt();
this.height = in.readInt();
this.size = in.readLong();
this.isOriginal = in.readByte() != 0;
this.fileName = in.readString();
this.parentFolderName = in.readString();
this.orientation = in.readInt();
this.loadLongImageStatus = in.readInt();
this.isLongImage = in.readByte() != 0;
this.bucketId = in.readLong();
this.isMaxSelectEnabledMask = in.readByte() != 0;
}
public static final Creator<LocalMedia> CREATOR = new Creator<LocalMedia>() {
@Override
public LocalMedia createFromParcel(Parcel source) {
return new LocalMedia(source);
}
@Override
public LocalMedia[] newArray(int size) {
return new LocalMedia[size];
}
};
}

View File

@ -1,204 +0,0 @@
package com.luck.picture.lib.entity;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2016-12-31 15:21
* @describeMediaFolder Entity
*/
public class LocalMediaFolder implements Parcelable {
/**
* bucketId
*/
private long bucketId = -1;
/**
* Folder name
*/
private String name;
/**
* Folder first path
*/
private String firstImagePath;
/**
* Folder media num
*/
private int imageNum;
/**
* If the selected num
*/
private int checkedNum;
/**
* If the selected
*/
private boolean isChecked;
/**
* type
*/
private int ofAllType = -1;
/**
* Whether or not the camera
*/
private boolean isCameraFolder;
/**
* data
*/
private List<LocalMedia> data = new ArrayList<>();
/**
* # Internal use
* setCurrentDataPage
*/
private int currentDataPage;
/**
* # Internal use
* is load more
*/
private boolean isHasMore;
public long getBucketId() {
return bucketId;
}
public void setBucketId(long bucketId) {
this.bucketId = bucketId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFirstImagePath() {
return firstImagePath;
}
public void setFirstImagePath(String firstImagePath) {
this.firstImagePath = firstImagePath;
}
public int getImageNum() {
return imageNum;
}
public void setImageNum(int imageNum) {
this.imageNum = imageNum;
}
public int getCheckedNum() {
return checkedNum;
}
public void setCheckedNum(int checkedNum) {
this.checkedNum = checkedNum;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
public int getOfAllType() {
return ofAllType;
}
public void setOfAllType(int ofAllType) {
this.ofAllType = ofAllType;
}
public boolean isCameraFolder() {
return isCameraFolder;
}
public void setCameraFolder(boolean cameraFolder) {
isCameraFolder = cameraFolder;
}
public List<LocalMedia> getData() {
return data;
}
public void setData(List<LocalMedia> data) {
this.data = data;
}
public int getCurrentDataPage() {
return currentDataPage;
}
public void setCurrentDataPage(int currentDataPage) {
this.currentDataPage = currentDataPage;
}
public boolean isHasMore() {
return isHasMore;
}
public void setHasMore(boolean hasMore) {
isHasMore = hasMore;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(this.bucketId);
dest.writeString(this.name);
dest.writeString(this.firstImagePath);
dest.writeInt(this.imageNum);
dest.writeInt(this.checkedNum);
dest.writeByte(this.isChecked ? (byte) 1 : (byte) 0);
dest.writeInt(this.ofAllType);
dest.writeByte(this.isCameraFolder ? (byte) 1 : (byte) 0);
dest.writeTypedList(this.data);
dest.writeInt(this.currentDataPage);
dest.writeByte(this.isHasMore ? (byte) 1 : (byte) 0);
}
public LocalMediaFolder() {
}
protected LocalMediaFolder(Parcel in) {
this.bucketId = in.readLong();
this.name = in.readString();
this.firstImagePath = in.readString();
this.imageNum = in.readInt();
this.checkedNum = in.readInt();
this.isChecked = in.readByte() != 0;
this.ofAllType = in.readInt();
this.isCameraFolder = in.readByte() != 0;
this.data = in.createTypedArrayList(LocalMedia.CREATOR);
this.currentDataPage = in.readInt();
this.isHasMore = in.readByte() != 0;
}
public static final Creator<LocalMediaFolder> CREATOR = new Creator<LocalMediaFolder>() {
@Override
public LocalMediaFolder createFromParcel(Parcel source) {
return new LocalMediaFolder(source);
}
@Override
public LocalMediaFolder[] newArray(int size) {
return new LocalMediaFolder[size];
}
};
}

View File

@ -1,32 +0,0 @@
package com.luck.picture.lib.entity;
import java.util.List;
/**
* @authorluck
* @date2020-04-17 13:52
* @describeMediaData
*/
public class MediaData {
/**
* Is there more
*/
public boolean isHasNextMore;
/**
* data
*/
public List<LocalMedia> data;
public MediaData() {
super();
}
public MediaData(boolean isHasNextMore, List<LocalMedia> data) {
super();
this.isHasNextMore = isHasNextMore;
this.data = data;
}
}

View File

@ -1,95 +0,0 @@
package com.luck.picture.lib.immersive;
import android.graphics.Color;
import android.os.Build;
import android.view.Window;
import android.view.WindowManager;
import androidx.appcompat.app.AppCompatActivity;
/**
* @authorluck
* @data2018/3/28 下午1:00
* @描述: 沉浸式相关
*/
public class ImmersiveManage {
/**
* 注意使用最好将布局xml 跟布局加入 android:fitsSystemWindows="true" 这样可以避免有些手机上布局顶边的问题
*
* @param baseActivity 这个会留出来状态栏和底栏的空白
* @param statusBarColor 状态栏的颜色
* @param navigationBarColor 导航栏的颜色
* @param isDarkStatusBarIcon 状态栏图标颜色是否是深 false状态栏图标颜色为白色
*/
public static void immersiveAboveAPI23(AppCompatActivity baseActivity, int statusBarColor, int navigationBarColor, boolean isDarkStatusBarIcon) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
immersiveAboveAPI23(baseActivity, false, false, statusBarColor, navigationBarColor, isDarkStatusBarIcon);
}
}
/**
* @param baseActivity
* @param statusBarColor 状态栏的颜色
* @param navigationBarColor 导航栏的颜色
*/
public static void immersiveAboveAPI23(AppCompatActivity baseActivity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, int statusBarColor, int navigationBarColor, boolean isDarkStatusBarIcon) {
try {
Window window = baseActivity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
//4.4版本及以上 5.0版本及以下
window.setFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (isMarginStatusBar && isMarginNavigationBar) {
//5.0版本及以上
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
, isMarginNavigationBar
, statusBarColor == Color.TRANSPARENT
, isDarkStatusBarIcon);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
window.requestFeature(Window.FEATURE_NO_TITLE);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
, isMarginNavigationBar
, statusBarColor == Color.TRANSPARENT
, isDarkStatusBarIcon);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
} else if (!isMarginStatusBar && isMarginNavigationBar) {
window.requestFeature(Window.FEATURE_NO_TITLE);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
, isMarginNavigationBar
, statusBarColor == Color.TRANSPARENT
, isDarkStatusBarIcon);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
} else {
//留出来状态栏 不留出来导航栏 没找到办法
return;
}
window.setStatusBarColor(statusBarColor);
window.setNavigationBarColor(navigationBarColor);
}
} catch (Exception e) {
}
}
}

View File

@ -1,189 +0,0 @@
package com.luck.picture.lib.immersive;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @authorluck
* @data2018/3/28 下午1:01
* @描述: 沉浸式
*/
public class LightStatusBarUtils {
public static void setLightStatusBarAboveAPI23(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
}
}
public static void setLightStatusBar(Activity activity, boolean dark) {
setLightStatusBar(activity, false, false, false, dark);
}
public static void setLightStatusBar(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
switch (RomUtils.getLightStatausBarAvailableRomType()) {
case RomUtils.AvailableRomType.MIUI:
if (RomUtils.getMIUIVersionCode() >= 7) {
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
} else {
setMIUILightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
}
break;
case RomUtils.AvailableRomType.FLYME:
setFlymeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
break;
case RomUtils.AvailableRomType.ANDROID_NATIVE:
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
break;
case RomUtils.AvailableRomType.NA:
// N/A do nothing
break;
}
}
private static boolean setMIUILightStatusBar(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean darkmode) {
initStatusBarStyle(activity, isMarginStatusBar, isMarginNavigationBar);
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
int darkModeFlag = 0;
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
return true;
} catch (Exception e) {
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, darkmode);
}
return false;
}
private static boolean setFlymeLightStatusBar(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
boolean result = false;
if (activity != null) {
initStatusBarStyle(activity, isMarginStatusBar, isMarginNavigationBar);
try {
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
activity.getWindow().setAttributes(lp);
result = true;
if (RomUtils.getFlymeVersion() >= 7) {
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
}
} catch (Exception e) {
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
}
}
return result;
}
@TargetApi(11)
private static void setAndroidNativeLightStatusBar(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean isDarkStatusBarIcon) {
try {
if (isTransStatusBar) {
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (isMarginStatusBar && isMarginNavigationBar) {
//5.0版本及以上
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
} else if (!isMarginStatusBar && isMarginNavigationBar) {
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
} else {
//留出来状态栏 不留出来导航栏 没找到办法
return;
}
}
} else {
View decor = activity.getWindow().getDecorView();
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
// We want to change tint color to white again.
// You can also record the flags in advance so that you can turn UI back completely if
// you have set other flags before, such as translucent or full screen.
decor.setSystemUiVisibility(0);
}
}
} catch (Exception e) {
}
}
private static void initStatusBarStyle(Activity activity, boolean isMarginStatusBar
, boolean isMarginNavigationBar) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (isMarginStatusBar && isMarginNavigationBar) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
} else if (!isMarginStatusBar && isMarginNavigationBar) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
} else {
//留出来状态栏 不留出来导航栏 没找到办法
}
}
}
}

View File

@ -1,31 +0,0 @@
package com.luck.picture.lib.immersive;
import android.app.Activity;
import android.os.Build;
import android.view.Window;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
/**
* @authorluck
* @date2019-11-25 20:58
* @describeNavBar工具类
*/
public class NavBarUtils {
/**
* 动态设置 NavBar 色值
*
* @param activity
* @param color
*/
public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) {
setNavBarColor(activity.getWindow(), color);
}
public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setNavigationBarColor(color);
}
}
}

View File

@ -1,139 +0,0 @@
package com.luck.picture.lib.immersive;
import android.os.Build;
import android.text.TextUtils;
import com.luck.picture.lib.tools.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @authorluck
* @data2018/3/28 下午1:02
* @描述: Rom版本管理
*/
public class RomUtils {
public class AvailableRomType {
public static final int MIUI = 1;
public static final int FLYME = 2;
public static final int ANDROID_NATIVE = 3;
public static final int NA = 4;
}
private static Integer romType;
public static int getLightStatausBarAvailableRomType() {
if (romType != null) {
return romType;
}
if (isMIUIV6OrAbove()) {
romType = AvailableRomType.MIUI;
return romType;
}
if (isFlymeV4OrAbove()) {
romType = AvailableRomType.FLYME;
return romType;
}
if (isAndroid5OrAbove()) {
romType = AvailableRomType.ANDROID_NATIVE;
return romType;
}
romType = AvailableRomType.NA;
return romType;
}
//Flyme V4的displayId格式为 [Flyme OS 4.x.x.xA]
//Flyme V5的displayId格式为 [Flyme 5.x.x.x beta]
private static boolean isFlymeV4OrAbove() {
return (getFlymeVersion() >= 4);
}
//Flyme V4的displayId格式为 [Flyme OS 4.x.x.xA]
//Flyme V5的displayId格式为 [Flyme 5.x.x.x beta]
public static int getFlymeVersion() {
String displayId = Build.DISPLAY;
if (!TextUtils.isEmpty(displayId) && displayId.contains("Flyme")) {
displayId = displayId.replaceAll("Flyme", "");
displayId = displayId.replaceAll("OS", "");
displayId = displayId.replaceAll(" ", "");
String version = displayId.substring(0, 1);
if (version != null) {
return StringUtils.stringToInt(version);
}
}
return 0;
}
//MIUI V6对应的versionCode是4
//MIUI V7对应的versionCode是5
private static boolean isMIUIV6OrAbove() {
String miuiVersionCodeStr = getSystemProperty("ro.miui.ui.version.code");
if (!TextUtils.isEmpty(miuiVersionCodeStr)) {
try {
int miuiVersionCode = Integer.parseInt(miuiVersionCodeStr);
if (miuiVersionCode >= 4) {
return true;
}
} catch (Exception e) {
}
}
return false;
}
public static int getMIUIVersionCode() {
String miuiVersionCodeStr = getSystemProperty("ro.miui.ui.version.code");
int miuiVersionCode = 0;
if (!TextUtils.isEmpty(miuiVersionCodeStr)) {
try {
miuiVersionCode = Integer.parseInt(miuiVersionCodeStr);
return miuiVersionCode;
} catch (Exception e) {
}
}
return miuiVersionCode;
}
//Android Api 23以上
private static boolean isAndroid5OrAbove() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return true;
}
return false;
}
public static String getSystemProperty(String propName) {
String line;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}
return line;
}
}

View File

@ -1,46 +0,0 @@
package com.luck.picture.lib.language;
/**
* @authorluck
* @date2019-11-25 21:50
* @describe语言配制
*/
public class LanguageConfig {
/**
* 简体中文
*/
public static final int CHINESE = 0;
/**
* 繁体
*/
public static final int TRADITIONAL_CHINESE = 1;
// 英语
public static final int ENGLISH = 2;
/**
* 韩语
*/
public static final int KOREA = 3;
/**
* 德语
*/
public static final int GERMANY = 4;
/**
* 法语
*/
public static final int FRANCE = 5;
/**
* 日语
*/
public static final int JAPAN = 6;
/**
* 越语
*/
public static final int VIETNAM = 7;
}

View File

@ -1,39 +0,0 @@
package com.luck.picture.lib.language;
import java.util.Locale;
/**
* @authorluck
* @date2019-11-25 21:58
* @describe语言转换
*/
public class LocaleTransform {
public static Locale getLanguage(int language) {
switch (language) {
case LanguageConfig.ENGLISH:
// 英语-美国
return Locale.ENGLISH;
case LanguageConfig.TRADITIONAL_CHINESE:
// 繁体中文
return Locale.TRADITIONAL_CHINESE;
case LanguageConfig.KOREA:
// 韩语
return Locale.KOREA;
case LanguageConfig.GERMANY:
// 德语
return Locale.GERMANY;
case LanguageConfig.FRANCE:
// 法语
return Locale.FRANCE;
case LanguageConfig.JAPAN:
// 日语
return Locale.JAPAN;
case LanguageConfig.VIETNAM:
// 越南语
return new Locale("vi");
default:
// 简体中文
return Locale.CHINESE;
}
}
}

View File

@ -1,118 +0,0 @@
package com.luck.picture.lib.language;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import androidx.annotation.NonNull;
import com.luck.picture.lib.tools.SPUtils;
import java.lang.ref.WeakReference;
import java.util.Locale;
/**
* @authorluck
* @data2018/3/28 下午1:00
* @描述: PictureLanguageUtils
*/
public class PictureLanguageUtils {
private static final String KEY_LOCALE = "KEY_LOCALE";
private static final String VALUE_FOLLOW_SYSTEM = "VALUE_FOLLOW_SYSTEM";
private PictureLanguageUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* init app the language
*
* @param context
* @param languageId
*/
public static void setAppLanguage(Context context, int languageId) {
WeakReference<Context> contextWeakReference = new WeakReference<>(context);
if (languageId >= 0) {
applyLanguage(contextWeakReference.get(), LocaleTransform.getLanguage(languageId));
} else {
setDefaultLanguage(contextWeakReference.get());
}
}
/**
* Apply the language.
*
* @param locale The language of locale.
*/
private static void applyLanguage(@NonNull Context context, @NonNull final Locale locale) {
applyLanguage(context, locale, false);
}
private static void applyLanguage(@NonNull Context context, @NonNull final Locale locale,
final boolean isFollowSystem) {
if (isFollowSystem) {
SPUtils.getPictureSpUtils().put(KEY_LOCALE, VALUE_FOLLOW_SYSTEM);
} else {
String localLanguage = locale.getLanguage();
String localCountry = locale.getCountry();
SPUtils.getPictureSpUtils().put(KEY_LOCALE, localLanguage + "$" + localCountry);
}
updateLanguage(context, locale);
}
private static void updateLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
Locale contextLocale = config.locale;
if (equals(contextLocale.getLanguage(), locale.getLanguage())
&& equals(contextLocale.getCountry(), locale.getCountry())) {
return;
}
DisplayMetrics dm = resources.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.setLocale(locale);
context.createConfigurationContext(config);
} else {
config.locale = locale;
}
resources.updateConfiguration(config, dm);
}
/**
* set default language
*
* @param context
*/
private static void setDefaultLanguage(Context context) {
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.setLocale(config.locale);
context.createConfigurationContext(config);
}
resources.updateConfiguration(config, dm);
}
private static boolean equals(final CharSequence s1, final CharSequence s2) {
if (s1 == s2) return true;
int length;
if (s1 != null && s2 != null && (length = s1.length()) == s2.length()) {
if (s1 instanceof String && s2 instanceof String) {
return s1.equals(s2);
} else {
for (int i = 0; i < length; i++) {
if (s1.charAt(i) != s2.charAt(i)) return false;
}
return true;
}
}
return false;
}
}

View File

@ -1,24 +0,0 @@
package com.luck.picture.lib.listener;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.List;
/**
* @authorluck
* @date2020-03-26 10:57
* @describeOnAlbumItemClickListener
*/
public interface OnAlbumItemClickListener {
/**
* Album catalog item click event
*
* @param position
* @param isCameraFolder
* @param bucketId
* @param folderName
* @param data
*/
void onItemClick(int position, boolean isCameraFolder,
long bucketId, String folderName, List<LocalMedia> data);
}

View File

@ -1,13 +0,0 @@
package com.luck.picture.lib.listener;
/**
* @authorluck
* @date2020/4/24 11:48 AM
* @describeOnCallbackListener
*/
public interface OnCallbackListener<T> {
/**
* @param data
*/
void onCall(T data);
}

View File

@ -1,21 +0,0 @@
package com.luck.picture.lib.listener;
import android.content.Context;
import com.luck.picture.lib.config.PictureSelectionConfig;
/**
* @authorluck
* @date2020/4/27 3:24 PM
* @describeOnCustomCameraInterfaceListener
*/
public interface OnCustomCameraInterfaceListener {
/**
* Camera Menu
*
* @param context
* @param config
* @param type
*/
void onCameraClick(Context context, PictureSelectionConfig config, int type);
}

View File

@ -1,18 +0,0 @@
package com.luck.picture.lib.listener;
/**
* @authorluck
* @date2020-01-03 16:43
* @describeImage load complete callback
*/
public interface OnImageCompleteCallback {
/**
* Start loading
*/
void onShowLoading();
/**
* Stop loading
*/
void onHideLoading();
}

View File

@ -1,18 +0,0 @@
package com.luck.picture.lib.listener;
import android.view.View;
/**
* @authorluck
* @date2020-03-26 10:50
* @describeOnItemClickListener
*/
public interface OnItemClickListener {
/**
* Item click event
*
* @param v
* @param position
*/
void onItemClick(View v, int position);
}

View File

@ -1,30 +0,0 @@
package com.luck.picture.lib.listener;
import java.util.List;
/**
* @authorluck
* @date2020-03-26 10:34
* @describeOnPhotoSelectChangedListener
*/
public interface OnPhotoSelectChangedListener<T> {
/**
* Photo callback
*/
void onTakePhoto();
/**
* Selected LocalMedia callback
*
* @param data
*/
void onChange(List<T> data);
/**
* Image preview callback
*
* @param data
* @param position
*/
void onPictureClick(T data, int position);
}

View File

@ -1,19 +0,0 @@
package com.luck.picture.lib.listener;
import java.util.List;
/**
* @authorluck
* @date2020-04-16 12:42
* @describeOnQueryMediaResultListener
*/
public interface OnQueryDataResultListener<T> {
/**
* Query to complete The callback listener
*
* @param data The data source
* @param currentPage The page number
* @param isHasMore Is there more
*/
void onComplete(List<T> data, int currentPage, boolean isHasMore);
}

View File

@ -1,13 +0,0 @@
package com.luck.picture.lib.listener;
/**
* @authorluck
* @date2020-04-14 18:44
* @describeOnRecyclerViewPreloadMoreListener
*/
public interface OnRecyclerViewPreloadMoreListener {
/**
* load more
*/
void onRecyclerViewPreloadMore();
}

View File

@ -1,22 +0,0 @@
package com.luck.picture.lib.listener;
import java.util.List;
/**
* @authorluck
* @date2020-01-14 17:08
* @describeonResult Callback Listener
*/
public interface OnResultCallbackListener<T> {
/**
* return LocalMedia result
*
* @param result
*/
void onResult(List<T> result);
/**
* Cancel
*/
void onCancel();
}

View File

@ -1,16 +0,0 @@
package com.luck.picture.lib.listener;
/**
* @authorluck
* @date2020-01-15 14:38
* @describeCustom video playback callback
*/
public interface OnVideoSelectedPlayCallback<T> {
/**
* Play the video
*
* @param data
*/
void startPlayVideo(T data);
}

View File

@ -1,407 +0,0 @@
package com.luck.picture.lib.model;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.entity.LocalMediaFolder;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.ValueOf;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* @authorluck
* @data2016/12/31 19:12
* @describe: Local media database query class
*/
@Deprecated
public final class LocalMediaLoader {
private static final String TAG = LocalMediaLoader.class.getSimpleName();
private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external");
private static final String ORDER_BY = MediaStore.Files.FileColumns._ID + " DESC";
private static final String NOT_GIF = "!='image/gif'";
/**
* Filter out recordings that are less than 500 milliseconds long
*/
private static final int AUDIO_DURATION = 500;
private Context mContext;
private boolean isAndroidQ;
private PictureSelectionConfig config;
/**
* unit
*/
private static final long FILE_SIZE_UNIT = 1024 * 1024L;
/**
* Media file database field
*/
private static final String[] PROJECTION = {
MediaStore.Files.FileColumns._ID,
MediaStore.MediaColumns.DATA,
MediaStore.MediaColumns.MIME_TYPE,
MediaStore.MediaColumns.WIDTH,
MediaStore.MediaColumns.HEIGHT,
MediaStore.MediaColumns.DURATION,
MediaStore.MediaColumns.SIZE,
MediaStore.MediaColumns.BUCKET_DISPLAY_NAME,
MediaStore.MediaColumns.DISPLAY_NAME,
MediaStore.MediaColumns.BUCKET_ID};
/**
* Image
*/
private static final String SELECTION = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0";
private static final String SELECTION_NOT_GIF = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF;
/**
* Queries for images with the specified suffix
*/
private static final String SELECTION_SPECIFIED_FORMAT = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE;
/**
* Query criteria (audio and video)
*
* @param time_condition
* @return
*/
private static String getSelectionArgsForSingleMediaCondition(String time_condition) {
return MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0"
+ " AND " + time_condition;
}
/**
* Query (video)
*
* @return
*/
private static String getSelectionArgsForSingleMediaCondition() {
return MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0";
}
/**
* Query conditions in all modes
*
* @param time_condition
* @param isGif
* @return
*/
private static String getSelectionArgsForAllMediaCondition(String time_condition, boolean isGif) {
String condition = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ " OR "
+ (MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + time_condition) + ")"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0";
return condition;
}
/**
* Get pictures or videos
*/
private static final String[] SELECTION_ALL_ARGS = {
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
};
/**
* Gets a file of the specified type
*
* @param mediaType
* @return
*/
private static String[] getSelectionArgsForSingleMediaType(int mediaType) {
return new String[]{String.valueOf(mediaType)};
}
public LocalMediaLoader(Context context, PictureSelectionConfig config) {
this.mContext = context.getApplicationContext();
this.isAndroidQ = SdkVersionUtils.checkedAndroid_Q();
this.config = config;
}
/**
* Query the local gallery data
*
* @return
*/
public List<LocalMediaFolder> loadAllMedia() {
Cursor data = mContext.getContentResolver().query(QUERY_URI, PROJECTION, getSelection(), getSelectionArgs(), ORDER_BY);
try {
if (data != null) {
List<LocalMediaFolder> imageFolders = new ArrayList<>();
LocalMediaFolder allImageFolder = new LocalMediaFolder();
List<LocalMedia> latelyImages = new ArrayList<>();
int count = data.getCount();
if (count > 0) {
data.moveToFirst();
do {
long id = data.getLong
(data.getColumnIndexOrThrow(PROJECTION[0]));
String absolutePath = data.getString
(data.getColumnIndexOrThrow(PROJECTION[1]));
String url = isAndroidQ ? getRealPathAndroid_Q(id) : absolutePath;
String mimeType = data.getString
(data.getColumnIndexOrThrow(PROJECTION[2]));
mimeType = TextUtils.isEmpty(mimeType) ? PictureMimeType.ofJPEG() : mimeType;
// Here, it is solved that some models obtain mimeType and return the format of image / *,
// which makes it impossible to distinguish the specific type, such as mi 8,9,10 and other models
if (mimeType.endsWith("image/*")) {
if (PictureMimeType.isContent(url)) {
mimeType = PictureMimeType.getImageMimeType(absolutePath);
} else {
mimeType = PictureMimeType.getImageMimeType(url);
}
if (!config.isGif) {
boolean isGif = PictureMimeType.isGif(mimeType);
if (isGif) {
continue;
}
}
}
int width = data.getInt
(data.getColumnIndexOrThrow(PROJECTION[3]));
int height = data.getInt
(data.getColumnIndexOrThrow(PROJECTION[4]));
long duration = data.getLong
(data.getColumnIndexOrThrow(PROJECTION[5]));
long size = data.getLong
(data.getColumnIndexOrThrow(PROJECTION[6]));
String folderName = data.getString
(data.getColumnIndexOrThrow(PROJECTION[7]));
String fileName = data.getString
(data.getColumnIndexOrThrow(PROJECTION[8]));
long bucketId = data.getLong(data.getColumnIndexOrThrow(PROJECTION[9]));
if (config.filterFileSize > 0) {
if (size > config.filterFileSize * FILE_SIZE_UNIT) {
continue;
}
}
if (PictureMimeType.isHasVideo(mimeType)) {
if (config.videoMinSecond > 0 && duration < config.videoMinSecond) {
// If you set the minimum number of seconds of video to display
continue;
}
if (config.videoMaxSecond > 0 && duration > config.videoMaxSecond) {
// If you set the maximum number of seconds of video to display
continue;
}
if (duration == 0) {
//If the length is 0, the corrupted video is processed and filtered out
continue;
}
if (size <= 0) {
// The video size is 0 to filter out
continue;
}
}
LocalMedia image = new LocalMedia
(id, url, absolutePath, fileName, folderName, duration, config.chooseMode, mimeType, width, height, size, bucketId);
LocalMediaFolder folder = getImageFolder(url, folderName, imageFolders);
folder.setBucketId(image.getBucketId());
List<LocalMedia> images = folder.getData();
images.add(image);
folder.setImageNum(folder.getImageNum() + 1);
folder.setBucketId(image.getBucketId());
latelyImages.add(image);
int imageNum = allImageFolder.getImageNum();
allImageFolder.setImageNum(imageNum + 1);
} while (data.moveToNext());
if (latelyImages.size() > 0) {
sortFolder(imageFolders);
imageFolders.add(0, allImageFolder);
allImageFolder.setFirstImagePath
(latelyImages.get(0).getPath());
String title = config.chooseMode == PictureMimeType.ofAudio() ?
mContext.getString(R.string.picture_all_audio)
: mContext.getString(R.string.picture_camera_roll);
allImageFolder.setName(title);
allImageFolder.setBucketId(-1);
allImageFolder.setOfAllType(config.chooseMode);
allImageFolder.setCameraFolder(true);
allImageFolder.setData(latelyImages);
}
}
return imageFolders;
}
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "loadAllMedia Data Error: " + e.getMessage());
return null;
} finally {
if (data != null && !data.isClosed()) {
data.close();
}
}
return null;
}
private String getSelection() {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
// Get all, not including audio
return getSelectionArgsForAllMediaCondition(getDurationCondition(0, 0), config.isGif);
case PictureConfig.TYPE_IMAGE:
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// Gets the image of the specified type
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'";
}
return config.isGif ? SELECTION : SELECTION_NOT_GIF;
case PictureConfig.TYPE_VIDEO:
// Access to video
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// Gets the image of the specified type
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'";
}
return getSelectionArgsForSingleMediaCondition();
case PictureConfig.TYPE_AUDIO:
// Access to the audio
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// Gets the image of the specified type
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'";
}
return getSelectionArgsForSingleMediaCondition(getDurationCondition(0, AUDIO_DURATION));
}
return null;
}
private String[] getSelectionArgs() {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
return SELECTION_ALL_ARGS;
case PictureConfig.TYPE_IMAGE:
// Get Image
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE);
case PictureConfig.TYPE_VIDEO:
// Get Video
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO);
case PictureConfig.TYPE_AUDIO:
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_AUDIO);
}
return null;
}
/**
* Sort by the number of files
*
* @param imageFolders
*/
private void sortFolder(List<LocalMediaFolder> imageFolders) {
Collections.sort(imageFolders, (lhs, rhs) -> {
if (lhs.getData() == null || rhs.getData() == null) {
return 0;
}
int lSize = lhs.getImageNum();
int rSize = rhs.getImageNum();
return Integer.compare(rSize, lSize);
});
}
/**
* Android Q
*
* @param id
* @return
*/
private String getRealPathAndroid_Q(long id) {
return QUERY_URI.buildUpon().appendPath(ValueOf.toString(id)).build().toString();
}
/**
* Create folder
*
* @param path
* @param imageFolders
* @param folderName
* @return
*/
private LocalMediaFolder getImageFolder(String path, String folderName, List<LocalMediaFolder> imageFolders) {
if (!config.isFallbackVersion) {
for (LocalMediaFolder folder : imageFolders) {
// Under the same folder, return yourself, otherwise create a new folder
String name = folder.getName();
if (TextUtils.isEmpty(name)) {
continue;
}
if (name.equals(folderName)) {
return folder;
}
}
LocalMediaFolder newFolder = new LocalMediaFolder();
newFolder.setName(folderName);
newFolder.setFirstImagePath(path);
imageFolders.add(newFolder);
return newFolder;
} else {
// Fault-tolerant processing
File imageFile = new File(path);
File folderFile = imageFile.getParentFile();
for (LocalMediaFolder folder : imageFolders) {
// Under the same folder, return yourself, otherwise create a new folder
String name = folder.getName();
if (TextUtils.isEmpty(name)) {
continue;
}
if (folderFile != null && name.equals(folderFile.getName())) {
return folder;
}
}
LocalMediaFolder newFolder = new LocalMediaFolder();
newFolder.setName(folderFile != null ? folderFile.getName() : "");
newFolder.setFirstImagePath(path);
imageFolders.add(newFolder);
return newFolder;
}
}
/**
* Get video (maximum or minimum time)
*
* @param exMaxLimit
* @param exMinLimit
* @return
*/
private String getDurationCondition(long exMaxLimit, long exMinLimit) {
long maxS = config.videoMaxSecond == 0 ? Long.MAX_VALUE : config.videoMaxSecond;
if (exMaxLimit != 0) {
maxS = Math.min(maxS, exMaxLimit);
}
return String.format(Locale.CHINA, "%d <%s " + MediaStore.MediaColumns.DURATION + " and " + MediaStore.MediaColumns.DURATION + " <= %d",
Math.max(exMinLimit, config.videoMinSecond),
Math.max(exMinLimit, config.videoMinSecond) == 0 ? "" : "=",
maxS);
}
}

View File

@ -1,713 +0,0 @@
package com.luck.picture.lib.model;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import com.luck.picture.lib.R;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.config.PictureSelectionConfig;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.entity.LocalMediaFolder;
import com.luck.picture.lib.entity.MediaData;
import com.luck.picture.lib.listener.OnQueryDataResultListener;
import com.luck.picture.lib.thread.PictureThreadUtils;
import com.luck.picture.lib.tools.PictureFileUtils;
import com.luck.picture.lib.tools.SdkVersionUtils;
import com.luck.picture.lib.tools.ValueOf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* @authorluck
* @date2020-04-13 15:06
* @describeLocal media database query classSupport paging
*/
public final class LocalMediaPageLoader {
private static final String TAG = LocalMediaPageLoader.class.getSimpleName();
private static final Uri QUERY_URI = MediaStore.Files.getContentUri("external");
private static final String ORDER_BY = MediaStore.Files.FileColumns._ID + " DESC";
private static final String NOT_GIF_UNKNOWN = "!='image/*'";
private static final String NOT_GIF = "!='image/gif' AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF_UNKNOWN;
private static final String GROUP_BY_BUCKET_Id = " GROUP BY (bucket_id";
private static final String COLUMN_COUNT = "count";
private static final String COLUMN_BUCKET_ID = "bucket_id";
private static final String COLUMN_BUCKET_DISPLAY_NAME = "bucket_display_name";
/**
* Filter out recordings that are less than 500 milliseconds long
*/
private static final int AUDIO_DURATION = 500;
private Context mContext;
private PictureSelectionConfig config;
/**
* unit
*/
private static final long FILE_SIZE_UNIT = 1024 * 1024L;
/**
* Image
*/
private static final String SELECTION = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? )"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
private static final String SELECTION_29 = MediaStore.Files.FileColumns.MEDIA_TYPE + "=? "
+ " AND " + MediaStore.MediaColumns.SIZE + ">0";
private static final String SELECTION_NOT_GIF = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF + ") AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
private static final String SELECTION_NOT_GIF_29 = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF + " AND " + MediaStore.MediaColumns.SIZE + ">0";
/**
* Queries for images with the specified suffix
*/
private static final String SELECTION_SPECIFIED_FORMAT = "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE;
/**
* Queries for images with the specified suffix targetSdk>=29
*/
private static final String SELECTION_SPECIFIED_FORMAT_29 = MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.MIME_TYPE;
/**
* Query criteria (audio and video)
*
* @param timeCondition
* @return
*/
private static String getSelectionArgsForSingleMediaCondition(String timeCondition) {
if (SdkVersionUtils.checkedAndroid_Q()) {
return MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ " AND " + MediaStore.MediaColumns.SIZE + ">0"
+ " AND " + timeCondition;
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ ") AND " + MediaStore.MediaColumns.SIZE + ">0"
+ " AND " + timeCondition + ")" + GROUP_BY_BUCKET_Id;
}
/**
* All mode conditions
*
* @param timeCondition
* @param isGif
* @return
*/
private static String getSelectionArgsForAllMediaCondition(String timeCondition, boolean isGif) {
if (SdkVersionUtils.checkedAndroid_Q()) {
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ " OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + timeCondition + ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ " OR " + (MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + timeCondition) + ")" + " AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
}
/**
* Get pictures or videos
*/
private static final String[] SELECTION_ALL_ARGS = {
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
};
/**
* Gets a file of the specified type
*
* @param mediaType
* @return
*/
private static String[] getSelectionArgsForSingleMediaType(int mediaType) {
return new String[]{String.valueOf(mediaType)};
}
/**
* Gets a file of the specified type
*
* @param mediaType
* @return
*/
private static String[] getSelectionArgsForPageSingleMediaType(int mediaType, long bucketId) {
return bucketId == -1 ? new String[]{String.valueOf(mediaType)} : new String[]{String.valueOf(mediaType), ValueOf.toString(bucketId)};
}
public LocalMediaPageLoader(Context context, PictureSelectionConfig config) {
this.mContext = context;
this.config = config;
}
private static final String[] PROJECTION_29 = {
MediaStore.Files.FileColumns._ID,
COLUMN_BUCKET_ID,
COLUMN_BUCKET_DISPLAY_NAME,
MediaStore.MediaColumns.MIME_TYPE};
private static final String[] PROJECTION = {
MediaStore.Files.FileColumns._ID,
MediaStore.MediaColumns.DATA,
COLUMN_BUCKET_ID,
COLUMN_BUCKET_DISPLAY_NAME,
MediaStore.MediaColumns.MIME_TYPE,
"COUNT(*) AS " + COLUMN_COUNT};
/**
* Media file database field
*/
private static final String[] PROJECTION_PAGE = {
MediaStore.Files.FileColumns._ID,
MediaStore.MediaColumns.DATA,
MediaStore.MediaColumns.MIME_TYPE,
MediaStore.MediaColumns.WIDTH,
MediaStore.MediaColumns.HEIGHT,
MediaStore.MediaColumns.DURATION,
MediaStore.MediaColumns.SIZE,
MediaStore.MediaColumns.BUCKET_DISPLAY_NAME,
MediaStore.MediaColumns.DISPLAY_NAME,
COLUMN_BUCKET_ID};
/**
* Get the latest cover of an album catalog
*
* @param bucketId
* @return
*/
public String getFirstCover(long bucketId) {
Cursor data = null;
try {
String orderBy = MediaStore.Files.FileColumns._ID + " DESC limit 1 offset 0";
data = mContext.getContentResolver().query(QUERY_URI, new String[]{
MediaStore.Files.FileColumns._ID,
MediaStore.MediaColumns.DATA}, getPageSelection(bucketId), getPageSelectionArgs(bucketId), orderBy);
if (data != null && data.getCount() > 0) {
if (data.moveToFirst()) {
long id = data.getLong(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));
return SdkVersionUtils.checkedAndroid_Q() ? getRealPathAndroid_Q(id) : data.getString
(data.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));
}
return null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (data != null && !data.isClosed()) {
data.close();
}
}
return null;
}
/**
* Queries for data in the specified directory
*
* @param bucketId
* @param page
* @param limit
* @param listener
* @return
*/
public void loadPageMediaData(long bucketId, int page, int limit, OnQueryDataResultListener listener) {
loadPageMediaData(bucketId, page, limit, config.pageSize, listener);
}
/**
* Queries for data in the specified directory
*
* @param bucketId
* @param listener
* @return
*/
public void loadPageMediaData(long bucketId, int page, OnQueryDataResultListener listener) {
loadPageMediaData(bucketId, page, config.pageSize, config.pageSize, listener);
}
/**
* Queries for data in the specified directory (page)
*
* @param bucketId
* @param page
* @param limit
* @param pageSize
* @return
*/
public void loadPageMediaData(long bucketId, int page, int limit, int pageSize, OnQueryDataResultListener listener) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<MediaData>() {
@Override
public MediaData doInBackground() {
Cursor data = null;
try {
String orderBy = page == -1 ? MediaStore.Files.FileColumns._ID + " DESC" : MediaStore.Files.FileColumns._ID + " DESC limit " + limit + " offset " + (page - 1) * pageSize;
data = mContext.getContentResolver().query(QUERY_URI, PROJECTION_PAGE, getPageSelection(bucketId), getPageSelectionArgs(bucketId), orderBy);
if (data != null) {
List<LocalMedia> result = new ArrayList<>();
if (data.getCount() > 0) {
data.moveToFirst();
do {
long id = data.getLong
(data.getColumnIndexOrThrow(PROJECTION_PAGE[0]));
String absolutePath = data.getString
(data.getColumnIndexOrThrow(PROJECTION_PAGE[1]));
String url = SdkVersionUtils.checkedAndroid_Q() ? getRealPathAndroid_Q(id) : absolutePath;
if (config.isFilterInvalidFile) {
if (!PictureFileUtils.isFileExists(absolutePath)) {
continue;
}
}
String mimeType = data.getString
(data.getColumnIndexOrThrow(PROJECTION_PAGE[2]));
mimeType = TextUtils.isEmpty(mimeType) ? PictureMimeType.ofJPEG() : mimeType;
// Here, it is solved that some models obtain mimeType and return the format of image / *,
// which makes it impossible to distinguish the specific type, such as mi 8,9,10 and other models
if (mimeType.endsWith("image/*")) {
if (PictureMimeType.isContent(url)) {
mimeType = PictureMimeType.getImageMimeType(absolutePath);
} else {
mimeType = PictureMimeType.getImageMimeType(url);
}
if (!config.isGif) {
boolean isGif = PictureMimeType.isGif(mimeType);
if (isGif) {
continue;
}
}
}
int width = data.getInt
(data.getColumnIndexOrThrow(PROJECTION_PAGE[3]));
int height = data.getInt
(data.getColumnIndexOrThrow(PROJECTION_PAGE[4]));
long duration = data.getLong
(data.getColumnIndexOrThrow(PROJECTION_PAGE[5]));
long size = data.getLong
(data.getColumnIndexOrThrow(PROJECTION_PAGE[6]));
String folderName = data.getString
(data.getColumnIndexOrThrow(PROJECTION_PAGE[7]));
String fileName = data.getString
(data.getColumnIndexOrThrow(PROJECTION_PAGE[8]));
long bucket_id = data.getLong
(data.getColumnIndexOrThrow(PROJECTION_PAGE[9]));
if (config.filterFileSize > 0) {
if (size > config.filterFileSize * FILE_SIZE_UNIT) {
continue;
}
}
if (PictureMimeType.isHasVideo(mimeType)) {
if (config.videoMinSecond > 0 && duration < config.videoMinSecond) {
// If you set the minimum number of seconds of video to display
continue;
}
if (config.videoMaxSecond > 0 && duration > config.videoMaxSecond) {
// If you set the maximum number of seconds of video to display
continue;
}
if (duration == 0) {
//If the length is 0, the corrupted video is processed and filtered out
continue;
}
if (size <= 0) {
// The video size is 0 to filter out
continue;
}
}
LocalMedia image = new LocalMedia
(id, url, absolutePath, fileName, folderName, duration, config.chooseMode, mimeType, width, height, size, bucket_id);
result.add(image);
} while (data.moveToNext());
}
return new MediaData(data.getCount() > 0, result);
}
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "loadMedia Page Data Error: " + e.getMessage());
return null;
} finally {
if (data != null && !data.isClosed()) {
data.close();
}
}
return null;
}
@Override
public void onSuccess(MediaData result) {
if (listener != null && result != null) {
listener.onComplete(result.data, page, result.isHasNextMore);
}
}
});
}
/**
* Query the local gallery data
*
* @param listener
*/
public void loadAllMedia(OnQueryDataResultListener listener) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<List<LocalMediaFolder>>() {
@Override
public List<LocalMediaFolder> doInBackground() {
Cursor data = mContext.getContentResolver().query(QUERY_URI,
SdkVersionUtils.checkedAndroid_Q() ? PROJECTION_29 : PROJECTION,
getSelection(), getSelectionArgs(), ORDER_BY);
try {
if (data != null) {
int count = data.getCount();
int totalCount = 0;
List<LocalMediaFolder> mediaFolders = new ArrayList<>();
if (count > 0) {
if (SdkVersionUtils.checkedAndroid_Q()) {
Map<Long, Long> countMap = new HashMap<>();
while (data.moveToNext()) {
long bucketId = data.getLong(data.getColumnIndex(COLUMN_BUCKET_ID));
Long newCount = countMap.get(bucketId);
if (newCount == null) {
newCount = 1L;
} else {
newCount++;
}
countMap.put(bucketId, newCount);
}
if (data.moveToFirst()) {
Set<Long> hashSet = new HashSet<>();
do {
long bucketId = data.getLong(data.getColumnIndex(COLUMN_BUCKET_ID));
if (hashSet.contains(bucketId)) {
continue;
}
LocalMediaFolder mediaFolder = new LocalMediaFolder();
mediaFolder.setBucketId(bucketId);
String bucketDisplayName = data.getString(
data.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME));
long size = countMap.get(bucketId);
long id = data.getLong(data.getColumnIndex(MediaStore.Files.FileColumns._ID));
mediaFolder.setName(bucketDisplayName);
mediaFolder.setImageNum(ValueOf.toInt(size));
mediaFolder.setFirstImagePath(getRealPathAndroid_Q(id));
mediaFolders.add(mediaFolder);
hashSet.add(bucketId);
totalCount += size;
} while (data.moveToNext());
}
} else {
data.moveToFirst();
do {
LocalMediaFolder mediaFolder = new LocalMediaFolder();
long bucketId = data.getLong(data.getColumnIndex(COLUMN_BUCKET_ID));
String bucketDisplayName = data.getString(data.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME));
int size = data.getInt(data.getColumnIndex(COLUMN_COUNT));
mediaFolder.setBucketId(bucketId);
String url = data.getString(data.getColumnIndex(MediaStore.MediaColumns.DATA));
mediaFolder.setFirstImagePath(url);
mediaFolder.setName(bucketDisplayName);
mediaFolder.setImageNum(size);
mediaFolders.add(mediaFolder);
totalCount += size;
} while (data.moveToNext());
}
sortFolder(mediaFolders);
// 相机胶卷
LocalMediaFolder allMediaFolder = new LocalMediaFolder();
allMediaFolder.setImageNum(totalCount);
allMediaFolder.setChecked(true);
allMediaFolder.setBucketId(-1);
if (data.moveToFirst()) {
String firstUrl = SdkVersionUtils.checkedAndroid_Q() ? getFirstUri(data) : getFirstUrl(data);
allMediaFolder.setFirstImagePath(firstUrl);
}
String bucketDisplayName = config.chooseMode == PictureMimeType.ofAudio() ?
mContext.getString(R.string.picture_all_audio)
: mContext.getString(R.string.picture_camera_roll);
allMediaFolder.setName(bucketDisplayName);
allMediaFolder.setOfAllType(config.chooseMode);
allMediaFolder.setCameraFolder(true);
mediaFolders.add(0, allMediaFolder);
return mediaFolders;
}
}
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "loadAllMedia Data Error: " + e.getMessage());
return null;
} finally {
if (data != null && !data.isClosed()) {
data.close();
}
}
return new ArrayList<>();
}
@Override
public void onSuccess(List<LocalMediaFolder> result) {
if (listener != null && result != null) {
listener.onComplete(result, 1, false);
}
}
});
}
/**
* Get cover uri
*
* @param cursor
* @return
*/
private static String getFirstUri(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID));
return getRealPathAndroid_Q(id);
}
/**
* Get cover url
*
* @param cursor
* @return
*/
private static String getFirstUrl(Cursor cursor) {
return cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA));
}
private String getPageSelection(long bucketId) {
String durationCondition = getDurationCondition(0, 0);
boolean isSpecifiedFormat = !TextUtils.isEmpty(config.specifiedFormat);
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
if (bucketId == -1) {
// ofAll
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ " OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + durationCondition + ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
// Gets the specified album directory
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ " OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + durationCondition + ") AND " + COLUMN_BUCKET_ID + "=? AND " + MediaStore.MediaColumns.SIZE + ">0";
case PictureConfig.TYPE_IMAGE:
// Gets the image of the specified type
if (bucketId == -1) {
// ofAll
if (isSpecifiedFormat) {
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF + " AND " + MediaStore.MediaColumns.MIME_TYPE + "='" + config.specifiedFormat + "'")
+ ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
// Gets the specified album directory
if (isSpecifiedFormat) {
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF + " AND " + MediaStore.MediaColumns.MIME_TYPE + "='" + config.specifiedFormat + "'")
+ ") AND " + COLUMN_BUCKET_ID + "=? AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?"
+ (config.isGif ? "" : " AND " + MediaStore.MediaColumns.MIME_TYPE + NOT_GIF)
+ ") AND " + COLUMN_BUCKET_ID + "=? AND " + MediaStore.MediaColumns.SIZE + ">0";
case PictureConfig.TYPE_VIDEO:
case PictureConfig.TYPE_AUDIO:
if (bucketId == -1) {
// ofAll
if (isSpecifiedFormat) {
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + MediaStore.MediaColumns.MIME_TYPE + "='" + config.specifiedFormat + "'" + " AND " + durationCondition + ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + durationCondition + ") AND " + MediaStore.MediaColumns.SIZE + ">0";
}
// Gets the specified album directory
if (isSpecifiedFormat) {
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + MediaStore.MediaColumns.MIME_TYPE + "='" + config.specifiedFormat + "'" + " AND " + durationCondition + ") AND " + COLUMN_BUCKET_ID + "=? AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=? AND " + durationCondition + ") AND " + COLUMN_BUCKET_ID + "=? AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return null;
}
private String[] getPageSelectionArgs(long bucketId) {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
if (bucketId == -1) {
// ofAll
return new String[]{
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
};
}
// Gets the specified album directory
return new String[]{
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
ValueOf.toString(bucketId)
};
case PictureConfig.TYPE_IMAGE:
// Get photo
return getSelectionArgsForPageSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE, bucketId);
case PictureConfig.TYPE_VIDEO:
// Get video
return getSelectionArgsForPageSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO, bucketId);
case PictureConfig.TYPE_AUDIO:
// Get audio
return getSelectionArgsForPageSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_AUDIO, bucketId);
}
return null;
}
private String getSelection() {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
// Get all, not including audio
return getSelectionArgsForAllMediaCondition(getDurationCondition(0, 0), config.isGif);
case PictureConfig.TYPE_IMAGE:
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// 获取指定类型的图片
if (SdkVersionUtils.checkedAndroid_Q()) {
return SELECTION_SPECIFIED_FORMAT_29 + "='" + config.specifiedFormat + "' AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "') AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
}
if (SdkVersionUtils.checkedAndroid_Q()) {
return config.isGif ? SELECTION_29 : SELECTION_NOT_GIF_29;
}
return config.isGif ? SELECTION : SELECTION_NOT_GIF;
case PictureConfig.TYPE_VIDEO:
// 获取视频
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// Gets the specified album directory
if (SdkVersionUtils.checkedAndroid_Q()) {
return SELECTION_SPECIFIED_FORMAT_29 + "='" + config.specifiedFormat + "' AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "') AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
}
return getSelectionArgsForSingleMediaCondition(getDurationCondition(0, 0));
case PictureConfig.TYPE_AUDIO:
// Get Audio
if (!TextUtils.isEmpty(config.specifiedFormat)) {
// Gets the specified album directory
if (SdkVersionUtils.checkedAndroid_Q()) {
return SELECTION_SPECIFIED_FORMAT_29 + "='" + config.specifiedFormat + "' AND " + MediaStore.MediaColumns.SIZE + ">0";
}
return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "') AND " + MediaStore.MediaColumns.SIZE + ">0)" + GROUP_BY_BUCKET_Id;
}
return getSelectionArgsForSingleMediaCondition(getDurationCondition(0, AUDIO_DURATION));
}
return null;
}
private String[] getSelectionArgs() {
switch (config.chooseMode) {
case PictureConfig.TYPE_ALL:
return SELECTION_ALL_ARGS;
case PictureConfig.TYPE_IMAGE:
// Get photo
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE);
case PictureConfig.TYPE_VIDEO:
// Get video
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO);
case PictureConfig.TYPE_AUDIO:
return getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_AUDIO);
}
return null;
}
/**
* Sort by number of files
*
* @param imageFolders
*/
private void sortFolder(List<LocalMediaFolder> imageFolders) {
Collections.sort(imageFolders, (lhs, rhs) -> {
if (lhs.getData() == null || rhs.getData() == null) {
return 0;
}
int lSize = lhs.getImageNum();
int rSize = rhs.getImageNum();
return Integer.compare(rSize, lSize);
});
}
/**
* Android Q
*
* @param id
* @return
*/
private static String getRealPathAndroid_Q(long id) {
return QUERY_URI.buildUpon().appendPath(ValueOf.toString(id)).build().toString();
}
/**
* Get video (maximum or minimum time)
*
* @param exMaxLimit
* @param exMinLimit
* @return
*/
private String getDurationCondition(long exMaxLimit, long exMinLimit) {
long maxS = config.videoMaxSecond == 0 ? Long.MAX_VALUE : config.videoMaxSecond;
if (exMaxLimit != 0) {
maxS = Math.min(maxS, exMaxLimit);
}
return String.format(Locale.CHINA, "%d <%s " + MediaStore.MediaColumns.DURATION + " and " + MediaStore.MediaColumns.DURATION + " <= %d",
Math.max(exMinLimit, config.videoMinSecond),
Math.max(exMinLimit, config.videoMinSecond) == 0 ? "" : "=",
maxS);
}
private static LocalMediaPageLoader instance;
public static LocalMediaPageLoader getInstance(Context context, PictureSelectionConfig
config) {
if (instance == null) {
synchronized (LocalMediaPageLoader.class) {
if (instance == null) {
instance = new LocalMediaPageLoader(context.getApplicationContext(), config);
}
}
}
return instance;
}
/**
* set empty
*/
public static void setInstanceNull() {
instance = null;
}
}

View File

@ -1,52 +0,0 @@
package com.luck.picture.lib.observable;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.ArrayList;
import java.util.List;
/**
* @authorluck
* @date2017-1-12 21:30
* @describe解决预览时传值过大问题
*/
public class ImagesObservable {
private List<LocalMedia> data;
private static ImagesObservable sObserver;
public static ImagesObservable getInstance() {
if (sObserver == null) {
synchronized (ImagesObservable.class) {
if (sObserver == null) {
sObserver = new ImagesObservable();
}
}
}
return sObserver;
}
/**
* 存储图片用于预览时用
*
* @param data
*/
public void savePreviewMediaData(List<LocalMedia> data) {
this.data = data;
}
/**
* 读取预览的图片
*/
public List<LocalMedia> readPreviewMediaData() {
return data == null ? new ArrayList<>() : data;
}
/**
* 清空预览的图片
*/
public void clearPreviewMediaData() {
if (data != null) {
data.clear();
}
}
}

View File

@ -1,62 +0,0 @@
package com.luck.picture.lib.permissions;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
/**
* @authorluck
* @date2019-11-20 19:07
* @describe权限检查
*/
public class PermissionChecker {
/**
* 检查是否有某个权限
*
* @param ctx
* @param permission
* @return
*/
public static boolean checkSelfPermission(Context ctx, String permission) {
return ContextCompat.checkSelfPermission(ctx.getApplicationContext(), permission)
== PackageManager.PERMISSION_GRANTED;
}
/**
* 动态申请多个权限
*
* @param activity
* @param code
*/
public static void requestPermissions(Activity activity, @NonNull String[] permissions, int code) {
ActivityCompat.requestPermissions(activity, permissions, code);
}
/**
* Launch the application's details settings.
*/
public static void launchAppDetailsSettings(Context context) {
Context applicationContext = context.getApplicationContext();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + applicationContext.getPackageName()));
if (!isIntentAvailable(context, intent)) return;
applicationContext.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
private static boolean isIntentAvailable(Context context, final Intent intent) {
return context.getApplicationContext()
.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
.size() > 0;
}
}

View File

@ -1,39 +0,0 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* 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.luck.picture.lib.photoview;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.View;
class Compat {
private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable);
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
}
}
@TargetApi(16)
private static void postOnAnimationJellyBean(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
}

View File

@ -1,206 +0,0 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.luck.picture.lib.photoview;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
/**
* Does a whole lot of gesture detecting.
*/
class CustomGestureDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;
private final ScaleGestureDetector mDetector;
private VelocityTracker mVelocityTracker;
private boolean mIsDragging;
private float mLastTouchX;
private float mLastTouchY;
private final float mTouchSlop;
private final float mMinimumVelocity;
private OnGestureListener mListener;
CustomGestureDetector(Context context, OnGestureListener listener) {
final ViewConfiguration configuration = ViewConfiguration
.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mTouchSlop = configuration.getScaledTouchSlop();
mListener = listener;
ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
return false;
if (scaleFactor >= 0) {
mListener.onScale(scaleFactor,
detector.getFocusX(), detector.getFocusY());
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// NO-OP
}
};
mDetector = new ScaleGestureDetector(context, mScaleListener);
}
private float getActiveX(MotionEvent ev) {
try {
return ev.getX(mActivePointerIndex);
} catch (Exception e) {
return ev.getX();
}
}
private float getActiveY(MotionEvent ev) {
try {
return ev.getY(mActivePointerIndex);
} catch (Exception e) {
return ev.getY();
}
}
public boolean isScaling() {
return mDetector.isInProgress();
}
public boolean isDragging() {
return mIsDragging;
}
public boolean onTouchEvent(MotionEvent ev) {
try {
mDetector.onTouchEvent(ev);
return processTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is called
return true;
}
}
private boolean processTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mVelocityTracker = VelocityTracker.obtain();
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
mIsDragging = false;
break;
case MotionEvent.ACTION_MOVE:
final float x = getActiveX(ev);
final float y = getActiveY(ev);
final float dx = x - mLastTouchX, dy = y - mLastTouchY;
if (!mIsDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
if (mIsDragging) {
mListener.onDrag(dx, dy);
mLastTouchX = x;
mLastTouchY = y;
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
}
break;
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER_ID;
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
if (mIsDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
// Compute velocity within the last 1000ms
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
.getYVelocity();
// If the velocity is greater than minVelocity, call
// listener
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
mListener.onFling(mLastTouchX, mLastTouchY, -vX,
-vY);
}
}
}
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
case MotionEvent.ACTION_POINTER_UP:
final int pointerIndex = Util.getPointerIndex(ev.getAction());
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}
mActivePointerIndex = ev
.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
: 0);
return true;
}
}

View File

@ -1,27 +0,0 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* 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.luck.picture.lib.photoview;
interface OnGestureListener {
void onDrag(float dx, float dy);
void onFling(float startX, float startY, float velocityX,
float velocityY);
void onScale(float scaleFactor, float focusX, float focusY);
}

View File

@ -1,18 +0,0 @@
package com.luck.picture.lib.photoview;
import android.graphics.RectF;
/**
* Interface definition for a callback to be invoked when the internal Matrix has changed for
* this View.
*/
public interface OnMatrixChangedListener {
/**
* Callback for when the Matrix displaying the Drawable has changed. This could be because
* the View's bounds have changed, or the user has zoomed.
*
* @param rect - Rectangle displaying the Drawable's new bounds.
*/
void onMatrixChanged(RectF rect);
}

View File

@ -1,14 +0,0 @@
package com.luck.picture.lib.photoview;
import android.widget.ImageView;
/**
* Callback when the user tapped outside of the photo
*/
public interface OnOutsidePhotoTapListener {
/**
* The outside of the photo has been tapped
*/
void onOutsidePhotoTap(ImageView imageView);
}

View File

@ -1,22 +0,0 @@
package com.luck.picture.lib.photoview;
import android.widget.ImageView;
/**
* A callback to be invoked when the Photo is tapped with a single
* tap.
*/
public interface OnPhotoTapListener {
/**
* A callback to receive where the user taps on a photo. You will only receive a callback if
* the user taps on the actual photo, tapping on 'whitespace' will be ignored.
*
* @param view ImageView the user tapped.
* @param x where the user tapped from the of the Drawable, as percentage of the
* Drawable width.
* @param y where the user tapped from the top of the Drawable, as percentage of the
* Drawable height.
*/
void onPhotoTap(ImageView view, float x, float y);
}

View File

@ -1,17 +0,0 @@
package com.luck.picture.lib.photoview;
/**
* Interface definition for callback to be invoked when attached ImageView scale changes
*/
public interface OnScaleChangedListener {
/**
* Callback for when the scale changes
*
* @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
* @param focusX focal point X position
* @param focusY focal point Y position
*/
void onScaleChange(float scaleFactor, float focusX, float focusY);
}

View File

@ -1,21 +0,0 @@
package com.luck.picture.lib.photoview;
import android.view.MotionEvent;
/**
* A callback to be invoked when the ImageView is flung with a single
* touch
*/
public interface OnSingleFlingListener {
/**
* A callback to receive where the user flings on a ImageView. You will receive a callback if
* the user flings anywhere on the view.
*
* @param e1 MotionEvent the user first touch.
* @param e2 MotionEvent the user last touch.
* @param velocityX distance of user's horizontal fling.
* @param velocityY distance of user's vertical fling.
*/
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}

View File

@ -1,16 +0,0 @@
package com.luck.picture.lib.photoview;
/**
* Interface definition for a callback to be invoked when the photo is experiencing a drag event
*/
public interface OnViewDragListener {
/**
* Callback for when the photo is experiencing a drag event. This cannot be invoked when the
* user is scaling.
*
* @param dx The change of the coordinates in the x-direction
* @param dy The change of the coordinates in the y-direction
*/
void onDrag(float dx, float dy);
}

Some files were not shown because too many files have changed in this diff Show More