diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java index 1e1ca043..3d8ab2f0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java @@ -15,11 +15,13 @@ */ package com.arialyy.aria.core.download.downloader; -import com.arialyy.aria.core.common.ftp.AbsFtpInfoThread; import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.OnFileInfoCallback; +import com.arialyy.aria.core.common.ftp.AbsFtpInfoThread; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.util.CommonUtil; +import org.apache.commons.net.ftp.FTPFile; /** * Created by Aria.Lao on 2017/7/25. @@ -31,6 +33,14 @@ class FtpFileInfoThread extends AbsFtpInfoThread dirs = FileUtil.getSDPathList(AriaManager.APP); + if (dirs == null || dirs.isEmpty()) { + return true; + } + for (String path : dirs) { + if (filePath.contains(path)) { + if (fileSize > 0 && fileSize > getAvailableExternalMemorySize(path)) { + return false; + } + } + } + return true; + } + + /** + * sdcard 可用大小 + * + * @param sdcardPath sdcard 根路径 + * @return 单位为:byte + */ + public static long getAvailableExternalMemorySize(String sdcardPath) { + StatFs stat = new StatFs(sdcardPath); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return availableBlocks * blockSize; + } + + /** + * sdcard 总大小 + * + * @param sdcardPath sdcard 根路径 + * @return 单位为:byte + */ + public static long getTotalExternalMemorySize(String sdcardPath) { + StatFs stat = new StatFs(sdcardPath); + long blockSize = stat.getBlockSize(); + long totalBlocks = stat.getBlockCount(); + return totalBlocks * blockSize; + } + /** * 获取某包下所有类 * diff --git a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java index 8732e99b..8fc0a22e 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java @@ -17,26 +17,43 @@ */ package com.arialyy.aria.util; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.os.Environment; +import android.text.TextUtils; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.SequenceInputStream; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Scanner; +import java.util.regex.Pattern; /** * 文件操作工具类 */ public class FileUtil { private static final String TAG = "FileUtil"; + private static final Pattern DIR_SEPORATOR = Pattern.compile("/"); + private static final String EXTERNAL_STORAGE_PATH = + Environment.getExternalStorageDirectory().getPath(); /** * 合并文件 @@ -148,4 +165,290 @@ public class FileUtil { e.printStackTrace(); } } + + /** + * 获取SD卡目录列表 + */ + public static List getSDPathList(Context context) { + List paths; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + paths = getVolumeList(context); + if (paths == null || paths.isEmpty()) { + paths = getStorageDirectories(); + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + paths = getVolumeList(context); + } else { + List mounts = readMountsFile(); + List volds = readVoldFile(); + paths = compareMountsWithVold(mounts, volds); + } + return paths; + } + + /** + * getSDPathList + */ + private static List getVolumeList(final Context context) { + List pathList = null; + try { + android.os.storage.StorageManager manager = + (android.os.storage.StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + Method method = manager.getClass().getMethod("getVolumePaths"); + String[] paths = (String[]) method.invoke(manager); + pathList = Arrays.asList(paths); + } catch (Exception e) { + e.printStackTrace(); + } + if (pathList == null || pathList.isEmpty()) { + pathList = new ArrayList<>(); + pathList.add(EXTERNAL_STORAGE_PATH); + } + LinkedHashMap paths = new LinkedHashMap<>(); + for (String path : pathList) { + File root = new File(path); + if (!root.exists() || !root.isDirectory() || !canWrite(path)) { + continue; + } + //去除mount的相同目录 + int key = (root.getTotalSpace() + "-" + root.getUsableSpace()).hashCode(); + String prevPath = paths.get(key); + if (!TextUtils.isEmpty(prevPath) && prevPath.length() < path.length()) { + continue; + } + paths.put(key, path); + } + List list = new ArrayList<>(); + for (Integer key : paths.keySet()) { + list.add(paths.get(key)); + } + return list; + } + + private static boolean canWrite(String dirPath) { + File dir = new File(dirPath); + if (dir.canWrite()) { + return true; + } + boolean canWrite; + File testWriteFile = null; + try { + testWriteFile = new File(dirPath, "tw.txt"); + if (testWriteFile.exists()) { + testWriteFile.delete(); + } + testWriteFile.createNewFile(); + FileWriter writer = new FileWriter(testWriteFile); + writer.write(1); + writer.close(); + canWrite = true; + } catch (Exception e) { + e.printStackTrace(); + canWrite = false; + } finally { + try { + if (testWriteFile != null && testWriteFile.exists()) { + testWriteFile.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return canWrite; + } + + /** + * Raturns all available SD-Cards in the system (include emulated) Warning: Hack! Based on Android source code of version 4.3 + * (API 18) Because there is no standard way to get it. TODO: Test on future Android versions 4.2+ + * + * @return paths to all available SD-Cards in the system (include emulated) + */ + public static List getStorageDirectories() { + // Final set of paths + final List rv = new ArrayList<>(); + // Primary physical SD-CARD (not emulated) + final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE"); + // All Secondary SD-CARDs (all exclude primary) separated by ":" + final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE"); + // Primary emulated SD-CARD + final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET"); + if (TextUtils.isEmpty(rawEmulatedStorageTarget)) { + // Device has physical external storage; use plain paths. + if (TextUtils.isEmpty(rawExternalStorage)) { + // EXTERNAL_STORAGE undefined; falling back to default. + rv.add("/storage/sdcard0"); + } else { + rv.add(rawExternalStorage); + } + } else { + // Device has emulated storage; external storage paths should have + // userId burned into them. + final String rawUserId; + + //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + final String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + final String[] folders = DIR_SEPORATOR.split(path); + final String lastFolder = folders[folders.length - 1]; + boolean isDigit = false; + if (!TextUtils.isEmpty(lastFolder) && TextUtils.isDigitsOnly(lastFolder)) { + isDigit = true; + } + rawUserId = isDigit ? lastFolder : ""; + //} else { + // rawUserId = ""; + //} + // /storage/emulated/0[1,2,...] + if (TextUtils.isEmpty(rawUserId)) { + rv.add(rawExternalStorage); + } else { + rv.add(rawEmulatedStorageTarget + File.separator + rawUserId); + } + } + // Add all secondary storages + if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) { + // All Secondary SD-CARDs splited into array + final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator); + Collections.addAll(rv, rawSecondaryStorages); + } + // checkout SD-CARDs writable + for (int i = rv.size() - 1; i >= 0; i--) { + String path = rv.get(i); + File root = new File(path); + if (!root.exists() || !root.isDirectory() || !canWrite(path)) { + rv.remove(i); + } + } + return rv; + } + + /** + * Scan the /proc/mounts file and look for lines like this: /dev/block/vold/179:1 /mnt/sdcard vfat + * rw,dirsync,nosuid,nodev,noexec ,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020, + * codepage=cp437,iocharset= iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 When one is found, split it into its + * elements and then pull out the path to the that mount point and add it to the arraylist + */ + private static List readMountsFile() { + // some mount files don't list the default + // path first, so we add it here to + // ensure that it is first in our list + List mounts = new ArrayList<>(); + mounts.add(EXTERNAL_STORAGE_PATH); + try { + Scanner scanner = new Scanner(new File("/proc/mounts")); + while (scanner.hasNext()) { + String line = scanner.nextLine(); + if (line.startsWith("/dev/block/vold/") || line.startsWith("/dev/block//vold/")) {// + String[] lineElements = line.split(" "); + // String partition = lineElements[0]; + String element = lineElements[1]; + // don't add the default mount path + // it's already in the list. + if (!element.equals(EXTERNAL_STORAGE_PATH)) { + mounts.add(element); + } + } + } + scanner.close(); + } catch (Exception e) { + // e.printStackTrace(); + } + return mounts; + } + + private static List readVoldFile() { + // read /etc/vold.conf or /etc/vold.fstab (it depends on version what + // config file is present) + List vold = null; + Scanner scanner = null; + try { + try { + scanner = new Scanner(new File("/system/etc/vold.fstab")); + } catch (FileNotFoundException e1) { + // e1.printStackTrace(); + scanner = new Scanner(new File("/system/etc/vold.conf")); + } + vold = new ArrayList(); + vold.add(EXTERNAL_STORAGE_PATH); + while (scanner.hasNext()) { + String line = scanner.nextLine(); + if (TextUtils.isEmpty(line)) { + continue; + } + line = line.trim(); + if (line.startsWith("dev_mount")) { + String[] lineElements = line.split(" "); + if (lineElements.length < 3) { + continue; + } + String element = lineElements[2]; + if (element.contains(":")) { + element = element.substring(0, element.indexOf(":")); + } + // ignore default path + if (!element.equals(EXTERNAL_STORAGE_PATH)) { + vold.add(element); + } + } else if (line.startsWith("mount_point")) { + String element = line.replaceAll("mount_point", "").trim(); + if (!element.equals(EXTERNAL_STORAGE_PATH)) { + vold.add(element); + } + } + } + } catch (Exception e) { + // e.printStackTrace(); + } + return vold; + } + + private static List compareMountsWithVold(List mounts, List volds) { + /* + * 有时候这两个list中的数据并不相同,我们只需要取两个list的交集部分。 + */ + for (int i = mounts.size() - 1; i >= 0; i--) { + String mount = mounts.get(i); + File root = new File(mount); + // 判断目录是否存在并且可读 + if (!root.exists() || !root.isDirectory() || !root.canWrite()) { + mounts.remove(i); + continue; + } + if (volds != null && !volds.contains(mount)) { + mounts.remove(i); + } + } + // 清除无用数据 + if (volds != null) { + volds.clear(); + } + return mounts; + } + + public static long getTotalMemory() { + String file_path = "/proc/meminfo";// 系统内存信息文件 + String ram_info; + String[] arrayOfRam; + long initial_memory = 0L; + try { + FileReader fr = new FileReader(file_path); + BufferedReader localBufferedReader = new BufferedReader(fr, 8192); + // 读取meminfo第一行,系统总内存大小 + ram_info = localBufferedReader.readLine(); + arrayOfRam = ram_info.split("\\s+");// 实现多个空格切割的效果 + initial_memory = + Integer.valueOf(arrayOfRam[1]) * 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte + localBufferedReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return initial_memory; + } + + public static long getAvailMemory(Context context) { + ActivityManager activityManager = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); + activityManager.getMemoryInfo(memoryInfo); + return memoryInfo.availMem; + } } diff --git a/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java b/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java index 2df1eb6a..4dcc4cb8 100644 --- a/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java +++ b/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java @@ -21,14 +21,14 @@ public class AnyRunActivity extends BaseActivity { AnyRunnModule module; String[] urls; int index = 0; - //String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; + String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; //String URL = "http://58.213.157.242:8081/sims_file/rest/v1/file/mshd_touchscreen_ms/guideFile/41c33556-dc4a-4d78-bb76-b9f627f94448.mp4/%E5%85%AB%E5%8D%A6%E6%B4%B2%E5%8D%97%E4%BA%AC%E5%86%9C%E4%B8%9A%E5%98%89%E5%B9%B4%E5%8D%8E0511.mp4"; //String URL = "http://d1.showself.com/download/showself_android-s236279_release.apk"; //String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; //private final String URL = "ftp://192.168.29.140:21/download/AriaPrj.rar"; //String URL = "https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe"; //String URL = "ftp://192.168.29.140:21/download/SDK_Demo-release.apk"; - String URL = "ftps://192.168.29.140:990/download/SDK_Demo-release.apk"; + //String URL = "ftps://192.168.29.140:990/download/SDK_Demo-release.apk"; //String URL = "http://d.quanscreen.com/k/down/resourceDownLoad?resourceId=1994&clientId=A000011106034058176"; //String URL = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv"; //private String URL = "https://www.bilibili.com/bangumi/play/ep77693"; @@ -51,8 +51,8 @@ public class AnyRunActivity extends BaseActivity { public void onClick(View view) { switch (view.getId()) { case R.id.start: - //module.start(URL); - module.startFtp(URL); + module.start(URL); + //module.startFtp(URL); break; case R.id.stop: module.stop(URL); diff --git a/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java b/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java index 1af461d3..6ca15480 100644 --- a/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java +++ b/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java @@ -64,7 +64,7 @@ public class AnyRunnModule { void start(String url) { mUrl = url; - String path = Environment.getExternalStorageDirectory().getPath() + "/mmm.mp4"; + String path = Environment.getExternalStorageDirectory().getPath() + "/mmm1.mp4"; Aria.download(this) .load(url) .setRequestMode(RequestEnum.GET)