完善导入、导出身份功能,目前可进入本地文件目录系统,任选目录导入或导出

This commit is contained in:
liubohahaha committed 2021-08-17 21:20:46 +08:00
1 parent d62a6e8eb7
commit e19a8efd11
85 files changed
+4924 -4

No files matched your search

+1
View File
@@ -78,6 +78,7 @@ dependencies {
implementation files('libs/gmhelper.jar') implementation files('libs/gmhelper.jar')
implementation files('libs/BaiduLBS_Android.jar') implementation files('libs/BaiduLBS_Android.jar')
implementation files('libs/min-dev-java-1.0-release.jar') implementation files('libs/min-dev-java-1.0-release.jar')
implementation project(path: ':fileselectorlib')
// implementation files('libs/vpnjce-1.0.jar') // implementation files('libs/vpnjce-1.0.jar')
// 在依赖中添加对jre的依赖,以尝试解决android.jar中原生javax与java中的javax的冲突问题 // 在依赖中添加对jre的依赖,以尝试解决android.jar中原生javax与java中的javax的冲突问题
@@ -7,9 +7,14 @@ package com.pkusz.min_vpn_client.activity.login;
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/ */
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@@ -30,6 +35,7 @@ import com.pkusz.min_vpn_client.utils.DigestUtilKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import br.com.simplepass.loadingbutton.customViews.CircularProgressButton; import br.com.simplepass.loadingbutton.customViews.CircularProgressButton;
@@ -43,7 +49,11 @@ import cn.qjm253.quick_android_easy_bar.EasyBar;
import cn.qjm253.quick_android_easy_bar.EasyBarExtensionsKt; import cn.qjm253.quick_android_easy_bar.EasyBarExtensionsKt;
import kotlin.Unit; import kotlin.Unit;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
import com.pkusz.min_vpn_client.utils.IdentityDump;
import com.pkusz.min_vpn_client.utils.identity.IdentityDump;
import com.pkusz.min_vpn_client.utils.identity.ScreenSizeUtils;
import com.zlylib.fileselectorlib.FileSelector;
import com.zlylib.fileselectorlib.utils.Const;
public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter> public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter>
@@ -153,7 +163,12 @@ public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter>
ContextExtensionKt.hideSoftKeyboard(this,export_identity); ContextExtensionKt.hideSoftKeyboard(this,export_identity);
export_identity.startAnimation(); export_identity.startAnimation();
export_identity.revertAnimation(); export_identity.revertAnimation();
new IdentityDump().exportIdentity(); //new IdentityDump().exportIdentity();
//showCustomizeDialog();
FileSelector.from(this)
.onlySelectFolder() //只能选择文件夹
.requestCode(2) //设置返回码
.start();
Toast.makeText(this, "You clicked export identity button", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "You clicked export identity button", Toast.LENGTH_SHORT).show();
}); });
@@ -163,7 +178,19 @@ public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter>
ContextExtensionKt.hideSoftKeyboard(this,import_identity); ContextExtensionKt.hideSoftKeyboard(this,import_identity);
import_identity.startAnimation(); import_identity.startAnimation();
import_identity.revertAnimation(); import_identity.revertAnimation();
new IdentityDump().importIdentity(); FileSelector.from(this)
// .onlyShowFolder() //只显示文件夹
//.onlySelectFolder() //只能选择文件夹
// .isSingle() // 只能选择一个
.setMaxCount(1) //设置最大选择数
.setFileTypes("png","jpg", "doc","apk", "mp3", "gif", "txt", "mp4", "zip","db","export") //设置文件类型
.setSortType(FileSelector.BY_NAME_ASC) //设置名字排序
//.setSortType(FileSelector.BY_TIME_ASC) //设置时间排序
//.setSortType(FileSelector.BY_SIZE_DESC) //设置大小排序
//.setSortType(FileSelector.BY_EXTENSION_DESC) //设置类型排序
.requestCode(1) //设置返回码
.setTargetPath("/storage/emulated/0/")
.start();
Toast.makeText(this, "You clicked import identity button", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "You clicked import identity button", Toast.LENGTH_SHORT).show();
}); });
@@ -290,4 +317,73 @@ public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter>
public void syncVpnInfoFailed() { public void syncVpnInfoFailed() {
showWarning("从VMS同步VPN服务器信息失败"); showWarning("从VMS同步VPN服务器信息失败");
} }
private void showCustomizeDialog() {
/* @setView 装入自定义View ==> R.layout.dialog_customize
* 由于dialog_customize.xml只放置了一个EditView,因此和图8一样
* dialog_customize.xml可自定义更复杂的View
*/
View view = LayoutInflater.from(this).inflate(R.layout.layout_identity_dialog,null,false);
final AlertDialog dialog = new AlertDialog.Builder(this).setView(view).create();
//使得点击对话框外部不消失对话框
dialog.setCanceledOnTouchOutside(false);
// Button test_button=view.findViewById(R.id.text_button);
// test_button.setOnClickListener(v->{
// Toast.makeText(this, "You clicked test button", Toast.LENGTH_SHORT).show();
// dialog.dismiss();
// });
dialog.show();
//设置dialog的位置、大小
Window dialogWindow = dialog.getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = (int) (ScreenSizeUtils.getInstance(this).getScreenWidth() * 0.8f);
lp.height = (int) (ScreenSizeUtils.getInstance(this).getScreenHeight() * 0.5f);
dialogWindow.setAttributes(lp);
}
@Override
//回调函数
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
//导入身份
if (requestCode == 1) {
if (data.getStringArrayListExtra(Const.EXTRA_RESULT_SELECTION) != null) {
ArrayList<String> essFileList = data.getStringArrayListExtra(Const.EXTRA_RESULT_SELECTION);
StringBuilder builder = new StringBuilder();
System.out.println(essFileList.size());
System.out.println(essFileList);
for (String file :
essFileList) {
builder.append(file);
}
System.out.print(builder.toString());
String path=builder.toString();
new IdentityDump().importIdentity(path);
Toast.makeText(this, "export adress is "+path, Toast.LENGTH_SHORT).show();
}
}
//导出身份
if(requestCode==2){
if (data.getStringArrayListExtra(Const.EXTRA_RESULT_SELECTION) != null) {
ArrayList<String> essFileList = data.getStringArrayListExtra(Const.EXTRA_RESULT_SELECTION);
StringBuilder builder = new StringBuilder();
System.out.println(essFileList.size());
System.out.println(essFileList);
for (String file :
essFileList) {
builder.append(file);
}
String path=builder.toString();
//new IdentityDump().importIdentity(path);
System.out.println(path);
new IdentityDump().exportIdentity(path);
Toast.makeText(this, "import address is "+path, Toast.LENGTH_SHORT).show();
}
}
}
}
} }
@@ -1,9 +1,12 @@
package com.pkusz.min_vpn_client.utils; package com.pkusz.min_vpn_client.utils.identity;
import com.pkusz.min_vpn_client.utils.KeyManager;
import security.SafeBag; import security.SafeBag;
import util.FileUtil; import util.FileUtil;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
@@ -79,6 +82,56 @@ public class IdentityDump {
.getIdentity("/"+username,identityPath)); .getIdentity("/"+username,identityPath));
} }
public void importIdentity(String identityFilePath){
// 导入身份前查看是否有该用户身份
// System.out.println("试图取出未导入的用户身份: "+KeyManager.INSTANCE
// .getIdentity("/"+username,identityPath));
// 从本地文件中读取身份数据
byte[] identityBytes;
try {
identityBytes=FileUtil.readFile(identityFilePath);
} catch (IOException e) {
e.printStackTrace();
return;
}
// 转成SafeBag
SafeBag safeBag=new SafeBag(identityBytes);
// 导入到本地身份数据库中
try {
KeyManager.INSTANCE.getKeyChain().importSafeBag(safeBag,"",true);
} catch (Exception e) {
e.printStackTrace();
}
// 导入身份后查看是否有该用户身份
int last=identityFilePath.lastIndexOf("/");
String identityPath=identityFilePath.substring(0,last);
System.out.println("查看是否成功导入用户身份: "+KeyManager.INSTANCE
.getIdentity("/"+username,identityPath));
}
public void exportIdentity(String identityPath){
String identityFilePath=identityPath+username+".export";
// 生成数据库身份
new IdentityDump().generateForeverIdentity(username,identityPath);
System.out.println("生成的用户身份: "+KeyManager.INSTANCE
.getIdentity("/"+username,identityPath));
// 导出数据库身份
SafeBag safeBag;
try {
safeBag=KeyManager.INSTANCE.getKeyChain().exportSafeBag("");
System.out.println(Arrays.toString(safeBag.getValue()));
} catch (Exception e) {
e.printStackTrace();
return;
}
// 将身份数据写入本地文件
try {
FileUtil.writeFile(identityFilePath,safeBag.getValue());
} catch (IOException e) {
e.printStackTrace();
}
}
} }
@@ -0,0 +1,38 @@
package com.pkusz.min_vpn_client.utils.identity;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.WindowManager;
public class ScreenSizeUtils {
private static ScreenSizeUtils instance = null;
private int screenWidth, screenHeight;
public static ScreenSizeUtils getInstance(Context mContext) {
if (instance == null) {
synchronized (ScreenSizeUtils.class) {
if (instance == null)
instance = new ScreenSizeUtils(mContext);
}
}
return instance;
}
private ScreenSizeUtils(Context mContext) {
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;// 获取屏幕分辨率宽度
screenHeight = dm.heightPixels;// 获取屏幕分辨率高度
}
//获取屏幕宽度
public int getScreenWidth() {
return screenWidth;
}
//获取屏幕高度
public int getScreenHeight() {
return screenHeight;
}
}
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="选择文件目录"
android:id="@+id/hint_text"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="33dp"
android:background="#EEEEEE"
android:orientation="horizontal">
<ImageView
android:id="@+id/imb_select_sdcard"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:rotation="90"
android:scaleType="centerInside"
android:src="@mipmap/ic_chevron_right_white_24dp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/breadcrumbs_view"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:paddingRight="10dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_file_list"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/confirm_button"
android:text="确定"
/>
</LinearLayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

+1
View File
@@ -0,0 +1 @@
/build
+37
View File
@@ -0,0 +1,37 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
//Android 自定义性ActionBar
implementation 'com.github.ZLYang110:TitleBar:1.0.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
implementation 'com.github.bumptech.glide:glide:4.8.0'
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'com.android.support:design:27.1.0'
}
View File
Whitespace-only changes.
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# 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
@@ -0,0 +1,27 @@
package com.zlylib.fileselectorlib;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.zlylib.fileselectorlib.test", appContext.getPackageName());
}
}
@@ -0,0 +1,21 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zlylib.fileselectorlib">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<activity android:name=".ui.FileSelectorActivity" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.ess.file.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
@@ -0,0 +1,66 @@
package com.zlylib.fileselectorlib;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.zlylib.fileselectorlib.ui.FileSelectorActivity;
import java.lang.ref.WeakReference;
public class FileSelector {
public static final int BY_NAME_ASC = 0;
public static final int BY_NAME_DESC = 1;
public static final int BY_TIME_ASC = 2;
public static final int BY_TIME_DESC = 3;
public static final int BY_SIZE_ASC = 4;
public static final int BY_SIZE_DESC = 5;
public static final int BY_EXTENSION_ASC = 6;
private final WeakReference<Context> mContext;
private final WeakReference<Fragment> mFragment;
private FileSelector(AppCompatActivity activity) {
this(activity,null);
}
private FileSelector(Fragment fragment){
this( fragment.getActivity(),fragment);
}
private FileSelector(Context mContext, Fragment mFragment) {
this.mContext = new WeakReference<>(mContext);
this.mFragment = new WeakReference<>(mFragment);
}
public static SelectCreator from(AppCompatActivity activity){
return new FileSelector(activity).initFile();
}
public static SelectCreator from(Fragment fragment){
return new FileSelector(fragment).initFile();
}
private SelectCreator initFile(){
return new SelectCreator(this);
}
public Context getActivity() {
return mContext.get();
}
public Fragment getFragment() {
return mFragment != null ? mFragment.get() : null;
}
}
@@ -0,0 +1,118 @@
package com.zlylib.fileselectorlib;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.zlylib.fileselectorlib.ui.FileSelectorActivity;
/**
* SelectCreator
* Created by zhangliyang on 2020/6/20.
*/
public final class SelectCreator {
private FileSelector filePicker;
private SelectOptions selectOptions;
public SelectCreator(FileSelector filePicker ) {
selectOptions = SelectOptions.getCleanInstance();
this.filePicker = filePicker;
}
public SelectCreator setMaxCount(int maxCount) {
selectOptions.maxCount = maxCount;
if (maxCount <= 1) {
selectOptions.maxCount = 1;
selectOptions.isSingle = true;
} else {
selectOptions.isSingle = false;
}
return this;
}
public SelectCreator setTargetPath(String path){
selectOptions.targetPath = path;
return this;
}
public SelectCreator setFileTypes(String... fileTypes) {
selectOptions.mFileTypes = fileTypes;
return this;
}
public SelectCreator setSortType(int sortType) {
selectOptions.setSortType(sortType);
return this;
}
public SelectCreator isSingle() {
selectOptions.isSingle = true;
selectOptions.maxCount = 1;
return this;
}
public SelectCreator onlyShowFolder() {
selectOptions.setOnlyShowFolder(true);
selectOptions.setOnlySelectFolder(true);
return this;
}
public SelectCreator onlySelectFolder() {
selectOptions.setOnlySelectFolder(true);
return this;
}
public SelectCreator setTilteBg(int color) {
selectOptions.setTitleBg(color);
return this;
}
public SelectCreator setTitleColor(int color) {
selectOptions.setTitleColor(color);
return this;
}
public SelectCreator setTitleLiftColor(int color) {
selectOptions.setTitleLiftColor(color);
return this;
}
public SelectCreator setTitleRightColor(int color) {
selectOptions.setTitleRightColor(color);
return this;
}
/* public SelectCreator onlyShowImages() {
selectOptions.onlyShowImages = true;
return this;
}
public SelectCreator onlyShowVideos() {
selectOptions.onlyShowVideos = true;
return this;
}
*/
public SelectCreator requestCode(int requestCode) {
selectOptions.request_code = requestCode;
return this;
}
public void start() {
final Context activity = filePicker.getActivity();
if (activity == null) {
return;
}
Intent intent = new Intent();
intent.setClass(activity, FileSelectorActivity.class);
Fragment fragment = filePicker.getFragment();
if (fragment != null) {
fragment.startActivityForResult(intent, selectOptions.request_code);
} else {
((AppCompatActivity)activity).startActivityForResult(intent, selectOptions.request_code);
}
}
}
@@ -0,0 +1,144 @@
package com.zlylib.fileselectorlib;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.text.TextUtils;
import com.zlylib.fileselectorlib.utils.FileUtils;
import java.io.File;
/**
* SelectOptions
* Created by ZHANGLIYANG on 2020/6/20.
*/
public class SelectOptions {
public static final String defaultTargetPath = Environment.getExternalStorageDirectory() + "/";
public String[] mFileTypes;
public String mSortType;//排序类型
public boolean isSingle = false;//是否是单选
public int maxCount = 10;//最多选的个数
private boolean onlyShowFolder = false;//只显示文件夹
private boolean onlySelectFolder = false;//只选择文件夹
//public boolean onlyShowImages = false;//只显示图片
//public boolean onlyShowVideos = false;//只显示视频
public int request_code;//返回码
public String targetPath = defaultTargetPath;//设置默认目录
private int titleBg = 0;//标题背景颜色
private int titleColor = 0;//标题文字颜色
private int titleLiftColor = 0;//标题左边颜色
private int titleRightColor = 0;//标题右边颜色
public String[] getFileTypes() {
if (mFileTypes == null || mFileTypes.length == 0) {
return new String[]{};
}
return mFileTypes;
}
public int getSortType() {
if (TextUtils.isEmpty(mSortType)) {
return FileUtils.BY_NAME_ASC;
}
return Integer.valueOf(mSortType);
}
public void setSortType(int sortType) {
mSortType = String.valueOf(sortType);
}
public String getTargetPath() {
if (!new File(targetPath).exists()) {
File file = new File(defaultTargetPath);
if (!file.exists()) {
file.mkdirs();
}
return defaultTargetPath;
}
return targetPath;
}
public boolean isOnlyShowFolder() {
return onlyShowFolder;
}
public void setOnlyShowFolder(boolean onlyShowFolder) {
this.onlyShowFolder = onlyShowFolder;
}
public boolean isOnlySelectFolder() {
return onlySelectFolder;
}
public void setOnlySelectFolder(boolean onlySelectFolder) {
this.onlySelectFolder = onlySelectFolder;
}
public int getTitleBg() {
return titleBg;
}
public void setTitleBg(int titleBg) {
this.titleBg = titleBg;
}
public int getTitleColor() {
return titleColor;
}
public void setTitleColor(int titleColor) {
this.titleColor = titleColor;
}
public int getTitleLiftColor() {
return titleLiftColor;
}
public void setTitleLiftColor(int titleLiftColor) {
this.titleLiftColor = titleLiftColor;
}
public int getTitleRightColor() {
return titleRightColor;
}
public void setTitleRightColor(int titleRightColor) {
this.titleRightColor = titleRightColor;
}
public static SelectOptions getInstance() {
return InstanceHolder.INSTANCE;
}
public static SelectOptions getCleanInstance() {
SelectOptions options = getInstance();
options.reset();
return options;
}
private void reset() {
mFileTypes = new String[]{};
mSortType = String.valueOf(FileUtils.BY_NAME_ASC);
isSingle = false;
maxCount = 10;
onlyShowFolder = false;
onlySelectFolder = false;
targetPath = defaultTargetPath;
titleBg = 0;//标题背景颜色
titleColor = 0;//标题文字颜色
titleLiftColor = 0;//标题左边颜色
titleRightColor = 0;//标题右边颜色
}
private static final class InstanceHolder {
private static final SelectOptions INSTANCE = new SelectOptions();
}
}
@@ -0,0 +1,32 @@
package com.zlylib.fileselectorlib.adapter;
import android.annotation.SuppressLint;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.zlylib.fileselectorlib.R;
import com.zlylib.fileselectorlib.bean.BreadModel;
import java.util.List;
/**
* BreadAdapter
* Created by zhangliyang on 2020/6/20.
*/
public class BreadAdapter extends BaseQuickAdapter<BreadModel, BaseViewHolder> {
public BreadAdapter(@Nullable List<BreadModel> data) {
super(R.layout.bread_item,data);
addChildClickViewIds(R.id.btn_bread);
}
@Override
protected void convert(BaseViewHolder helper, BreadModel item) {
helper.setText(R.id.btn_bread,item.getCurName());
}
}
@@ -0,0 +1,141 @@
package com.zlylib.fileselectorlib.adapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.zlylib.fileselectorlib.R;
import com.zlylib.fileselectorlib.bean.EssFile;
import com.zlylib.fileselectorlib.utils.FileSizeUtil;
import com.zlylib.fileselectorlib.utils.FileUtils;
import java.util.List;
/**
* FileListAdapter
* Created by zhangliyang on 2020/6/20.
*/
public class FileListAdapter extends BaseQuickAdapter<EssFile, BaseViewHolder> {
private onLoadFileCountListener loadFileCountListener;
public interface onLoadFileCountListener{
void onLoadFileCount(int posistion);
}
public onLoadFileCountListener getLoadFileCountListener() {
return loadFileCountListener;
}
public void setLoadFileCountListener(onLoadFileCountListener loadFileCountListener) {
this.loadFileCountListener = loadFileCountListener;
}
public FileListAdapter(@Nullable List<EssFile> data) {
super(R.layout.item_file_list, data);
}
@Override
protected void convert(BaseViewHolder helper, EssFile item) {
TextView textView = helper.getView(R.id.tv_item_file_list_desc);
if (item.isDirectory()) {
helper.setVisible(R.id.iv_item_file_select_right, true);
if(item.getChildFolderCount().equals("加载中")){
//查找数量
if(loadFileCountListener!=null){
loadFileCountListener.onLoadFileCount(helper.getAdapterPosition());
}
}
textView.setText(String.format(getContext().getString(R.string.folder_desc), item.getChildFileCount(),item.getChildFolderCount()));
} else {
helper.setVisible(R.id.iv_item_file_select_right, false);
textView.setText(String.format(getContext().getString(R.string.file_desc), FileUtils.getDateTime(item.getAbsolutePath()), FileSizeUtil.getAutoFileOrFilesSize(item.getFile())));
}
helper.setText(R.id.tv_item_file_list, item.getName());
if(item.isChecked()){
helper.setVisible(R.id.checkbox_item_file_list,true);
}else {
helper.setVisible(R.id.checkbox_item_file_list,false);
}
ImageView imageView = helper.getView(R.id.iv_item_file_select_left);
String fileNameExtension = FileUtils.getExtension(item.getName()).toLowerCase();
switch (fileNameExtension) {
case "apk":
imageView.setImageResource(R.mipmap.apk);
break;
case "avi":
imageView.setImageResource(R.mipmap.avi);
break;
case "doc":
case "docx":
imageView.setImageResource(R.mipmap.doc);
break;
case "exe":
imageView.setImageResource(R.mipmap.exe);
break;
case "flv":
imageView.setImageResource(R.mipmap.flv);
break;
case "gif":
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.mipmap.gif);
Glide
.with(getContext())
.load(item.getAbsolutePath())
.apply(options)
.into(imageView);
break;
case "jpg":
case "jpeg":
case "png":
RequestOptions options2 = new RequestOptions()
.centerCrop()
.placeholder(R.mipmap.png);
Glide
.with(getContext())
.load(item.getAbsolutePath())
.apply(options2)
.into(imageView);
break;
case "mp3":
imageView.setImageResource(R.mipmap.mp3);
break;
case "mp4":
case "f4v":
imageView.setImageResource(R.mipmap.movie);
break;
case "pdf":
imageView.setImageResource(R.mipmap.pdf);
break;
case "ppt":
case "pptx":
imageView.setImageResource(R.mipmap.ppt);
break;
case "wav":
imageView.setImageResource(R.mipmap.wav);
break;
case "xls":
case "xlsx":
imageView.setImageResource(R.mipmap.xls);
break;
case "zip":
imageView.setImageResource(R.mipmap.zip);
break;
case "ext":
default:
if (item.isDirectory()) {
imageView.setImageResource(R.mipmap.folder);
} else {
imageView.setImageResource(R.mipmap.documents);
}
break;
}
}
}
@@ -0,0 +1,26 @@
package com.zlylib.fileselectorlib.adapter;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.zlylib.fileselectorlib.R;
import java.util.List;
/**
* SelectSdcardAdapter
* Created by zhangliyang on 2020/6/22.
*/
public class SelectSdcardAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public SelectSdcardAdapter(@Nullable List<String> data) {
super(R.layout.item_select_sdcard,data);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.tv_item_select_sdcard,item);
}
}
@@ -0,0 +1,93 @@
package com.zlylib.fileselectorlib.bean;
import java.util.ArrayList;
import java.util.List;
/**
* BreadModel
* Created by zhangliyang on 2018/2/5.
*/
public class BreadModel {
/*当前Path*/
private String mCurPath;
/*之前的浏览位置,默认0*/
private int mPrePosition = 0;
/*当前面包屑的名称*/
private String mCurName;
public String getCurName() {
return mCurName;
}
public void setCurName(String mCurName) {
this.mCurName = mCurName;
}
public int getPrePosition() {
return mPrePosition;
}
public void setPrePosition(int mPrePosition) {
this.mPrePosition = mPrePosition;
}
public String getCurPath() {
return mCurPath;
}
public void setmCurPath(String mCurPath) {
this.mCurPath = mCurPath;
}
/**
* 获取需要添加的路径列表
* @param oldList
* @param newList
* @return
*/
public static List<BreadModel> getNewBreadModel(List<BreadModel> oldList, List<BreadModel> newList) {
List<BreadModel> newModelList = new ArrayList<>();
if (oldList == null || newList == null) {
return newModelList;
}
if (oldList.size() >= newList.size()) {
return newModelList;
}
for (int i = 0; i < newList.size(); i++) {
if (i < oldList.size()) {
continue;
}
newModelList.add(newList.get(i));
}
return newModelList;
}
/**
* 获取路径List需要裁剪的位置
* @param oldList
* @param newList
* @return
*/
public static int getRemovedBreadModel(List<BreadModel> oldList, List<BreadModel> newList) {
int removeFirstPosition = 0;
if (oldList == null || newList == null) {
return removeFirstPosition;
}
if (oldList.size() <= newList.size()) {
return removeFirstPosition;
}
for (int i = 0; i < oldList.size(); i++) {
if (i == newList.size()) {
return i;
}
}
return removeFirstPosition;
}
}
@@ -0,0 +1,291 @@
package com.zlylib.fileselectorlib.bean;
import android.content.ContentUris;
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.MediaStore;
import com.zlylib.fileselectorlib.utils.FileUtils;
import com.zlylib.fileselectorlib.utils.MimeType;
import com.zlylib.fileselectorlib.utils.PathUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* EssFile
* Created by zhangliyang on 2018/2/5.
*/
public class EssFile implements Parcelable {
public static final int CAPTURE = 0;
public static final int MEDIA = 1;
private String mFilePath;
private String mimeType;
private String childFolderCount = "加载中";
private String childFileCount = "加载中";
private boolean isChecked = false;
private boolean isExits = false;
private boolean isDirectory = false;
private boolean isFile = false;
private String mFileName;
private Uri uri;
private int itemType = MEDIA;
protected EssFile(Parcel in) {
mFilePath = in.readString();
mimeType = in.readString();
childFolderCount = in.readString();
childFileCount = in.readString();
isChecked = in.readByte() != 0;
isExits = in.readByte() != 0;
isDirectory = in.readByte() != 0;
isFile = in.readByte() != 0;
mFileName = in.readString();
uri = in.readParcelable(Uri.class.getClassLoader());
itemType = in.readInt();
}
public static final Creator<EssFile> CREATOR = new Creator<EssFile>() {
@Override
public EssFile createFromParcel(Parcel in) {
return new EssFile(in);
}
@Override
public EssFile[] newArray(int size) {
return new EssFile[size];
}
};
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
public EssFile(String path) {
mFilePath = path;
File file = new File(mFilePath);
if (file.exists()) {
isExits = true;
isDirectory = file.isDirectory();
isFile = file.isFile();
mFileName = file.getName();
}
mimeType = FileUtils.getMimeType(mFilePath);
}
public EssFile(File file) {
mFilePath = file.getAbsolutePath();
if (file.exists()) {
isExits = true;
isDirectory = file.isDirectory();
isFile = file.isFile();
}
mimeType = FileUtils.getMimeType(file.getAbsolutePath());
}
public EssFile(long id, String mimeType) {
this.mimeType = mimeType;
Uri contentUri;
if (isImage()) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if (isVideo()) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else {
// ?
contentUri = MediaStore.Files.getContentUri("external");
}
this.uri = ContentUris.withAppendedId(contentUri, id);
}
public Uri getUri() {
return uri;
}
public boolean isExits() {
return isExits;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public String getChildFolderCount() {
return childFolderCount;
}
public void setChildFolderCount(String childFolderCount) {
this.childFolderCount = childFolderCount;
}
public String getChildFileCount() {
return childFileCount;
}
public void setChildFileCount(String childFileCount) {
this.childFileCount = childFileCount;
}
public void setChildCounts(String childFileCount, String childFolderCount) {
this.childFileCount = childFileCount;
this.childFolderCount = childFolderCount;
}
public File getFile() {
return new File(mFilePath);
}
public String getName() {
return new File(mFilePath).getName();
}
public boolean isDirectory() {
return isDirectory;
}
public boolean isFile() {
return isFile;
}
public String getAbsolutePath() {
return mFilePath;
}
public static List<EssFile> getEssFileList(List<File> files,boolean isSelectFolder) {
List<EssFile> essFileList = new ArrayList<>();
for (File file :files) {
if(isSelectFolder){
if(isFolder(file)){//只添加文件夹
essFileList.add(new EssFile(file));
}
}else{
essFileList.add(new EssFile(file));
}
}
return essFileList;
}
public static ArrayList<EssFile> getEssFileList(Context context, Set<EssFile> essFileSet) {
ArrayList<EssFile> essFileArrayList = new ArrayList<>();
for (EssFile ess_file :
essFileSet) {
ess_file.mFilePath = PathUtils.getPath(context, ess_file.uri);
essFileArrayList.add(ess_file);
}
return essFileArrayList;
}
public static ArrayList<String> getFilePathList(ArrayList<EssFile> essFileArrayList){
ArrayList<String> resultList = new ArrayList<>();
for (EssFile essFile:essFileArrayList) {
resultList.add(essFile.getAbsolutePath());
}
return resultList;
}
@Override
public String toString() {
return "EssFile{" +
"mFilePath='" + mFilePath + '\'' +
", mimeType='" + mimeType + '\'' +
", mFileName='" + mFileName + '\'' +
'}';
}
public static boolean isFolder(File file) {
return file.isDirectory();
}
public boolean isImage() {
if (mimeType == null) return false;
return mimeType.equals(MimeType.JPEG.toString())
|| mimeType.equals(MimeType.PNG.toString())
|| mimeType.equals(MimeType.GIF.toString())
|| mimeType.equals(MimeType.BMP.toString())
|| mimeType.equals(MimeType.WEBP.toString());
}
public boolean isGif() {
if (mimeType == null) return false;
return mimeType.equals(MimeType.GIF.toString());
}
public boolean isVideo() {
if (mimeType == null) return false;
return mimeType.equals(MimeType.MPEG.toString())
|| mimeType.equals(MimeType.MP4.toString())
|| mimeType.equals(MimeType.QUICKTIME.toString())
|| mimeType.equals(MimeType.THREEGPP.toString())
|| mimeType.equals(MimeType.THREEGPP2.toString())
|| mimeType.equals(MimeType.MKV.toString())
|| mimeType.equals(MimeType.WEBM.toString())
|| mimeType.equals(MimeType.TS.toString())
|| mimeType.equals(MimeType.AVI.toString());
}
public void setItemType(int itemType) {
this.itemType = itemType;
}
public int getItemType() {
return itemType;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mFilePath);
dest.writeString(mimeType);
dest.writeString(childFolderCount);
dest.writeString(childFileCount);
dest.writeByte((byte) (isChecked ? 1 : 0));
dest.writeByte((byte) (isExits ? 1 : 0));
dest.writeByte((byte) (isDirectory ? 1 : 0));
dest.writeByte((byte) (isFile ? 1 : 0));
dest.writeString(mFileName);
dest.writeParcelable(uri, flags);
dest.writeInt(itemType);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof EssFile)) {
return false;
}
EssFile other = (EssFile) obj;
if (uri == null) {
return mFilePath.equalsIgnoreCase(other.getAbsolutePath());
} else {
return uri.equals(other.getUri());
}
}
@Override
public int hashCode() {
int result = mFilePath != null ? mFilePath.hashCode() : 0;
result = 31 * result + (uri != null ? uri.hashCode() : 0);
result = 31 * result + itemType;
return result;
}
}
@@ -0,0 +1,10 @@
package com.zlylib.fileselectorlib.bean;
/**
* EssFileCountCallBack
* Created by zhangliyang on 2018/3/5.
*/
public interface EssFileCountCallBack {
void onFindChildFileAndFolderCount(int position, String childFileCount, String childFolderCount);
}
@@ -0,0 +1,34 @@
package com.zlylib.fileselectorlib.bean;
import java.io.File;
import java.io.FileFilter;
/**
* EssFileFilter
* 不显示隐藏文件、文件夹
*/
public class EssFileFilter implements FileFilter {
private String[] mTypes;
public EssFileFilter(String[] types) {
this.mTypes = types;
}
@Override
public boolean accept(File file) {
if (file.isDirectory() && !file.isHidden()) {
return true;
}
if (mTypes != null && mTypes.length > 0) {
for (String mType : mTypes) {
if ((file.getName().endsWith(mType.toLowerCase()) || file.getName().endsWith(mType.toUpperCase())) && !file.isHidden()) {
// if (FileUtils.getMimeType(file.getAbsolutePath()).equalsIgnoreCase(MimeTypeMap.getSingleton().getMimeTypeFromExtension(mType))) {
return true;
}
}
}else {
return true;
}
return false;
}
}
@@ -0,0 +1,12 @@
package com.zlylib.fileselectorlib.bean;
import java.util.List;
/**
* EssFileListCallBack
* Created by zhangliyang on 2018/3/5.
*/
public interface EssFileListCallBack {
void onFindFileList(String queryPath, List<EssFile> essFileList);
}
@@ -0,0 +1,61 @@
package com.zlylib.fileselectorlib.core;
import android.os.AsyncTask;
import com.zlylib.fileselectorlib.bean.EssFile;
import com.zlylib.fileselectorlib.bean.EssFileCountCallBack;
import com.zlylib.fileselectorlib.bean.EssFileFilter;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
* EssFileCountTask
* Created by zhangliyang on 2020/6/20.
*/
public class EssFileCountTask extends AsyncTask<Void,Void,Void>{
private int position;
private String queryPath;
private String[] types;
private EssFileCountCallBack countCallBack;
private int childFileCount = 0;
private int childFolderCount = 0;
private Boolean isSelectFolder = false;
public EssFileCountTask(int position, String queryPath, String[] types, Boolean isSelectFolder, EssFileCountCallBack countCallBack) {
this.position = position;
this.queryPath = queryPath;
this.types = types;
this.isSelectFolder = isSelectFolder;
this.countCallBack = countCallBack;
}
@Override
protected Void doInBackground(Void... voids) {
File file = new File(queryPath);
File[] files = file.listFiles(new EssFileFilter(types));
if(files == null){
return null;
}
List<EssFile> fileList = EssFile.getEssFileList(Arrays.asList(files),isSelectFolder);
for (EssFile essFile :
fileList) {
if(essFile.isDirectory()){
childFolderCount++;
}else {
childFileCount++;
}
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
if(countCallBack!=null){
countCallBack.onFindChildFileAndFolderCount(position,String.valueOf(childFileCount),String.valueOf(childFolderCount));
}
}
}
@@ -0,0 +1,92 @@
package com.zlylib.fileselectorlib.core;
import android.os.AsyncTask;
import com.zlylib.fileselectorlib.bean.EssFile;
import com.zlylib.fileselectorlib.bean.EssFileFilter;
import com.zlylib.fileselectorlib.bean.EssFileListCallBack;
import com.zlylib.fileselectorlib.utils.FileUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* EssFileListTask
* Created by zhangliyang on 2018/3/5.
*/
public class EssFileListTask extends AsyncTask<Void,Void,List<EssFile>> {
private List<EssFile> mSelectedFileList;
private String queryPath;
private String[] types;
private int mSortType;
private EssFileListCallBack callBack;
private Boolean isSelectFolder = false;
public EssFileListTask(List<EssFile> mSelectedFileList, String queryPath, String[] types, int mSortType, Boolean isSelectFolder, EssFileListCallBack fileCallBack) {
this.mSelectedFileList = mSelectedFileList;
this.queryPath = queryPath;
this.types = types;
this.mSortType = mSortType;
this.isSelectFolder = isSelectFolder;
this.callBack = fileCallBack;
}
@Override
protected List<EssFile> doInBackground(Void... voids) {
File file = new File(queryPath);
File[] files = file.listFiles(new EssFileFilter(types));
if(files == null){
return new ArrayList<>();
}
List<File> fileList = Arrays.asList(files);
if(mSortType == FileUtils.BY_NAME_ASC){
Collections.sort(fileList, new FileUtils.SortByName());
}else if(mSortType == FileUtils.BY_NAME_DESC){
Collections.sort(fileList, new FileUtils.SortByName());
Collections.reverse(fileList);
}else if(mSortType == FileUtils.BY_TIME_ASC){
Collections.sort(fileList,new FileUtils.SortByTime());
}else if(mSortType == FileUtils.BY_TIME_DESC){
Collections.sort(fileList,new FileUtils.SortByTime());
Collections.reverse(fileList);
}else if(mSortType == FileUtils.BY_SIZE_ASC){
Collections.sort(fileList,new FileUtils.SortBySize());
}else if(mSortType == FileUtils.BY_SIZE_DESC){
Collections.sort(fileList,new FileUtils.SortBySize());
Collections.reverse(fileList);
}else if(mSortType == FileUtils.BY_EXTENSION_ASC){
Collections.sort(fileList,new FileUtils.SortByExtension());
}else if(mSortType == FileUtils.BY_EXTENSION_DESC){
Collections.sort(fileList,new FileUtils.SortByExtension());
Collections.reverse(fileList);
}
List<EssFile> tempFileList = EssFile.getEssFileList(fileList,isSelectFolder);
for (EssFile selectedFile :
mSelectedFileList) {
for (int i = 0; i < tempFileList.size(); i++) {
if (selectedFile.getAbsolutePath().equals(tempFileList.get(i).getAbsolutePath())) {
tempFileList.get(i).setChecked(true);
break;
}
}
}
return tempFileList;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(List<EssFile> essFileList) {
if(callBack!=null){
callBack.onFindFileList(queryPath,essFileList);
}
}
}
@@ -0,0 +1,359 @@
package com.zlylib.fileselectorlib.ui;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupWindow;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemChildClickListener;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.google.android.material.snackbar.Snackbar;
import com.zlylib.fileselectorlib.R;
import com.zlylib.fileselectorlib.SelectOptions;
import com.zlylib.fileselectorlib.adapter.BreadAdapter;
import com.zlylib.fileselectorlib.adapter.FileListAdapter;
import com.zlylib.fileselectorlib.adapter.SelectSdcardAdapter;
import com.zlylib.fileselectorlib.bean.BreadModel;
import com.zlylib.fileselectorlib.bean.EssFile;
import com.zlylib.fileselectorlib.bean.EssFileCountCallBack;
import com.zlylib.fileselectorlib.bean.EssFileListCallBack;
import com.zlylib.fileselectorlib.core.EssFileCountTask;
import com.zlylib.fileselectorlib.core.EssFileListTask;
import com.zlylib.fileselectorlib.utils.Const;
import com.zlylib.fileselectorlib.utils.FileUtils;
import com.zlylib.fileselectorlib.utils.LogUtils;
import com.zlylib.titlebarlib.ActionBarCommon;
import com.zlylib.titlebarlib.OnActionBarChildClickListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class FileSelectorActivity extends AppCompatActivity implements OnItemClickListener, OnItemChildClickListener,
View.OnClickListener, FileListAdapter.onLoadFileCountListener, EssFileListCallBack, EssFileCountCallBack {
/*当前目录,默认是SD卡根目录*/
private String mCurFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
/*是否刚才切换了SD卡路径*/
private boolean mHasChangeSdCard = false;
/*所有可访问存储设备列表*/
private List<String> mSdCardList;
private ActionBarCommon abc;
private RecyclerView mRecyclerView;
private RecyclerView mBreadRecyclerView;
private ImageView mImbSelectSdCard;
/**
* 已选中的文件列表
*/
private ArrayList<EssFile> mSelectedFileList = new ArrayList<>();// 全部信息列表
private ArrayList<String> mSelectedList = new ArrayList<>();//地址信息列表
/*当前选中排序方式的位置*/
private int mSelectSortTypeIndex = 0;
private BreadAdapter mBreadAdapter;
private FileListAdapter mAdapter;
private EssFileListTask essFileListTask;
private EssFileCountTask essFileCountTask;
private PopupWindow mSelectSdCardWindow;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_file);
mSdCardList = FileUtils.getAllSdPaths(this);
if (!mSdCardList.isEmpty()) {
mCurFolder = mSdCardList.get(0) + File.separator;
if(FileUtils.exist(SelectOptions.getInstance().getTargetPath())){
mCurFolder = SelectOptions.getInstance().getTargetPath();
}
}
initUi();
initData();
}
@SuppressLint("ResourceAsColor")
private void initUi() {
abc = findViewById(R.id.abc);
if (SelectOptions.getInstance().getTitleBg() != 0) {
abc.setBackgroundColor(getResources().getColor(SelectOptions.getInstance().getTitleBg()));
}
if (SelectOptions.getInstance().getTitleColor() != 0) {
abc.getTitleTextView().setTextColor(getResources().getColor(SelectOptions.getInstance().getTitleColor()));
}
if (SelectOptions.getInstance().getTitleLiftColor() != 0) {
abc.getLeftIconView().setColorFilter(getResources().getColor(SelectOptions.getInstance().getTitleLiftColor()));
}
if (SelectOptions.getInstance().getTitleRightColor() != 0) {
abc.getRightTextView().setTextColor(getResources().getColor(SelectOptions.getInstance().getTitleRightColor()));
}
abc.setOnLeftIconClickListener(new OnActionBarChildClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
abc.setOnRightTextClickListener(new OnActionBarChildClickListener() {
@Override
public void onClick(View v) {
if (SelectOptions.getInstance().isOnlySelectFolder()) {
mSelectedList.add(mCurFolder);
}
//选中
if (mSelectedList.isEmpty()) {
return;
}
//不为空,向main activity返回数据
Intent result = new Intent();
result.putStringArrayListExtra(Const.EXTRA_RESULT_SELECTION, mSelectedList);
setResult(RESULT_OK, result);
finish();
}
});
if (SelectOptions.getInstance().isOnlyShowFolder()) {
abc.getRightTextView().setText("选中");
}
mRecyclerView = findViewById(R.id.rcv_file_list);
mBreadRecyclerView = findViewById(R.id.breadcrumbs_view);
mImbSelectSdCard = findViewById(R.id.imb_select_sdcard);
mImbSelectSdCard.setOnClickListener(this);
if (!mSdCardList.isEmpty() && mSdCardList.size() > 1) {
mImbSelectSdCard.setVisibility(View.VISIBLE);
}
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new FileListAdapter(new ArrayList<EssFile>());
mAdapter.setLoadFileCountListener(this);
mRecyclerView.setAdapter(mAdapter);
mAdapter.onAttachedToRecyclerView(mRecyclerView);
mAdapter.setOnItemClickListener(this);
List<BreadModel> breadModelList = FileUtils.getBreadModeListFromPath(mSdCardList, mCurFolder);
mBreadRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mBreadAdapter = new BreadAdapter(breadModelList);
mBreadRecyclerView.setAdapter(mBreadAdapter);
mBreadAdapter.onAttachedToRecyclerView(mBreadRecyclerView);
mBreadAdapter.setOnItemChildClickListener(this);
}
private void initData() {
executeListTask(mSelectedFileList, mCurFolder, SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().getSortType());
}
private void executeListTask(List<EssFile> essFileList, String queryPath, String[] types, int sortType) {
essFileListTask = new EssFileListTask(essFileList, queryPath, types, sortType, SelectOptions.getInstance().isOnlyShowFolder(), this);
essFileListTask.execute();
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.imb_select_sdcard) {
showPopupWindow();
}
}
/**
* 显示选择SdCard的PopupWindow
* 点击其他区域隐藏,阴影
*/
private void showPopupWindow() {
if (mSelectSdCardWindow != null) {
mSelectSdCardWindow.showAsDropDown(mImbSelectSdCard);
return;
}
View popView = LayoutInflater.from(this).inflate(R.layout.pop_select_sdcard, null);
mSelectSdCardWindow = new PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mSelectSdCardWindow.setFocusable(true);
mSelectSdCardWindow.setOutsideTouchable(true);
RecyclerView recyclerView = popView.findViewById(R.id.rcv_pop_select_sdcard);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
final SelectSdcardAdapter adapter = new SelectSdcardAdapter(FileUtils.getAllSdCardList(mSdCardList));
recyclerView.setAdapter(adapter);
adapter.onAttachedToRecyclerView(recyclerView);
adapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapterIn, View view, int position) {
mSelectSdCardWindow.dismiss();
mHasChangeSdCard = true;
executeListTask(mSelectedFileList, FileUtils.getChangeSdCard(adapter.getData().get(position), mSdCardList), SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().getSortType());
}
});
mSelectSdCardWindow.showAsDropDown(mImbSelectSdCard);
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
if (adapter.equals(mBreadAdapter) && view.getId() == R.id.btn_bread) {
//点击某个路径时
String queryPath = FileUtils.getBreadModelListByPosition(mSdCardList, mBreadAdapter.getData(), position);
if (mCurFolder.equals(queryPath)) {
return;
}
executeListTask(mSelectedFileList, queryPath, SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().getSortType());
}
}
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, final int position) {
if (adapter.equals(mAdapter)) {
EssFile item = mAdapter.getData().get(position);
if (item.isDirectory()) {
//点击文件夹
//保存当前的垂直滚动位置
mBreadAdapter.getData().get(mBreadAdapter.getData().size() - 1).setPrePosition(mRecyclerView.computeVerticalScrollOffset());
executeListTask(mSelectedFileList, mCurFolder + item.getName() + File.separator, SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().getSortType());
} else {
//选中某文件后,判断是否只能选择文件夹
if (SelectOptions.getInstance().isOnlySelectFolder()) {
if (!item.getFile().isDirectory()) {
Snackbar.make(mRecyclerView, "您只能选择文件夹", Snackbar.LENGTH_SHORT).show();
}
return;
}
// if (SelectOptions.getInstance().isSingle) {
// mSelectedFileList.add(item);
// mSelectedList.add(item.getAbsolutePath());
// Intent result = new Intent();
// result.putParcelableArrayListExtra(Const.EXTRA_RESULT_SELECTION, mSelectedFileList);
// setResult(RESULT_OK, result);
// super.onBackPressed();
// return;
// }
//选中某文件后,判断是否单选
if (SelectOptions.getInstance().isSingle) {
mSelectedFileList.add(item);
mSelectedList.add(item.getAbsolutePath());
Intent result = new Intent();
result.putStringArrayListExtra(Const.EXTRA_RESULT_SELECTION, mSelectedList);
setResult(RESULT_OK, result);
finish();
}
if (mAdapter.getData().get(position).isChecked()) {
int index = findFileIndex(item);
if (index != -1) {
mSelectedFileList.remove(index);
mSelectedList.remove(index);
}
} else {
if (mSelectedFileList.size() >= SelectOptions.getInstance().maxCount) {
//超出最大可选择数量后
Snackbar.make(mRecyclerView, "您最多只能选择" + SelectOptions.getInstance().maxCount + "个。", Snackbar.LENGTH_SHORT).show();
return;
}
mSelectedFileList.add(item);
mSelectedList.add(item.getAbsolutePath());
}
mAdapter.getData().get(position).setChecked(!mAdapter.getData().get(position).isChecked());
// mAdapter.notifyItemChanged(position, "");
mAdapter.notifyDataSetChanged();
abc.getRightTextView().setText(String.format(getString(R.string.selected_file_count), String.valueOf(mSelectedFileList.size()), String.valueOf(SelectOptions.getInstance().maxCount)));
}
}
}
/**
* 查找文件位置
*/
private int findFileIndex(EssFile item) {
for (int i = 0; i < mSelectedFileList.size(); i++) {
if (mSelectedFileList.get(i).getAbsolutePath().equals(item.getAbsolutePath())) {
return i;
}
}
return -1;
}
@Override
public void onLoadFileCount(int posistion) {
essFileCountTask = new EssFileCountTask(posistion, mAdapter.getData().get(posistion).getAbsolutePath(), SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().isOnlyShowFolder(), this);
essFileCountTask.execute();
}
/**
* 查找到文件列表后
*
* @param queryPath 查询路径
* @param fileList 文件列表
*/
@Override
public void onFindFileList(String queryPath, List<EssFile> fileList) {
if (fileList.isEmpty()) {
mAdapter.setEmptyView(R.layout.empty_file_list);
}
mCurFolder = queryPath;
mAdapter.setNewInstance(fileList);
List<BreadModel> breadModelList = FileUtils.getBreadModeListFromPath(mSdCardList, mCurFolder);
if (mHasChangeSdCard) {
mBreadAdapter.setNewInstance(breadModelList);
mHasChangeSdCard = false;
} else {
if (breadModelList.size() > mBreadAdapter.getData().size()) {
//新增
List<BreadModel> newList = BreadModel.getNewBreadModel(mBreadAdapter.getData(), breadModelList);
mBreadAdapter.addData(newList);
} else {
//减少
int removePosition = BreadModel.getRemovedBreadModel(mBreadAdapter.getData(), breadModelList);
if (removePosition > 0) {
mBreadAdapter.setNewData(mBreadAdapter.getData().subList(0, removePosition));
}
}
}
mBreadRecyclerView.smoothScrollToPosition(mBreadAdapter.getItemCount() - 1);
//先让其滚动到顶部,然后再scrollBy,滚动到之前保存的位置
mRecyclerView.scrollToPosition(0);
int scrollYPosition = mBreadAdapter.getData().get(mBreadAdapter.getData().size() - 1).getPrePosition();
//恢复之前的滚动位置
mRecyclerView.scrollBy(0, scrollYPosition);
}
@Override
public void onFindChildFileAndFolderCount(int position, String childFileCount, String childFolderCount) {
mAdapter.getData().get(position).setChildCounts(childFileCount, childFolderCount);
// mAdapter.notifyItemChanged(position, "childCountChanges");
mAdapter.notifyDataSetChanged();
}
@Override
public void onBackPressed() {
if (!FileUtils.canBackParent(mCurFolder, mSdCardList)) {
super.onBackPressed();
return;
}
executeListTask(mSelectedFileList, new File(mCurFolder).getParentFile().getAbsolutePath() + File.separator, SelectOptions.getInstance().getFileTypes(), SelectOptions.getInstance().getSortType());
}
@Override
protected void onDestroy() {
super.onDestroy();
// TODO: 2019/3/12 暂时移除
// EventBus.getDefault().unregister(this);
if (essFileListTask != null) {
essFileListTask.cancel(true);
}
if (essFileCountTask != null) {
essFileCountTask.cancel(true);
}
}
}
@@ -0,0 +1,98 @@
package com.zlylib.fileselectorlib.utils;
import java.util.HashMap;
import java.util.Map;
/**
* Const
* Created by zhangliyang on 2020/6/20.
*/
public class Const {
public static Map<String, String> mimeTypeMap = null;
static {
mimeTypeMap = new HashMap<>();
mimeTypeMap.put("apk","application/vnd.android.package-archive");
mimeTypeMap.put("asf", "video/x-ms-asf");
mimeTypeMap.put("avi", "video/x-msvideo");
mimeTypeMap.put("bin", "application/octet-stream");
mimeTypeMap.put("bmp", "image/bmp");
mimeTypeMap.put("c", "text/plain");
mimeTypeMap.put("class", "application/octet-stream");
mimeTypeMap.put("conf", "text/plain");
mimeTypeMap.put("cpp", "text/plain");
mimeTypeMap.put("doc", "application/msword");
mimeTypeMap.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
mimeTypeMap.put("xls", "application/vnd.ms-excel");
mimeTypeMap.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
mimeTypeMap.put("exe", "application/octet-stream");
mimeTypeMap.put("gif", "image/gif");
mimeTypeMap.put("gtar", "application/x-gtar");
mimeTypeMap.put("gz", "application/x-gzip");
mimeTypeMap.put("h", "text/plain");
mimeTypeMap.put("htm", "text/html");
mimeTypeMap.put("html", "text/html");
mimeTypeMap.put("jar", "application/java-archive");
mimeTypeMap.put("java", "text/plain");
mimeTypeMap.put("jpeg", "image/jpeg");
mimeTypeMap.put("jpg", "image/jpeg");
mimeTypeMap.put("js", "application/x-javascript");
mimeTypeMap.put("log", "text/plain");
mimeTypeMap.put("m3u", "audio/x-mpegurl");
mimeTypeMap.put("m4a", "audio/mp4a-latm");
mimeTypeMap.put("m4b", "audio/mp4a-latm");
mimeTypeMap.put("m4p", "audio/mp4a-latm");
mimeTypeMap.put("m4u", "video/vnd.mpegurl");
mimeTypeMap.put("m4v", "video/x-m4v");
mimeTypeMap.put("mov", "video/quicktime");
mimeTypeMap.put("mp2", "audio/x-mpeg");
mimeTypeMap.put("mp3", "audio/mpeg");
mimeTypeMap.put("mp4", "video/mp4");
mimeTypeMap.put("mpc", "application/vnd.mpohun.certificate");
mimeTypeMap.put("mpe", "video/mpeg");
mimeTypeMap.put("mpeg", "video/mpeg");
mimeTypeMap.put("mpg", "video/mpeg");
mimeTypeMap.put("mpg4", "video/mp4");
mimeTypeMap.put("mpga", "audio/mpeg");
mimeTypeMap.put("msg", "application/vnd.ms-outlook");
mimeTypeMap.put("ogg", "audio/ogg");
mimeTypeMap.put("pdf", "application/pdf");
mimeTypeMap.put("png", "image/png");
mimeTypeMap.put("pps", "application/vnd.ms-powerpoint");
mimeTypeMap.put("ppt", "application/vnd.ms-powerpoint");
mimeTypeMap.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
mimeTypeMap.put("prop", "text/plain");
mimeTypeMap.put("rc", "text/plain");
mimeTypeMap.put("rmvb", "audio/x-pn-realaudio");
mimeTypeMap.put("rtf", "application/rtf");
mimeTypeMap.put("sh", "text/plain");
mimeTypeMap.put("tar", "application/x-tar");
mimeTypeMap.put("tgz", "application/x-compressed");
mimeTypeMap.put("txt", "text/plain");
mimeTypeMap.put("wav", "audio/x-wav");
mimeTypeMap.put("wma", "audio/x-ms-wma");
mimeTypeMap.put("wmv", "audio/x-ms-wmv");
mimeTypeMap.put("wps", "application/vnd.ms-works");
mimeTypeMap.put("xml", "text/plain");
mimeTypeMap.put("z", "application/x-compress");
mimeTypeMap.put("zip", "application/x-zip-compressed");
mimeTypeMap.put("", "*/*");
}
/*文件类型*/
public static final String EXTRA_KEY_FILE_TYPE = "EXTRA_KEY_FILE_TYPE";
/*排序类型*/
public static final String EXTRA_KEY_SORT_TYPE = "EXTRA_KEY_SORT_TYPE";
/*是否多选*/
public static final String EXTRA_KEY_IS_SINGLE = "EXTRA_KEY_IS_SINGLE";
/*最大可选择数量*/
public static final String EXTRA_KEY_MAX_COUNT = "EXTRA_KEY_MAX_COUNT";
public static final String EXTRA_KEY_OnSelectFileListener = "EXTRA_KEY_OnSelectFileListener";
public static final String EXTRA_RESULT_SELECTION = "extra_result_selection";
}
@@ -0,0 +1,636 @@
package com.zlylib.fileselectorlib.utils;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.View;
import android.widget.ListView;
import android.widget.ScrollView;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
/**
* 数据类型转换、单位转换
*
* @author zhangliyang
* @since 2014-4-18
*/
public class ConvertUtils {
public static final long GB = 1073741824;
public static final long MB = 1048576;
public static final long KB = 1024;
public static int toInt(Object obj) {
try {
return Integer.parseInt(obj.toString());
} catch (NumberFormatException e) {
return -1;
}
}
public static int toInt(byte[] bytes) {
int result = 0;
byte abyte;
for (int i = 0; i < bytes.length; i++) {
abyte = bytes[i];
result += (abyte & 0xFF) << (8 * i);
}
return result;
}
public static int toShort(byte first, byte second) {
return (first << 8) + (second & 0xFF);
}
public static long toLong(Object obj) {
try {
return Long.parseLong(obj.toString());
} catch (NumberFormatException e) {
return -1L;
}
}
public static float toFloat(Object obj) {
try {
return Float.parseFloat(obj.toString());
} catch (NumberFormatException e) {
return -1f;
}
}
/**
* int占4字节
*
* @param i the
* @return byte [ ]
*/
public static byte[] toByteArray(int i) {
// byte[] bytes = new byte[4];
// bytes[0] = (byte) (0xff & i);
// bytes[1] = (byte) ((0xff00 & i) >> 8);
// bytes[2] = (byte) ((0xff0000 & i) >> 16);
// bytes[3] = (byte) ((0xff000000 & i) >> 24);
// return bytes;
return ByteBuffer.allocate(4).putInt(i).array();
}
public static byte[] toByteArray(String hexData, boolean isHex) {
if (hexData == null || hexData.equals("")) {
return null;
}
if (!isHex) {
return hexData.getBytes();
}
hexData = hexData.replaceAll("\\s+", "");
String hexDigits = "0123456789ABCDEF";
ByteArrayOutputStream baos = new ByteArrayOutputStream(
hexData.length() / 2);
// 将每2位16进制整数组装成一个字节
for (int i = 0; i < hexData.length(); i += 2) {
baos.write((hexDigits.indexOf(hexData.charAt(i)) << 4 | hexDigits
.indexOf(hexData.charAt(i + 1))));
}
byte[] bytes = baos.toByteArray();
try {
baos.close();
} catch (IOException e) {
LogUtils.warn(e);
}
return bytes;
}
public static String toHexString(String str) {
if (TextUtils.isEmpty(str))
return "";
StringBuilder builder = new StringBuilder();
byte[] bytes = str.getBytes();
for (byte aByte : bytes) {
builder.append(Integer.toHexString(0xFF & aByte));
builder.append(" ");
}
return builder.toString();
}
/**
* To hex string string.
*
* @param bytes the bytes
* @return the string
*/
public static String toHexString(byte... bytes) {
char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// 参见:http://www.oschina.net/code/snippet_116768_9019
char[] buffer = new char[bytes.length * 2];
for (int i = 0, j = 0; i < bytes.length; ++i) {
int u = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];//转无符号整型
buffer[j++] = DIGITS[u >>> 4];
buffer[j++] = DIGITS[u & 0xf];
}
return new String(buffer);
}
/**
* To hex string string.
*
* @param num the num
* @return the string
*/
public static String toHexString(int num) {
String hexString = Integer.toHexString(num);
LogUtils.verbose(String.format(Locale.CHINA, "%d to hex string is %s", num, hexString));
return hexString;
}
/**
* To binary string string.
*
* @param bytes the bytes
* @return the string
*/
public static String toBinaryString(byte... bytes) {
char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// 参见:http://www.oschina.net/code/snippet_116768_9019
char[] buffer = new char[bytes.length * 8];
for (int i = 0, j = 0; i < bytes.length; ++i) {
int u = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];//转无符号整型
buffer[j++] = DIGITS[(u >>> 7) & 0x1];
buffer[j++] = DIGITS[(u >>> 6) & 0x1];
buffer[j++] = DIGITS[(u >>> 5) & 0x1];
buffer[j++] = DIGITS[(u >>> 4) & 0x1];
buffer[j++] = DIGITS[(u >>> 3) & 0x1];
buffer[j++] = DIGITS[(u >>> 2) & 0x1];
buffer[j++] = DIGITS[(u >>> 1) & 0x1];
buffer[j++] = DIGITS[u & 0x1];
}
return new String(buffer);
}
/**
* To binary string string.
*
* @param num the num
* @return the string
*/
public static String toBinaryString(int num) {
String binaryString = Integer.toBinaryString(num);
LogUtils.verbose(String.format(Locale.CHINA, "%d to binary string is %s", num, binaryString));
return binaryString;
}
public static String toSlashString(String str) {
String result = "";
char[] chars = str.toCharArray();
for (char chr : chars) {
if (chr == '"' || chr == '\'' || chr == '\\') {
result += "\\";//符合“"”“'”“\”这三个符号的前面加一个“\”
}
result += chr;
}
return result;
}
public static <T> T[] toArray(List<T> list) {
//noinspection unchecked
return (T[]) list.toArray();
}
public static <T> List<T> toList(T[] array) {
return Arrays.asList(array);
}
public static String toString(Object[] objects) {
return Arrays.deepToString(objects);
}
public static String toString(Object[] objects, String tag) {
StringBuilder sb = new StringBuilder();
for (Object object : objects) {
sb.append(object);
sb.append(tag);
}
return sb.toString();
}
public static byte[] toByteArray(InputStream is) {
if (is == null) {
return null;
}
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buff = new byte[100];
while (true) {
int len = is.read(buff, 0, 100);
if (len == -1) {
break;
} else {
os.write(buff, 0, len);
}
}
byte[] bytes = os.toByteArray();
os.close();
is.close();
return bytes;
} catch (IOException e) {
LogUtils.warn(e);
}
return null;
}
public static byte[] toByteArray(Bitmap bitmap) {
if (bitmap == null) {
return null;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 将Bitmap压缩成PNG编码,质量为100%存储,除了PNG还有很多常见格式,如jpeg等。
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
byte[] bytes = os.toByteArray();
try {
os.close();
} catch (IOException e) {
LogUtils.warn(e);
}
return bytes;
}
public static Bitmap toBitmap(byte[] bytes, int width, int height) {
Bitmap bitmap = null;
if (bytes.length != 0) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
// 不进行图片抖动处理
options.inDither = false;
// 设置让解码器以最佳方式解码
options.inPreferredConfig = null;
if (width > 0 && height > 0) {
options.outWidth = width;
options.outHeight = height;
}
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
bitmap.setDensity(96);// 96 dpi
} catch (Exception e) {
LogUtils.error(e);
}
}
return bitmap;
}
public static Bitmap toBitmap(byte[] bytes) {
return toBitmap(bytes, -1, -1);
}
/**
* 将Drawable转换为Bitmap
* 参考:http://kylines.iteye.com/blog/1660184
*/
public static Bitmap toBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof ColorDrawable) {
//color
Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(((ColorDrawable) drawable).getColor());
return bitmap;
} else if (drawable instanceof NinePatchDrawable) {
//.9.png
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
return null;
}
/**
* 从第三方文件选择器获取路径。
* 参见:http://blog.csdn.net/zbjdsbj/article/details/42387551
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String toPath(Context context, Uri uri) {
if (uri == null) {
LogUtils.verbose("uri is null");
return "";
}
LogUtils.verbose("uri: " + uri.toString());
String path = uri.getPath();
String scheme = uri.getScheme();
String authority = uri.getAuthority();
//是否是4.4及以上版本
boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
String docId = DocumentsContract.getDocumentId(uri);
String[] split = docId.split(":");
String type = split[0];
Uri contentUri = null;
switch (authority) {
// ExternalStorageProvider
case "com.android.externalstorage.documents":
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
break;
// DownloadsProvider
case "com.android.providers.downloads.documents":
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
return _queryPathFromMediaStore(context, contentUri, null, null);
// MediaProvider
case "com.android.providers.media.documents":
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
String selection = "_id=?";
String[] selectionArgs = new String[]{split[1]};
return _queryPathFromMediaStore(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else {
if ("content".equalsIgnoreCase(scheme)) {
// Return the remote address
if (authority.equals("com.google.android.apps.photos.content")) {
return uri.getLastPathSegment();
}
return _queryPathFromMediaStore(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(scheme)) {
return uri.getPath();
}
}
LogUtils.verbose("uri to path: " + path);
return path;
}
private static String _queryPathFromMediaStore(Context context, Uri uri, String selection, String[] selectionArgs) {
String filePath = null;
try {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
filePath = cursor.getString(column_index);
cursor.close();
}
} catch (IllegalArgumentException e) {
LogUtils.error(e);
}
return filePath;
}
/**
* 把view转化为bitmap(截图)
* 参见:http://www.cnblogs.com/lee0oo0/p/3355468.html
*/
public static Bitmap toBitmap(View view) {
int width = view.getWidth();
int height = view.getHeight();
if (view instanceof ListView) {
height = 0;
// 获取listView实际高度
ListView listView = (ListView) view;
for (int i = 0; i < listView.getChildCount(); i++) {
height += listView.getChildAt(i).getHeight();
}
} else if (view instanceof ScrollView) {
height = 0;
// 获取scrollView实际高度
ScrollView scrollView = (ScrollView) view;
for (int i = 0; i < scrollView.getChildCount(); i++) {
height += scrollView.getChildAt(i).getHeight();
}
}
view.setDrawingCacheEnabled(true);
view.clearFocus();
view.setPressed(false);
boolean willNotCache = view.willNotCacheDrawing();
view.setWillNotCacheDrawing(false);
// Reset the drawing cache background color to fully transparent for the duration of this operation
int color = view.getDrawingCacheBackgroundColor();
view.setDrawingCacheBackgroundColor(Color.WHITE);//截图去黑色背景(透明像素)
if (color != Color.WHITE) {
view.destroyDrawingCache();
}
view.buildDrawingCache();
Bitmap cacheBitmap = view.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(cacheBitmap, 0, 0, null);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
if (!bitmap.isRecycled()) {
LogUtils.verbose("recycle bitmap: " + bitmap.toString());
bitmap.recycle();
}
// Restore the view
view.destroyDrawingCache();
view.setWillNotCacheDrawing(willNotCache);
view.setDrawingCacheBackgroundColor(color);
return bitmap;
}
public static Drawable toDrawable(Bitmap bitmap) {
return bitmap == null ? null : new BitmapDrawable(Resources.getSystem(), bitmap);
}
public static byte[] toByteArray(Drawable drawable) {
return toByteArray(toBitmap(drawable));
}
public static Drawable toDrawable(byte[] bytes) {
return toDrawable(toBitmap(bytes));
}
/**
* dp转换为px
*/
public static int toPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
int pxValue = (int) (dpValue * scale + 0.5f);
LogUtils.verbose(dpValue + " dp == " + pxValue + " px");
return pxValue;
}
/**
* px转换为dp
*/
public static int toDp(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
int dpValue = (int) (pxValue / scale + 0.5f);
LogUtils.verbose(pxValue + " px == " + dpValue + " dp");
return dpValue;
}
/**
* px转换为sp
*/
public static int toSp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
int spValue = (int) (pxValue / fontScale + 0.5f);
LogUtils.verbose(pxValue + " px == " + spValue + " sp");
return spValue;
}
public static String toGbk(String str) {
try {
return new String(str.getBytes("utf-8"), "gbk");
} catch (UnsupportedEncodingException e) {
LogUtils.warn(e);
return str;
}
}
public static String toFileSizeString(long fileSize) {
DecimalFormat df = new DecimalFormat("0.00");
String fileSizeString;
if (fileSize < KB) {
fileSizeString = fileSize + "B";
} else if (fileSize < MB) {
fileSizeString = df.format((double) fileSize / KB) + "K";
} else if (fileSize < GB) {
fileSizeString = df.format((double) fileSize / MB) + "M";
} else {
fileSizeString = df.format((double) fileSize / GB) + "G";
}
return fileSizeString;
}
public static String toString(InputStream is, String charset) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
while (true) {
String line = reader.readLine();
if (line == null) {
break;
} else {
sb.append(line).append("\n");
}
}
reader.close();
is.close();
} catch (IOException e) {
LogUtils.error(e);
}
return sb.toString();
}
public static String toString(InputStream is) {
return toString(is, "utf-8");
}
public static int toDarkenColor(@ColorInt int color) {
return toDarkenColor(color, 0.8f);
}
public static int toDarkenColor(@ColorInt int color, @FloatRange(from = 0f, to = 1f) float value) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= value;//HSV指Hue、Saturation、Value,即色调、饱和度和亮度,此处表示修改亮度
return Color.HSVToColor(hsv);
}
/**
* 转换为6位十六进制颜色代码,不含“#”
*/
public static String toColorString(@ColorInt int color) {
return toColorString(color, false);
}
/**
* 转换为6位十六进制颜色代码,不含“#”
*/
public static String toColorString(@ColorInt int color, boolean includeAlpha) {
String alpha = Integer.toHexString(Color.alpha(color));
String red = Integer.toHexString(Color.red(color));
String green = Integer.toHexString(Color.green(color));
String blue = Integer.toHexString(Color.blue(color));
if (alpha.length() == 1) {
alpha = "0" + alpha;
}
if (red.length() == 1) {
red = "0" + red;
}
if (green.length() == 1) {
green = "0" + green;
}
if (blue.length() == 1) {
blue = "0" + blue;
}
String colorString;
if (includeAlpha) {
colorString = alpha + red + green + blue;
LogUtils.verbose(String.format(Locale.CHINA, "%d to color string is %s", color, colorString));
} else {
colorString = red + green + blue;
LogUtils.verbose(String.format(Locale.CHINA, "%d to color string is %s%s%s%s, exclude alpha is %s", color, alpha, red, green, blue, colorString));
}
return colorString;
}
/**
* 对TextView、Button等设置不同状态时其文字颜色。
* 参见:http://blog.csdn.net/sodino/article/details/6797821
* Modified by liyujiang at 2015.08.13
*/
public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor,
@ColorInt int focusedColor, @ColorInt int unableColor) {
int[] colors = new int[]{pressedColor, focusedColor, normalColor, focusedColor, unableColor, normalColor};
int[][] states = new int[6][];
states[0] = new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled};
states[1] = new int[]{android.R.attr.state_enabled, android.R.attr.state_focused};
states[2] = new int[]{android.R.attr.state_enabled};
states[3] = new int[]{android.R.attr.state_focused};
states[4] = new int[]{android.R.attr.state_window_focused};
states[5] = new int[]{};
return new ColorStateList(states, colors);
}
public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor) {
return toColorStateList(normalColor, pressedColor, pressedColor, normalColor);
}
}
@@ -0,0 +1,236 @@
package com.zlylib.fileselectorlib.utils;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* 日期时间工具类
*
* @author zhangliyang
* @since 2015/8/5
*/
public class DateUtils extends android.text.format.DateUtils {
public static final int Second = 0;
public static final int Minute = 1;
public static final int Hour = 2;
public static final int Day = 3;
@IntDef(value = {Second, Minute, Hour, Day})
@Retention(RetentionPolicy.SOURCE)
public @interface DifferenceMode {
}
public static long calculateDifferentSecond(Date startDate, Date endDate) {
return calculateDifference(startDate, endDate, Second);
}
public static long calculateDifferentMinute(Date startDate, Date endDate) {
return calculateDifference(startDate, endDate, Minute);
}
public static long calculateDifferentHour(Date startDate, Date endDate) {
return calculateDifference(startDate, endDate, Hour);
}
public static long calculateDifferentDay(Date startDate, Date endDate) {
return calculateDifference(startDate, endDate, Day);
}
public static long calculateDifferentSecond(long startTimeMillis, long endTimeMillis) {
return calculateDifference(startTimeMillis, endTimeMillis, Second);
}
public static long calculateDifferentMinute(long startTimeMillis, long endTimeMillis) {
return calculateDifference(startTimeMillis, endTimeMillis, Minute);
}
public static long calculateDifferentHour(long startTimeMillis, long endTimeMillis) {
return calculateDifference(startTimeMillis, endTimeMillis, Hour);
}
public static long calculateDifferentDay(long startTimeMillis, long endTimeMillis) {
return calculateDifference(startTimeMillis, endTimeMillis, Day);
}
/**
* 计算两个时间戳之间相差的时间戳数
*/
public static long calculateDifference(long startTimeMillis, long endTimeMillis, @DifferenceMode int mode) {
return calculateDifference(new Date(startTimeMillis), new Date(endTimeMillis), mode);
}
/**
* 计算两个日期之间相差的时间戳数
*/
public static long calculateDifference(Date startDate, Date endDate, @DifferenceMode int mode) {
long[] different = calculateDifference(startDate, endDate);
if (mode == Minute) {
return different[2];
} else if (mode == Hour) {
return different[1];
} else if (mode == Day) {
return different[0];
} else {
return different[3];
}
}
private static long[] calculateDifference(Date startDate, Date endDate) {
return calculateDifference(endDate.getTime() - startDate.getTime());
}
private static long[] calculateDifference(long differentMilliSeconds) {
long secondsInMilli = 1000;//1s==1000ms
long minutesInMilli = secondsInMilli * 60;
long hoursInMilli = minutesInMilli * 60;
long daysInMilli = hoursInMilli * 24;
long elapsedDays = differentMilliSeconds / daysInMilli;
differentMilliSeconds = differentMilliSeconds % daysInMilli;
long elapsedHours = differentMilliSeconds / hoursInMilli;
differentMilliSeconds = differentMilliSeconds % hoursInMilli;
long elapsedMinutes = differentMilliSeconds / minutesInMilli;
differentMilliSeconds = differentMilliSeconds % minutesInMilli;
long elapsedSeconds = differentMilliSeconds / secondsInMilli;
LogUtils.verbose(String.format(Locale.CHINA, "different: %d ms, %d days, %d hours, %d minutes, %d seconds",
differentMilliSeconds, elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds));
return new long[]{elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds};
}
/**
* 计算每月的天数
*/
public static int calculateDaysInMonth(int month) {
return calculateDaysInMonth(0, month);
}
/**
* 根据年份及月份计算每月的天数
*/
public static int calculateDaysInMonth(int year, int month) {
// 添加大小月月份并将其转换为list,方便之后的判断
String[] bigMonths = {"1", "3", "5", "7", "8", "10", "12"};
String[] littleMonths = {"4", "6", "9", "11"};
List<String> bigList = Arrays.asList(bigMonths);
List<String> littleList = Arrays.asList(littleMonths);
// 判断大小月及是否闰年,用来确定"日"的数据
if (bigList.contains(String.valueOf(month))) {
return 31;
} else if (littleList.contains(String.valueOf(month))) {
return 30;
} else {
if (year <= 0) {
return 29;
}
// 是否闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
return 29;
} else {
return 28;
}
}
}
/**
* 月日时分秒,0-9前补0
*/
@NonNull
public static String fillZero(int number) {
return number < 10 ? "0" + number : "" + number;
}
/**
* 截取掉前缀0以便转换为整数
*
* @see #fillZero(int)
*/
public static int trimZero(@NonNull String text) {
try {
if (text.startsWith("0")) {
text = text.substring(1);
}
return Integer.parseInt(text);
} catch (NumberFormatException e) {
LogUtils.warn(e);
return 0;
}
}
/**
* 功能:判断日期是否和当前date对象在同一天。
* 参见:http://www.cnblogs.com/myzhijie/p/3330970.html
*
* @param date 比较的日期
* @return boolean 如果在返回true,否则返回false。
*/
public static boolean isSameDay(Date date) {
if (date == null) {
throw new IllegalArgumentException("date is null");
}
Calendar nowCalendar = Calendar.getInstance();
Calendar newCalendar = Calendar.getInstance();
newCalendar.setTime(date);
return (nowCalendar.get(Calendar.ERA) == newCalendar.get(Calendar.ERA) &&
nowCalendar.get(Calendar.YEAR) == newCalendar.get(Calendar.YEAR) &&
nowCalendar.get(Calendar.DAY_OF_YEAR) == newCalendar.get(Calendar.DAY_OF_YEAR));
}
/**
* 将yyyy-MM-dd HH:mm:ss字符串转换成日期<br/>
*
* @param dateStr 时间字符串
* @param dataFormat 当前时间字符串的格式。
* @return Date 日期 ,转换异常时返回null。
*/
public static Date parseDate(String dateStr, String dataFormat) {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat(dataFormat, Locale.PRC);
Date date = dateFormat.parse(dateStr);
return new Date(date.getTime());
} catch (ParseException e) {
LogUtils.warn(e);
return null;
}
}
/**
* 将yyyy-MM-dd HH:mm:ss字符串转换成日期<br/>
*
* @param dateStr yyyy-MM-dd HH:mm:ss字符串
* @return Date 日期 ,转换异常时返回null。
*/
public static Date parseDate(String dateStr) {
return parseDate(dateStr, "yyyy-MM-dd HH:mm:ss");
}
public static String getFileLastModifyTime(long time) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA);
return formatter.format(time);
}
/**
* 将指定的日期转换为一定格式的字符串
*/
public static String formatDate(Date date, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.PRC);
return sdf.format(date);
}
/**
* 将当前日期转换为一定格式的字符串
*/
public static String formatDate(String format) {
return formatDate(Calendar.getInstance(Locale.CHINA).getTime(), format);
}
}
@@ -0,0 +1,153 @@
package com.zlylib.fileselectorlib.utils;
import java.io.File;
import java.io.FileInputStream;
import java.text.DecimalFormat;
/**
* FileSizeUtil 计算文件大小,自动转换为b,kb,mb等
* Created by 李波 on 2018/2/7.
*/
public class FileSizeUtil {
private static final String TAG = FileSizeUtil.class.getSimpleName();
public static final int SIZETYPE_B = 1;//获取文件大小单位为B的double值
public static final int SIZETYPE_KB = 2;//获取文件大小单位为KB的double值
public static final int SIZETYPE_MB = 3;//获取文件大小单位为MB的double值
public static final int SIZETYPE_GB = 4;//获取文件大小单位为GB的double值
/**
* 获取文件指定文件的指定单位的大小
*
* @param filePath 文件路径
* @param sizeType 获取大小的类型1为B、2为KB、3为MB、4为GB
* @return double值的大小
*/
public static double getFileOrFilesSize(String filePath, int sizeType) {
File file = new File(filePath);
long blockSize = 0;
try {
if (file.isDirectory()) {
blockSize = getFileSizes(file);
} else {
blockSize = getFileSize(file);
}
} catch (Exception e) {
e.printStackTrace();
}
return FormetFileSize(blockSize, sizeType);
}
/**
* 调用此方法自动计算指定文件或指定文件夹的大小
*
* @return 计算好的带B、KB、MB、GB的字符串
*/
public static String getAutoFileOrFilesSize(File file) {
long blockSize = 0;
try {
if (file.isDirectory()) {
blockSize = getFileSizes(file);
} else {
blockSize = file.length();
}
} catch (Exception e) {
e.printStackTrace();
}
return FormetFileSize(blockSize);
}
/**
* 获取指定文件大小
*
* @param file
* @return
* @throws Exception
*/
private static long getFileSize(File file) throws Exception {
long size = 0;
if (file.exists()) {
FileInputStream fis = null;
fis = new FileInputStream(file);
size = fis.available();
} else {
file.createNewFile();
}
return size;
}
/**
* 获取指定文件夹
*
* @param f
* @return
* @throws Exception
*/
private static long getFileSizes(File f) throws Exception {
long size = 0;
File flist[] = f.listFiles();
for (int i = 0; i < flist.length; i++) {
if (flist[i].isDirectory()) {
size = size + getFileSizes(flist[i]);
} else {
size = size + getFileSize(flist[i]);
}
}
return size;
}
/**
* 转换文件大小
*
* @param fileS
* @return
*/
private static String FormetFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "GB";
}
return fileSizeString;
}
/**
* 转换文件大小,指定转换的类型
*
* @param fileS
* @param sizeType
* @return
*/
private static double FormetFileSize(long fileS, int sizeType) {
DecimalFormat df = new DecimalFormat("#.00");
double fileSizeLong = 0;
switch (sizeType) {
case SIZETYPE_B:
fileSizeLong = Double.valueOf(df.format((double) fileS));
break;
case SIZETYPE_KB:
fileSizeLong = Double.valueOf(df.format((double) fileS / 1024));
break;
case SIZETYPE_MB:
fileSizeLong = Double.valueOf(df.format((double) fileS / 1048576));
break;
case SIZETYPE_GB:
fileSizeLong = Double.valueOf(df.format((double) fileS / 1073741824));
break;
default:
break;
}
return fileSizeLong;
}
}
@@ -0,0 +1,946 @@
package com.zlylib.fileselectorlib.utils;
import android.content.Context;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import androidx.annotation.IntDef;
import com.zlylib.fileselectorlib.bean.BreadModel;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
/**
* 文件处理
* <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
*
* @author zhangliyang
* @since 2014-4-18
*/
public final class FileUtils {
public static final int BY_NAME_ASC = 0;
public static final int BY_NAME_DESC = 1;
public static final int BY_TIME_ASC = 2;
public static final int BY_TIME_DESC = 3;
public static final int BY_SIZE_ASC = 4;
public static final int BY_SIZE_DESC = 5;
public static final int BY_EXTENSION_ASC = 6;
public static final int BY_EXTENSION_DESC = 7;
@IntDef(value = {
BY_NAME_ASC,//按名称
BY_NAME_DESC,
BY_TIME_ASC,//按最后修改时间
BY_TIME_DESC,
BY_SIZE_ASC,//按大小
BY_SIZE_DESC,
BY_EXTENSION_ASC,//按文件扩展名
BY_EXTENSION_DESC
})
@Retention(RetentionPolicy.SOURCE)
public @interface SortType {
}
/**
* 将目录分隔符统一为平台默认的分隔符,并为目录结尾添加分隔符
*/
public static String separator(String path) {
String separator = File.separator;
path = path.replace("\\", separator);
if (!path.endsWith(separator)) {
path += separator;
}
return path;
}
/**
* 从路径名中获取面包屑导航列表
*
* @param mSdCardList mSdCardList
* @param path 路径名
* @return 面包屑导航列表
*/
public static List<BreadModel> getBreadModeListFromPath(List<String> mSdCardList, String path) {
List<String> pathList = new ArrayList<>();
for (int i = 0; i < mSdCardList.size(); i++) {
LogUtils.debug("getBreadModeListFromPath","--"+mSdCardList.get(i));
if (i == 0) {
//内部存储设备
path = path.replace(mSdCardList.get(i), "/内部存储设备");
} else {
path = path.replace(mSdCardList.get(i), "/SD卡" + i);
}
}
if (!TextUtils.isEmpty(path)) {
String[] a = path.substring(1, path.length()).split("/");
pathList = Arrays.asList(a);
}
List<BreadModel> breadModelList = new ArrayList<>();
for (String str : pathList) {
LogUtils.debug("getBreadModeListFromPath",str);
BreadModel breadModel = new BreadModel();
breadModel.setCurName(str);
breadModelList.add(breadModel);
}
return breadModelList;
}
/**
* 点击某个位置的面包屑导航,获取到面包屑导航列表
*
* @param mSdCardList mSdCardList
* @param breadModelList 原列表
* @param position 点击位置
* @return 新列表
*/
public static String getBreadModelListByPosition(List<String> mSdCardList, List<BreadModel> breadModelList, int position) {
StringBuilder result = new StringBuilder("/");
for (int i = 0; i < breadModelList.size(); i++) {
if (position >= i) {
result.append(breadModelList.get(i).getCurName()).append(File.separator);
} else {
break;
}
}
String resultStr = result.toString();
if (resultStr.startsWith("/内部存储设备")) {
resultStr = resultStr.replace("/内部存储设备", mSdCardList.get(0));
} else if (resultStr.startsWith("/SD卡")) {
resultStr = resultStr.replace("/SD卡" + String.valueOf(resultStr.charAt(4)), mSdCardList.get(Integer.valueOf(String.valueOf(resultStr.charAt(4)))));
}
return resultStr;
}
/**
* 切换SD卡路径
* @param sdCardName
* @param mSdCardList
* @return
*/
public static String getChangeSdCard(String sdCardName, List<String> mSdCardList){
if(TextUtils.isEmpty(sdCardName)){
return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
}
if(sdCardName.startsWith("内部存储设备")){
return mSdCardList.get(0) + File.separator;
}
if(sdCardName.startsWith("SD卡")){
return mSdCardList.get(Integer.valueOf(String.valueOf(sdCardName.charAt(3)))) + File.separator;
}
return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
}
/**
* 判断是否可以返回上一级目录,true可以返回上级目录,false不可以返回,直接finish
*/
public static boolean canBackParent(String curFolder, List<String> sdCardList) {
for (String sdcard :
sdCardList) {
if (curFolder.equals(sdcard + File.separator)) {
return false;
}
}
return true;
}
public static void closeSilently(Closeable c) {
if (c == null) {
return;
}
try {
c.close();
} catch (IOException e) {
// do nothing
}
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath, String[] excludeDirs, @SortType int sortType) {
ArrayList<File> dirList = new ArrayList<File>();
File startDir = new File(startDirPath);
if (!startDir.isDirectory()) {
return new File[0];
}
File[] dirs = startDir.listFiles(new FileFilter() {
public boolean accept(File f) {
if (f == null) {
return false;
}
//noinspection RedundantIfStatement
if (f.isDirectory()) {
return true;
}
return false;
}
});
if (dirs == null) {
return new File[0];
}
if (excludeDirs == null) {
excludeDirs = new String[0];
}
for (File dir : dirs) {
File file = dir.getAbsoluteFile();
if (!ConvertUtils.toString(excludeDirs).contains(file.getName())) {
dirList.add(file);
}
}
if (sortType == BY_NAME_ASC) {
Collections.sort(dirList, new SortByName());
} else if (sortType == BY_NAME_DESC) {
Collections.sort(dirList, new SortByName());
Collections.reverse(dirList);
} else if (sortType == BY_TIME_ASC) {
Collections.sort(dirList, new SortByTime());
} else if (sortType == BY_TIME_DESC) {
Collections.sort(dirList, new SortByTime());
Collections.reverse(dirList);
} else if (sortType == BY_SIZE_ASC) {
Collections.sort(dirList, new SortBySize());
} else if (sortType == BY_SIZE_DESC) {
Collections.sort(dirList, new SortBySize());
Collections.reverse(dirList);
} else if (sortType == BY_EXTENSION_ASC) {
Collections.sort(dirList, new SortByExtension());
} else if (sortType == BY_EXTENSION_DESC) {
Collections.sort(dirList, new SortByExtension());
Collections.reverse(dirList);
}
return dirList.toArray(new File[dirList.size()]);
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath, String[] excludeDirs) {
return listDirs(startDirPath, excludeDirs, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath) {
return listDirs(startDirPath, null, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有子目录及所有文件
*/
public static File[] listDirsAndFiles(String startDirPath, String[] allowExtensions) {
File[] dirs, files, dirsAndFiles;
dirs = listDirs(startDirPath);
if (allowExtensions == null) {
files = listFiles(startDirPath);
} else {
files = listFiles(startDirPath, allowExtensions);
}
if (dirs == null || files == null) {
return null;
}
dirsAndFiles = new File[dirs.length + files.length];
System.arraycopy(dirs, 0, dirsAndFiles, 0, dirs.length);
System.arraycopy(files, 0, dirsAndFiles, dirs.length, files.length);
return dirsAndFiles;
}
/**
* 列出指定目录下的所有子目录及所有文件
*/
public static File[] listDirsAndFiles(String startDirPath) {
return listDirsAndFiles(startDirPath, null);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, final Pattern filterPattern, @SortType int sortType) {
LogUtils.verbose(String.format("list file %s", startDirPath));
ArrayList<File> fileList = new ArrayList<File>();
File f = new File(startDirPath);
if (!f.isDirectory()) {
return new File[0];
}
File[] files = f.listFiles(new FileFilter() {
public boolean accept(File f) {
if (f == null) {
return false;
}
if (f.isDirectory()) {
return false;
}
//noinspection SimplifiableIfStatement
if (filterPattern == null) {
return true;
}
return filterPattern.matcher(f.getName()).find();
}
});
if (files == null) {
return new File[0];
}
for (File file : files) {
fileList.add(file.getAbsoluteFile());
}
if (sortType == BY_NAME_ASC) {
Collections.sort(fileList, new SortByName());
} else if (sortType == BY_NAME_DESC) {
Collections.sort(fileList, new SortByName());
Collections.reverse(fileList);
} else if (sortType == BY_TIME_ASC) {
Collections.sort(fileList, new SortByTime());
} else if (sortType == BY_TIME_DESC) {
Collections.sort(fileList, new SortByTime());
Collections.reverse(fileList);
} else if (sortType == BY_SIZE_ASC) {
Collections.sort(fileList, new SortBySize());
} else if (sortType == BY_SIZE_DESC) {
Collections.sort(fileList, new SortBySize());
Collections.reverse(fileList);
} else if (sortType == BY_EXTENSION_ASC) {
Collections.sort(fileList, new SortByExtension());
} else if (sortType == BY_EXTENSION_DESC) {
Collections.sort(fileList, new SortByExtension());
Collections.reverse(fileList);
}
return fileList.toArray(new File[fileList.size()]);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, Pattern filterPattern) {
return listFiles(startDirPath, filterPattern, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath) {
return listFiles(startDirPath, null, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, final String[] allowExtensions) {
LogUtils.verbose(String.format("list file %s", startDirPath));
File file = new File(startDirPath);
return file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//返回当前目录所有以某些扩展名结尾的文件
String extension = FileUtils.getExtension(name);
return ConvertUtils.toString(allowExtensions).contains(extension);
}
});
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, String allowExtension) {
return listFiles(startDirPath, new String[]{allowExtension});
}
/**
* 判断文件或目录是否存在
*/
public static boolean exist(String path) {
File file = new File(path);
return file.exists();
}
/**
* 删除文件或目录
*/
public static boolean delete(File file, boolean deleteRootDir) {
LogUtils.verbose(String.format("delete file %s", file.getAbsolutePath()));
boolean result = false;
if (file.isFile()) {
//是文件
result = deleteResolveEBUSY(file);
} else {
//是目录
File[] files = file.listFiles();
if (files == null) {
return false;
}
if (files.length == 0) {
result = deleteRootDir && deleteResolveEBUSY(file);
} else {
for (File f : files) {
delete(f, deleteRootDir);
result = deleteResolveEBUSY(f);
}
}
if (deleteRootDir) {
result = deleteResolveEBUSY(file);
}
}
return result;
}
/**
* bug: open failed: EBUSY (Device or resource busy)
* fix: http://stackoverflow.com/questions/11539657/open-failed-ebusy-device-or-resource-busy
*/
private static boolean deleteResolveEBUSY(File file) {
// Before you delete a Directory or File: rename it!
final File to = new File(file.getAbsolutePath() + System.currentTimeMillis());
//noinspection ResultOfMethodCallIgnored
file.renameTo(to);
return to.delete();
}
/**
* 删除文件或目录
*/
public static boolean delete(String path, boolean deleteRootDir) {
File file = new File(path);
//noinspection SimplifiableIfStatement
if (file.exists()) {
return delete(file, deleteRootDir);
}
return false;
}
/**
* 删除文件或目录, 不删除最顶层目录
*/
public static boolean delete(String path) {
return delete(path, false);
}
/**
* 删除文件或目录, 不删除最顶层目录
*/
public static boolean delete(File file) {
return delete(file, false);
}
/**
* 复制文件为另一个文件,或复制某目录下的所有文件及目录到另一个目录下
*/
public static boolean copy(String src, String tar) {
File srcFile = new File(src);
return srcFile.exists() && copy(srcFile, new File(tar));
}
/**
* 复制文件或目录
*/
public static boolean copy(File src, File tar) {
try {
LogUtils.verbose(String.format("copy %s to %s", src.getAbsolutePath(), tar.getAbsolutePath()));
if (src.isFile()) {
InputStream is = new FileInputStream(src);
OutputStream op = new FileOutputStream(tar);
BufferedInputStream bis = new BufferedInputStream(is);
BufferedOutputStream bos = new BufferedOutputStream(op);
byte[] bt = new byte[1024 * 8];
while (true) {
int len = bis.read(bt);
if (len == -1) {
break;
} else {
bos.write(bt, 0, len);
}
}
bis.close();
bos.close();
} else if (src.isDirectory()) {
File[] files = src.listFiles();
//noinspection ResultOfMethodCallIgnored
tar.mkdirs();
for (File file : files) {
copy(file.getAbsoluteFile(), new File(tar.getAbsoluteFile(), file.getName()));
}
}
return true;
} catch (Exception e) {
LogUtils.error(e);
return false;
}
}
/**
* 移动文件或目录
*/
public static boolean move(String src, String tar) {
return move(new File(src), new File(tar));
}
/**
* 移动文件或目录
*/
public static boolean move(File src, File tar) {
return rename(src, tar);
}
/**
* 文件重命名
*/
public static boolean rename(String oldPath, String newPath) {
return rename(new File(oldPath), new File(newPath));
}
/**
* 文件重命名
*/
public static boolean rename(File src, File tar) {
LogUtils.verbose(String.format("rename %s to %s", src.getAbsolutePath(), tar.getAbsolutePath()));
return src.renameTo(tar);
}
/**
* 读取文本文件, 失败将返回空串
*/
public static String readText(String filepath, String charset) {
LogUtils.verbose(String.format("read %s use %s", filepath, charset));
try {
byte[] data = readBytes(filepath);
if (data != null) {
return new String(data, charset).trim();
}
} catch (UnsupportedEncodingException e) {
LogUtils.warn(e);
}
return "";
}
/**
* 读取文本文件, 失败将返回空串
*/
public static String readText(String filepath) {
return readText(filepath, "utf-8");
}
/**
* 读取文件内容, 失败将返回空串
*/
public static byte[] readBytes(String filepath) {
LogUtils.verbose(String.format("read %s", filepath));
FileInputStream fis = null;
try {
fis = new FileInputStream(filepath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
int len = fis.read(buffer, 0, buffer.length);
if (len == -1) {
break;
} else {
baos.write(buffer, 0, len);
}
}
byte[] data = baos.toByteArray();
baos.close();
return data;
} catch (IOException e) {
LogUtils.warn(e);
return null;
} finally {
closeSilently(fis);
}
}
/**
* 保存文本内容
*/
public static boolean writeText(String filepath, String content, String charset) {
try {
writeBytes(filepath, content.getBytes(charset));
return true;
} catch (UnsupportedEncodingException e) {
LogUtils.warn(e);
return false;
}
}
/**
* 保存文本内容
*/
public static boolean writeText(String filepath, String content) {
return writeText(filepath, content, "utf-8");
}
/**
* 保存文件内容
*/
public static boolean writeBytes(String filepath, byte[] data) {
LogUtils.verbose(String.format("write %s", filepath));
File file = new File(filepath);
FileOutputStream fos = null;
try {
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.getParentFile().mkdirs();
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
}
fos = new FileOutputStream(filepath);
fos.write(data);
return true;
} catch (IOException e) {
LogUtils.warn(e);
return false;
} finally {
closeSilently(fos);
}
}
/**
* 追加文本内容
*/
public static boolean appendText(String path, String content) {
LogUtils.verbose(String.format("append %s", path));
File file = new File(path);
FileWriter writer = null;
try {
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
}
writer = new FileWriter(file, true);
writer.write(content);
return true;
} catch (IOException e) {
LogUtils.warn(e);
return false;
} finally {
closeSilently(writer);
}
}
/**
* 获取文件大小
*/
public static long getLength(String path) {
File file = new File(path);
if (!file.isFile() || !file.exists()) {
return 0;
}
return file.length();
}
/**
* 获取文件或网址的名称(包括后缀)
*/
public static String getName(String pathOrUrl) {
if (pathOrUrl == null) {
return "";
}
int pos = pathOrUrl.lastIndexOf('/');
if (0 <= pos) {
return pathOrUrl.substring(pos + 1);
} else {
return String.valueOf(System.currentTimeMillis()) + "." + getExtension(pathOrUrl);
}
}
/**
* 获取文件名(不包括扩展名)
*/
public static String getNameExcludeExtension(String path) {
try {
String fileName = (new File(path)).getName();
int lastIndexOf = fileName.lastIndexOf(".");
if (lastIndexOf != -1) {
fileName = fileName.substring(0, lastIndexOf);
}
return fileName;
} catch (Exception e) {
LogUtils.warn(e);
return "";
}
}
/**
* 获取格式化后的文件大小
*/
public static String getSize(String path) {
long fileSize = getLength(path);
return ConvertUtils.toFileSizeString(fileSize);
}
/**
* 获取文件后缀,不包括“.”
*/
public static String getExtension(String pathOrUrl) {
int dotPos = pathOrUrl.lastIndexOf('.');
if (0 <= dotPos) {
return pathOrUrl.substring(dotPos + 1);
} else {
return "ext";
}
}
/**
* 获取文件的MIME类型
*/
public static String getMimeType(String pathOrUrl) {
String ext = getExtension(pathOrUrl);
MimeTypeMap map = MimeTypeMap.getSingleton();
String mimeType;
if (map.hasExtension(ext)) {
mimeType = map.getMimeTypeFromExtension(ext);
} else {
mimeType = "*/*";
}
return mimeType;
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(String path) {
return getDateTime(path, "yyyy-MM-dd HH:mm");
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(String path, String format) {
File file = new File(path);
return getDateTime(file, format);
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(File file, String format) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(file.lastModified());
return DateUtils.formatDate(cal.getTime(), format);
}
/**
* 比较两个文件的最后修改时间
*/
public static int compareLastModified(String path1, String path2) {
long stamp1 = (new File(path1)).lastModified();
long stamp2 = (new File(path2)).lastModified();
if (stamp1 > stamp2) {
return 1;
} else if (stamp1 < stamp2) {
return -1;
} else {
return 0;
}
}
/**
* 创建多级别的目录
*/
public static boolean makeDirs(String path) {
return makeDirs(new File(path));
}
/**
* 创建多级别的目录
*/
public static boolean makeDirs(File file) {
return file.mkdirs();
}
public static class SortByExtension implements Comparator<File> {
public SortByExtension() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
return f1.getName().compareToIgnoreCase(f2.getName());
}
}
}
}
public static class SortByName implements Comparator<File> {
private boolean caseSensitive;
public SortByName(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
public SortByName() {
this.caseSensitive = false;
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
String s1 = f1.getName();
String s2 = f2.getName();
if (caseSensitive) {
return s1.compareTo(s2);
} else {
return s1.compareToIgnoreCase(s2);
}
}
}
}
}
public static class SortBySize implements Comparator<File> {
public SortBySize() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
if (f1.length() < f2.length()) {
return -1;
} else {
return 1;
}
}
}
}
}
public static class SortByTime implements Comparator<File> {
public SortByTime() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
if (f1.lastModified() > f2.lastModified()) {
return -1;
} else {
return 1;
}
}
}
}
}
/**
* 得到所有的存储路径(内部存储+外部存储)
*
* @param context context
* @return 路径列表
*/
public static List<String> getAllSdPaths(Context context) {
Method mMethodGetPaths = null;
String[] paths = null;
//通过调用类的实例mStorageManager的getClass()获取StorageManager类对应的Class对象
//getMethod("getVolumePaths")返回StorageManager类对应的Class对象的getVolumePaths方法,这里不带参数
StorageManager mStorageManager = (StorageManager) context
.getSystemService(context.STORAGE_SERVICE);//storage
try {
mMethodGetPaths = mStorageManager.getClass().getMethod("getVolumePaths");
paths = (String[]) mMethodGetPaths.invoke(mStorageManager);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (paths != null) {
return Arrays.asList(paths);
}
return new ArrayList<String>();
}
/**
* 获取用于显示的Sd卡列表
* @param sdCardList sdCardList
* @return List
*/
public static List<String> getAllSdCardList(List<String> sdCardList) {
List<String> resultList = new ArrayList<>();
for (int i = 0; i < sdCardList.size(); i++) {
if (i == 0) {
//内部存储设备
resultList.add("内部存储设备");
} else {
resultList.add("SD卡"+i);
}
}
return resultList;
}
}
@@ -0,0 +1,323 @@
package com.zlylib.fileselectorlib.utils;
import android.os.Debug;
import android.os.Environment;
import android.util.Log;
import com.zlylib.fileselectorlib.BuildConfig;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 将信息记录到控制台的LogCat,显示调用方法及所在的文件、行号,方便开发时调试查错。
* 注意:在Debug状态下开启,在Release状态下关闭,敏感信息不宜打印,否则被非法之徒抓取贻害无穷。
*
* @author zhangliyang[QQ:1023694760]
* @since 2013/11/2
*/
public final class LogUtils {
private static final int MIN_STACK_OFFSET = 3;// starts at this class after two native calls
private static final int MAX_STACK_TRACE_SIZE = 131071; //128 KB - 1
private static final int METHOD_COUNT = 2; // show method count in trace
private static boolean isDebug = BuildConfig.DEBUG;// 是否调试模式
private static String debugTag = "FilePicker";// LogCat的标记
public static void setIsDebug(boolean isDebug) {
LogUtils.isDebug = isDebug;
}
public static boolean isDebug() {
return isDebug;
}
public static void setDebugTag(String debugTag) {
LogUtils.debugTag = debugTag;
}
public static String getDebugTag() {
return debugTag;
}
/**
* Verbose.
*
* @param message the message
*/
public static void verbose(String message) {
verbose("", message);
}
/**
* Verbose.
*
* @param object the object
* @param message the message
*/
public static void verbose(Object object, String message) {
verbose(object.getClass().getSimpleName(), message);
}
/**
* 记录“verbose”级别的信息
*
* @param tag the tag
* @param msg the msg
*/
public static void verbose(String tag, String msg) {
if (isDebug) {
tag = debugTag + ((tag == null || tag.trim().length() == 0) ? "" : "-") + tag;
msg = msg + getTraceElement();
Log.v(tag, msg);
}
}
/**
* Debug.
*
* @param message the message
*/
public static void debug(String message) {
debug("", message);
}
/**
* Debug.
*
* @param object the object
* @param message the message
*/
public static void debug(Object object, String message) {
debug(object.getClass().getSimpleName(), message);
}
/**
* 记录“debug”级别的信息
*
* @param tag the tag
* @param msg the msg
*/
public static void debug(String tag, String msg) {
if (isDebug) {
tag = debugTag + ((tag == null || tag.trim().length() == 0) ? "" : "-") + tag;
msg = msg + getTraceElement();
Log.d(tag, msg);
}
}
/**
* Warn.
*
* @param e the e
*/
public static void warn(Throwable e) {
warn(toStackTraceString(e));
}
/**
* Warn.
*
* @param message the message
*/
public static void warn(String message) {
warn("", message);
}
/**
* Warn.
*
* @param object the object
* @param message the message
*/
public static void warn(Object object, String message) {
warn(object.getClass().getSimpleName(), message);
}
/**
* Warn.
*
* @param object the object
* @param e the e
*/
public static void warn(Object object, Throwable e) {
warn(object.getClass().getSimpleName(), toStackTraceString(e));
}
/**
* 记录“warn”级别的信息
*
* @param tag the tag
* @param msg the msg
*/
public static void warn(String tag, String msg) {
if (isDebug) {
tag = debugTag + ((tag == null || tag.trim().length() == 0) ? "" : "-") + tag;
msg = msg + getTraceElement();
Log.w(tag, msg);
}
}
/**
* Error.
*
* @param e the e
*/
public static void error(Throwable e) {
error(toStackTraceString(e));
}
/**
* Error.
*
* @param message the message
*/
public static void error(String message) {
error("", message);
}
/**
* Error.
*
* @param object the object
* @param message the message
*/
public static void error(Object object, String message) {
error(object.getClass().getSimpleName(), message);
}
/**
* Error.
*
* @param object the object
* @param e the e
*/
public static void error(Object object, Throwable e) {
error(object.getClass().getSimpleName(), toStackTraceString(e));
}
/**
* 记录“error”级别的信息
*
* @param tag the tag
* @param msg the msg
*/
public static void error(String tag, String msg) {
if (isDebug) {
tag = debugTag + ((tag == null || tag.trim().length() == 0) ? "" : "-") + tag;
msg = msg + getTraceElement();
Log.e(tag, msg);
}
}
/**
* 在某个方法中调用生成.trace文件。然后拿到电脑上用DDMS工具打开分析
*
* @see #stopMethodTracing()
*/
public static void startMethodTracing() {
if (isDebug) {
Debug.startMethodTracing(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + debugTag + ".trace");
}
}
/**
* Stop method tracing.
*/
public static void stopMethodTracing() {
if (isDebug) {
Debug.stopMethodTracing();
}
}
/**
* To stack trace string string.
* <p>
* 此方法参见:https://github.com/Ereza/CustomActivityOnCrash
*
* @param throwable the throwable
* @return the string
*/
public static String toStackTraceString(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
String stackTraceString = sw.toString();
//Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
//The limit is 1MB on Android but some devices seem to have it lower.
//See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
//And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
if (stackTraceString.length() > MAX_STACK_TRACE_SIZE) {
String disclaimer = " [stack trace too large]";
stackTraceString = stackTraceString.substring(0, MAX_STACK_TRACE_SIZE - disclaimer.length()) + disclaimer;
}
pw.close();
return stackTraceString;
}
/**
* 可显示调用方法所在的文件行号,在AndroidStudio的logcat处可点击定位。
* 此方法参考:https://github.com/orhanobut/logger
*/
private static String getTraceElement() {
try {
int methodCount = METHOD_COUNT;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
int stackOffset = _getStackOffset(trace);
//corresponding method count with the current stack may exceeds the stack trace. Trims the count
if (methodCount + stackOffset > trace.length) {
methodCount = trace.length - stackOffset - 1;
}
String level = " ";
StringBuilder builder = new StringBuilder();
for (int i = methodCount; i > 0; i--) {
int stackIndex = i + stackOffset;
if (stackIndex >= trace.length) {
continue;
}
builder.append("\n")
.append(level)
.append(_getSimpleClassName(trace[stackIndex].getClassName()))
.append(".")
.append(trace[stackIndex].getMethodName())
.append(" ")
.append("(")
.append(trace[stackIndex].getFileName())
.append(":")
.append(trace[stackIndex].getLineNumber())
.append(")");
level += " ";
}
return builder.toString();
} catch (Exception e) {
Log.w(debugTag, e);
return "";
}
}
/**
* Determines the starting index of the stack trace, after method calls made by this class.
*
* @param trace the stack trace
* @return the stack offset
*/
private static int _getStackOffset(StackTraceElement[] trace) {
for (int i = MIN_STACK_OFFSET; i < trace.length; i++) {
StackTraceElement e = trace[i];
String name = e.getClassName();
if (!name.equals(LogUtils.class.getName())) {
return --i;
}
}
return -1;
}
private static String _getSimpleClassName(String name) {
int lastIndex = name.lastIndexOf(".");
return name.substring(lastIndex + 1);
}
}
@@ -0,0 +1,152 @@
/*
* Copyright (C) 2014 nohana, Inc.
* Copyright 2017 Zhihu Inc.
*
* 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 &quot;AS IS&quot; 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.zlylib.fileselectorlib.utils;
import android.content.ContentResolver;
import android.net.Uri;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import androidx.collection.ArraySet;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
/**
* MIME Type enumeration to restrict selectable media on the selection activity. Matisse only supports images and
* videos.
* <p>
* Good example of mime types Android supports:
* https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/MediaFile.java
*/
@SuppressWarnings("unused")
public enum MimeType {
// ============== images ==============
JPEG("image/jpeg", arraySetOf(
"jpg",
"jpeg"
)),
PNG("image/png", arraySetOf(
"png"
)),
GIF("image/gif", arraySetOf(
"gif"
)),
BMP("image/x-ms-bmp", arraySetOf(
"bmp"
)),
WEBP("image/webp", arraySetOf(
"webp"
)),
// ============== videos ==============
MPEG("video/mpeg", arraySetOf(
"mpeg",
"mpg"
)),
MP4("video/mp4", arraySetOf(
"mp4",
"m4v"
)),
QUICKTIME("video/quicktime", arraySetOf(
"mov"
)),
THREEGPP("video/3gpp", arraySetOf(
"3gp",
"3gpp"
)),
THREEGPP2("video/3gpp2", arraySetOf(
"3g2",
"3gpp2"
)),
MKV("video/x-matroska", arraySetOf(
"mkv"
)),
WEBM("video/webm", arraySetOf(
"webm"
)),
TS("video/mp2ts", arraySetOf(
"ts"
)),
AVI("video/avi", arraySetOf(
"avi"
));
private final String mMimeTypeName;
private final Set<String> mExtensions;
MimeType(String mimeTypeName, Set<String> extensions) {
mMimeTypeName = mimeTypeName;
mExtensions = extensions;
}
public static Set<MimeType> ofAll() {
return EnumSet.allOf(MimeType.class);
}
public static Set<MimeType> of(MimeType type, MimeType... rest) {
return EnumSet.of(type, rest);
}
public static Set<MimeType> ofImage() {
return EnumSet.of(JPEG, PNG, GIF, BMP, WEBP);
}
public static Set<MimeType> ofVideo() {
return EnumSet.of(MPEG, MP4, QUICKTIME, THREEGPP, THREEGPP2, MKV, WEBM, TS, AVI);
}
private static Set<String> arraySetOf(String... suffixes) {
return new ArraySet<>(Arrays.asList(suffixes));
}
@Override
public String toString() {
return mMimeTypeName;
}
public boolean checkType(ContentResolver resolver, Uri uri) {
MimeTypeMap map = MimeTypeMap.getSingleton();
if (uri == null) {
return false;
}
String type = map.getExtensionFromMimeType(resolver.getType(uri));
String path = null;
// lazy load the path and prevent resolve for multiple times
boolean pathParsed = false;
for (String extension : mExtensions) {
if (extension.equals(type)) {
return true;
}
if (!pathParsed) {
// we only resolve the path for one time
path = PhotoMetadataUtils.getPath(resolver, uri);
if (!TextUtils.isEmpty(path)) {
path = path.toLowerCase(Locale.US);
}
pathParsed = true;
}
if (path != null && path.endsWith(extension)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,135 @@
package com.zlylib.fileselectorlib.utils;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
/**
* http://stackoverflow.com/a/27271131/4739220
*/
public class PathUtils {
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if (Platform.hasKitKat() && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
} else if (isDownloadsDocument(uri)) { // DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) { // MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general)
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) { // File
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int columnIndex = cursor.getColumnIndexOrThrow(column);
return cursor.getString(columnIndex);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2014 nohana, Inc.
* Copyright 2017 Zhihu Inc.
*
* 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 &quot;AS IS&quot; 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.zlylib.fileselectorlib.utils;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.net.Uri;
import android.provider.MediaStore;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
public final class PhotoMetadataUtils {
private static final String TAG = PhotoMetadataUtils.class.getSimpleName();
private static final int MAX_WIDTH = 1600;
private static final String SCHEME_CONTENT = "content";
private PhotoMetadataUtils() {
throw new AssertionError("oops! the utility class is about to be instantiated...");
}
public static int getPixelsCount(ContentResolver resolver, Uri uri) {
Point size = getBitmapBound(resolver, uri);
return size.x * size.y;
}
public static Point getBitmapBound(ContentResolver resolver, Uri uri) {
InputStream is = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
is = resolver.openInputStream(uri);
BitmapFactory.decodeStream(is, null, options);
int width = options.outWidth;
int height = options.outHeight;
return new Point(width, height);
} catch (FileNotFoundException e) {
return new Point(0, 0);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String getPath(ContentResolver resolver, Uri uri) {
if (uri == null) {
return null;
}
if (SCHEME_CONTENT.equals(uri.getScheme())) {
Cursor cursor = null;
try {
cursor = resolver.query(uri, new String[]{MediaStore.Images.ImageColumns.DATA},
null, null, null);
if (cursor == null || !cursor.moveToFirst()) {
return null;
}
return cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));
} finally {
if (cursor != null) {
cursor.close();
}
}
}
return uri.getPath();
}
public static float getSizeInMB(long sizeInBytes) {
return Float.valueOf(new DecimalFormat("0.0").format((float) sizeInBytes / 1024 / 1024));
}
}
@@ -0,0 +1,16 @@
package com.zlylib.fileselectorlib.utils;
import android.os.Build;
/**
* @author JoongWon Baik
*/
public class Platform {
public static boolean hasICS() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}
public static boolean hasKitKat() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#D3DFDE"/>
</shape>
</item>
<item
android:bottom="1px">
<shape>
<solid android:color="#FFFFFF"/>
</shape>
</item>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.zlylib.titlebarlib.ActionBarCommon
android:id="@+id/abc"
style="@style/ActionBar.Common"
app:ab_immersion="immersed"
app:ab_statusBarVisible="auto"
app:abc_leftIconRes="@drawable/ic_back"
app:abc_rightTextPaddingLeft="0dp"
app:abc_rightTextPaddingRight="15dp"
app:abc_rightText="选择"
app:abc_titleText="文件选择" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="33dp"
android:background="@color/Grey200"
android:orientation="horizontal">
<ImageView
android:id="@+id/imb_select_sdcard"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:rotation="90"
android:scaleType="centerInside"
android:src="@mipmap/ic_chevron_right_white_24dp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/breadcrumbs_view"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:paddingRight="10dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_file_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:background="@android:color/transparent"
android:paddingLeft="10dp"
>
<Button
android:id="@+id/btn_bread"
android:minWidth="36dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:elevation="0dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/Grey700" />
<ImageButton
android:id="@+id/imb_bread"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@mipmap/ic_chevron_right_white_24dp"
android:tint="@color/Grey500"
android:background="?android:attr/selectableItemBackground"
/>
</LinearLayout>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<TextView
android:id="@+id/tv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp"
android:text="无数据"
android:layout_below="@id/iv_empty"
android:textColor="@color/Grey500"
android:textSize="18sp"/>
<ImageView
android:layout_centerHorizontal="true"
android:id="@+id/iv_empty"
android:layout_width="120dp"
android:layout_height="120dp"
android:gravity="center"
android:layout_centerInParent="true"
android:background="@mipmap/lfile_emptyimg"/>
</RelativeLayout>
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:background="#fff"
>
<ImageView
android:id="@+id/iv_item_file_select_left"
android:layout_width="36dp"
android:layout_height="42dp"
android:src="@mipmap/apk" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="15dp"
android:paddingRight="10dp"
android:gravity="center_vertical"
android:background="@drawable/bg_bottom_line_gray"
>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/tv_item_file_list"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:gravity="center_vertical"
android:maxLines="1"
android:ellipsize="end"
android:text="风控.apk"
android:textColor="#333"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_item_file_list_desc"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:maxLines="1"
android:gravity="center_vertical"
android:ellipsize="end"
android:text="文件: 文件夹:"
android:textColor="@android:color/darker_gray"
android:textSize="12sp" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/checkbox_item_file_list"
android:checked="true"
android:enabled="false"
android:layout_width="32dp"
android:layout_height="32dp"
android:clickable="true"
/>
<ImageView
android:id="@+id/iv_item_file_select_right"
android:layout_width="16dp"
android:layout_height="wrap_content"
android:src="@mipmap/right"
/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@drawable/bg_bottom_line_gray"
android:textAppearance="?android:attr/textAppearanceSmallPopupMenu"
android:layout_marginLeft="15dp"
android:id="@+id/tv_item_select_sdcard"
android:gravity="center_vertical"
android:layout_height="54dp"
/>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rcv_pop_select_sdcard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff" />
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/browser_select_count"
android:orderInCategory="100"
android:title="选中(0)"
app:showAsAction="always"/>
</menu>
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="transparent">#00000000</color>
<color name="white">#FFFFFF</color>
<color name="Grey50">#FAFAFA</color>
<color name="Grey100">#F5F5F5</color>
<color name="Grey200">#EEEEEE</color>
<color name="Grey300">#E0E0E0</color>
<color name="Grey400">#bdbdbd</color>
<color name="Grey500">#9e9e9e</color>
<color name="Grey600">#757575</color>
<color name="Grey700">#616161</color>
<color name="Grey800">#3D3D3D</color>
<color name="Grey900">#212121</color>
<color name="black">#000000</color>
<color name="titlebg">#6200EE</color>
</resources>
@@ -0,0 +1,6 @@
<resources>
<string name="app_name" translatable="false">zly</string>
<string name="folder_desc" translatable="false">文件:%1$s&#160;&#160;|&#160;&#160;文件夹:%2$s</string>
<string name="file_desc" translatable="false">%1$s&#160;&#160;|&#160;&#160;%2$s</string>
<string name="selected_file_count" translatable="false">选中(%1$s/%2$s)</string>
</resources>
@@ -0,0 +1,23 @@
<resources>
<style name="ActionBar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">?attr/colorPrimary</item>
<item name="ab_bottomLineHeight">0dp</item>
<item name="ab_statusBarColor">@color/transparent</item>
<item name="ab_titleBarHeight">48dp</item>
</style>
<style name="ActionBar.Common">
<item name="abc_titleTextColor">@color/white</item>
<item name="abc_titleTextSize">18dp</item>
<item name="abc_leftIconColor">@color/white</item>
<item name="abc_leftIconPadding">13dp</item>
<item name="abc_leftIconMarginLeft">3dp</item>
<item name="abc_leftTextColor">@color/white</item>
<item name="abc_rightIconColor">@color/white</item>
<item name="abc_rightIconPadding">13dp</item>
<item name="abc_rightIconMarginRight">3dp</item>
<item name="abc_rightTextColor">@color/white</item>
</style>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
@@ -0,0 +1,17 @@
package com.zlylib.fileselectorlib;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
+1
View File
@@ -9,3 +9,4 @@ include ':locallib_quick_android:quick_android_mvp'
include ':locallib_quick_android:quick_android_qrcode' include ':locallib_quick_android:quick_android_qrcode'
include ':locallib_quick_android:quick_android_rx_permission' include ':locallib_quick_android:quick_android_rx_permission'
include ':locallib_quick_android:quick_android_webview' include ':locallib_quick_android:quick_android_webview'
include ':fileselectorlib'