[
  {
    "path": "README.md",
    "content": "# Android常用开发工具类\n\n## 应用工具类  [ **`AbAppUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbAppUtil.java)\n* 读取application 节点  meta-data 信息`readMetaDataFromApplication`\n* 打开并安装文件 `installApk`\n* 卸载程序 `uninstallApk`\n* 用来判断服务是否运行 `isServiceRunning`\n* 停止服务  `stopRunningService`\n* 判断网络是否有效 `isNetworkAvailable`\n* Gps是否打开 `isGpsEnabled`\n* 判断当前网络是否是移动数据网络 `isMobile`\n* 导入数据库 `importDatabase`\n* 获取屏幕尺寸与密度 `getDisplayMetrics`\n* 打开键盘 `showSoftInput`\n* 关闭键盘事件 `closeSoftInput`\n* 获取包信息 `getPackageInfo`\n* 获取当前版本号 `getVersionName`\n* 获取开发版本号 `getVersionCode`\n* 是否存在该包名的应用 `exitAppBy`\n\n\n## 日期处理类  [**`AbDateUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbDateUtil.java)\n* String类型的日期时间转化为Date类型 `getDateByFormat`\n* 获取偏移之后的Date `getDateByOffset`\n* 获取指定日期时间的字符串(可偏移) `getStringByOffset`\n* Date类型转化为String类型(可偏移) `getStringByOffset`\n* Date类型转化为String类型 `getStringByFormat`\n* 获取指定日期时间的字符串,用于导出想要的格式 `getStringByFormat`\n* 获取milliseconds表示的日期时间的字符串 `getStringByFormat`\n* 获取表示当前日期时间的字符串 `getCurrentDate`\n* 获取表示当前日期时间的字符串(可偏移) `getCurrentDateByOffset`\n* 计算两个日期所差的天数 `getOffectDay`\n* 计算两个日期所差的小时数 `getOffectHour`\n* 计算两个日期所差的分钟数 `getOffectMinutes`\n* 获取本周一 `getFirstDayOfWeek`\n* 获取本周日 `getLastDayOfWeek`\n* 获取本周的某一天 `getDayOfWeek`\n* 获取本月第一天 `getFirstDayOfMonth`\n* 获取本月最后一天 `getLastDayOfMonth`\n* 获取表示当前日期的0点时间毫秒数 `getFirstTimeOfDay`\n* 获取表示当前日期24点时间毫秒数 `getLastTimeOfDay`\n* 判断是否是闰年 `isLeapYear`\n* 根据时间返回格式化后的时间的描述. 小于1小时显示多少分钟前 大于1小时显示今天＋实际日期，大于今天全部显示实际时间`formatDateStr2Desc`\n* 取指定日期为星期几 `getWeekNumber`\n* 根据给定的日期判断是否为上下午 `getTimeQuantum`\n* 根据给定的毫秒数算得时间的描述 `getTimeDescription`\n* 解析时间按照小时：分：秒格式输出 `getTime`\n\n\n## 文件操作类 [**`AbFileUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbFileUtil.java)\n* 通过文件的网络地址从SD卡中读取图片，如果SD中没有则自动下载并保存 `getBitmapFromSD`\n* 通过文件的本地地址从SD卡读取图片 `getBitmapFromSD`\n* 通过文件的本地地址从SD卡读取图片 `getBitmapFromSD`\n* 将图片的byte[]写入本地文件 `getBitmapFromByte`\n* 根据URL从互连网获取图片 `getBitmapFromURL`\n* 获取src中的图片资源 `getBitmapFromSrc`\n* 获取Asset中的图片资源 `getBitmapFromAsset` `getDrawableFromAsset`\n* 下载网络文件到SD卡中.如果SD中存在同名文件将不再下载 `downloadFile`\n* 获取网络文件的大小 `getContentLengthFromUrl`\n* 获取文件名，通过网络获取 `getRealFileNameFromUrl`\n* 获取真实文件名（xx.后缀），通过网络获取 `getRealFileName`\n* 获取文件名（不含后缀） `getCacheFileNameFromUrl`\n* 获取文件名（.后缀），外链模式和通过网络获取 `getCacheFileNameFromUrl`\n* 获取文件后缀，本地 `getMIMEFromUrl`\n* 从sd卡中的文件读取到byte `getByteArrayFromSD`\n* 将byte数组写入文件 `writeByteArrayToSD`\n* SD卡是否能用 `isCanUseSD`\n* 计算sdcard上的剩余空间 `freeSpaceOnSD`\n* 根据文件的最后修改时间进行排序 `FileLastModifSort`\n* 删除所有缓存文件 `clearDownloadFile`\n* 读取Assets目录的文件内容 `readAssetsByName`\n* 读取Raw目录的文件内容 `readRawByName`\n* 解压缩功能. 将zipFile文件解压到folderPath目录下 `upZipFile`\n* 给定根目录，返回一个相对路径所对应的实际文件名.（压缩文件)  `getRealFileName`\n* 打开pdf文件 `openPdfFile`\n* 删除文件，可以是单个文件或文件夹 `delete`\n* 删除单个文件 `deleteFile`\n* 删除目录（文件夹）以及目录下的文件 `deleteDirectory`\n* 获取下载根目录 `getDownloadRootDir`\n* 获取图片下载根目录  `getImageDownloadDir`\n* 获取文件下载根目录`getFileDownloadDir`\n* 本地缓存的目录 `getCacheDownloadDir`\n* 本地数据库目录 `getDbDownloadDir`\n* 缓存中可用的大小 `getFreeSdSpaceNeededToCache`\n\n\n## 图形处理类 [**`AbGraphicUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbGraphicUtil.java)\n* 获取字符的所在位置（按像素获取最大能容纳的）`subStringLength`\n* 获取文字的像素宽 `getStringWidth`\n* 获得文字的宽度 `getDesiredWidth`\n* 获取文字的高度 `getDesiredHeight`\n* 字符解析成行 `getDrawRowStr`\n* 获取这段文本多少行 `getDrawRowCount`\n* 绘制文本，支持换行 `drawText`\n\n\n## 图片处理类 [**`AbImageUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbImageUtil.java)\n* 解析bitmap `getBitmapByte`\n* 直接获取互联网上的图片 `getBitmap`\n* 获取原图 `getBitmap`\n* 缩放图片.压缩 `scaleImg`\n* 缩放图片,不压缩的缩放\n* 裁剪图片 `cutImg`\n* Drawable转Bitmap `drawableToBitmap`\n* Bitmap对象转换Drawable对象. `bitmapToDrawable`\n* Bitmap对象转换TransitionDrawable对象 `bitmapToTransitionDrawable`\n* Drawable对象转换TransitionDrawable对象 `drawableToTransitionDrawable`\n* 将Bitmap转换为byte[] `bitmap2Bytes`\n* 获取Bitmap大小 `getByteCount`\n* 将byte[]转换为Bitmap `bytes2Bimap`\n* 将View转换为Drawable.需要最上层布局为Linearlayout `view2Drawable`\n* 将View转换为Bitmap.需要最上层布局为Linearlayout `view2Bitmap`\n* 将View转换为byte[] `view2Bytes`\n* 旋转Bitmap为一定的角度 `rotateBitmap`\n* 旋转Bitmap为一定的角度并四周暗化处理 `rotateBitmapTranslate`\n* 转换图片转换成圆形 `toRoundBitmap`\n* 转换图片转换成圆形通过指定的弧度 `toRoundBitmap`\n* 转换图片转换成镜面效果的图片 `toReflectionBitmap`\n* 释放Bitmap对象 `releaseBitmap`\n* 释放Bitmap数组 `releaseBitmapArray`\n* 简单的图像的特征值，用于缩略图找原图比较好 `getHashCode`\n* 图像的特征值颜色分布 将颜色分4个区，0,1,2,3 区组合共64组，计算每个像素点属于哪个区 `getColorHistogram`\n* 计算\"汉明距离\"（Hamming distance）`hammingDistance`\n* 灰度值计算 `rgbToGray`\n* 压缩图片 `compressBitmap`\n* 根据URI获取图片物理路径 `getAbsoluteImagePath`\n\n## 日志工具类 [**`AbLogUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbLogUtil.java)\n\n## 数学处理类 [**`AbMathUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbMathUtil.java)\n* 四舍五入  `round`\n* 字节数组转换成16进制串 `byte2HexStr`\n* 二进制转为十六进制 `binaryToHex`\n* 一维数组转为二维数组 `arrayToMatrix`\n* 二维数组转为一维数组 `matrixToArray`\n* int数组转换为double数组 `intToDoubleArray`\n* int二维数组转换为double二维数组. `intToDoubleMatrix`\n* 计算数组的平均值 `average`\n* 点在直线上 `pointAtSLine`\n* 点在线段上 `pointAtELine`\n* 两条直线相交 `LineAtLine`\n* 线段与线段相交 `eLineAtELine`\n* 点在矩形内 `pointAtRect`\n* 矩形在矩形内 `rectAtRect`\n* 圆心在矩形内 `circleAtRect`\n* 获取两点间的距离 `getDistance`\n* 矩形碰撞检测 参数为x,y,width,height `isRectCollision`\n\n\n## MD5加密 [**`AbMd5`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbMd5.java)\n* MD5加密 `MD5`\n\n\n## 保存到 SharedPreferences 的数据 [**`AbSharedUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbSharedUtil.java)\n\n## 字符串处理类 [**`AbStrUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbStrUtil.java)\n* 给填写搜索单词的关键词显示 特殊颜色 `changeTextColor`\n* 将null转化为“” `parseEmpty`\n* 判断一个字符串是否为null或空值 `isEmpty`\n* 集合是否为空 `isEmpty`\n* 获取字符串中文字符的长度（每个中文算2个字符） `chineseLength`\n* 获取字符串的长度 `strLength`\n* 获取指定长度的字符所在位置 `subStringLength`\n* 手机号格式验证 `isMobileNo`\n* 是否只是字母和数字 `isNumberLetter`\n* 是否只是数字 `isNumber`\n* 是否是邮箱 `isEmail`\n* 是否是中文 `isChinese`\n* 是否包含中文 `isContainChinese`\n* 是否包含中文数字字母的用户名 `isConintChinseUser`\n* 从输入流中获得String `convertStreamToString`\n* 标准化日期时间类型的数据，不足两位的补0 `dateTimeFormat`\n* 不足2个字符的在前面补“0” `strFormat2`\n* 截取字符串到指定字节长度 `cutString`\n* 截取字符串从第一个指定字符 `cutStringFromChar`\n* 获取字节长度 `strlen`\n* 获取大小的描述 `getSizeDesc`\n* ip地址转换为10进制数 `ip2int`\n\n## View工具类 [**`AbViewUtil`**](https://github.com/wzgiceman/ALibrary/blob/master/src/main/java/com/ab/util/AbViewUtil.java)\n* 测量这个view `measureView`\n* 获得这个View的宽度 `getViewWidth`\n* 获得这个View的高度 `getViewHeight`\n* 从父亲布局中移除自己 `removeSelfFromParent`\n* dip转换为px `dip2px`\n* px转换为dip `px2dip`\n* sp转换为px `sp2px`\n* px转换为sp `px2sp`\n* 根据屏幕大小缩放 `scale`\n* 根据屏幕大小缩放 `scale`\n* TypedValue官方源码中的算法，任意单位转换为PX单位 `applyDimension`\n* View树递归调用做适配 `scaleContentView`\n* 按比例缩放View，以布局中的尺寸为基准 `scaleView`\n* 缩放文字大小 `setSPTextSize`\n* 缩放文字大小,这样设置的好处是文字的大小不和密度有关 `setTextSize`\n* 缩放文字大小 `setTextSize`\n* 设置View的PX尺寸 `setViewSize`\n* 设置PX padding. `setPadding`\n* 设置 PX margin `setMargin`\n\n\n"
  },
  {
    "path": "abLibraryUtils.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":abLibraryUtils\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"DownProgressView\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"SELECTED_TEST_ARTIFACT\" value=\"_android_test_\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <afterSyncTasks>\n          <task>generateDebugSources</task>\n        </afterSyncTasks>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n        <option name=\"LIBRARY_PROJECT\" value=\"true\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" LANGUAGE_LEVEL=\"JDK_1_7\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <output-test url=\"file://$MODULE_DIR$/build/intermediates/classes/test/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/resValues/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/shaders\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/rs\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/testDebug/shaders\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/shaders\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/rs\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/shaders\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/shaders\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/blame\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental-safeguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jniLibs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/shaders\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/transforms\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"1.8\" jdkType=\"JavaSDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "build.gradle",
    "content": "apply plugin: 'com.android.library'\n\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.3\"\n\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "local.properties",
    "content": "## This file is automatically generated by Android Studio.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must *NOT* be checked into Version Control Systems,\n# as it contains information specific to your local configuration.\n#\n# Location of the SDK. This is only used by Gradle.\n# For customization when using a Version Control System, please read the\n# header note.\n#Tue Mar 01 14:22:54 CST 2016\nsdk.dir=E\\:\\\\Android+tool\\\\sdk\\\\sdk\n"
  },
  {
    "path": "src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.ab\"\n    android:versionCode=\"18\"\n    android:versionName=\"1.6\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"14\"\n        android:targetSdkVersion=\"17\" />\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n</manifest>"
  },
  {
    "path": "src/main/java/com/ab/global/AbAppConfig.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.global;\n\nimport java.io.File;\n\n// TODO: Auto-generated Javadoc\n/**\n * © 2012 amsoft.cn 名称：AbAppConfig.java 描述：初始设置类.\n *\n * @author 还如一梦中\n * @version v1.0 @date：2014-07-03 下午1:33:39\n */\npublic class AbAppConfig {\n\n\t/** UI设计的基准宽度. */\n\tpublic static int UI_WIDTH = 720;\n\n\t/** UI设计的基准高度. */\n\tpublic static int UI_HEIGHT = 1080;\n\n\t/** 默认 SharePreferences文件名. */\n\tpublic static String SHARED_PATH = \"app_share\";\n\n\t/** 默认下载文件地址. */\n\tpublic static String DOWNLOAD_ROOT_DIR = \"Android\" + File.separator + \"data\";\n\n\t/** 默认下载图片文件地址. */\n\tpublic static String DOWNLOAD_IMAGE_DIR = \"images\";\n\n\t/** 默认下载文件地址. */\n\tpublic static String DOWNLOAD_FILE_DIR = \"files\";\n\n\t/** APP缓存目录. */\n\tpublic static String CACHE_DIR = \"caches\";\n\n\t/** DB目录. */\n\tpublic static String DB_DIR = \"db\";\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbAppUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport android.app.Activity;\nimport android.app.ActivityManager;\nimport android.app.ActivityManager.RunningServiceInfo;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.location.LocationManager;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.util.DisplayMetrics;\nimport android.view.inputmethod.InputMethodManager;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\n/**\n * 描述：应用工具类.\n */\npublic class AbAppUtil {\n\n    /**\n     * 读取application 节点  meta-data 信息\n     */\n    public static String readMetaDataFromApplication(Context context, String key) {\n        try {\n            ApplicationInfo appInfo = context.getPackageManager()\n                    .getApplicationInfo(context.getPackageName(),\n                            PackageManager.GET_META_DATA);\n            return appInfo.metaData.getString(key);\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * 描述：打开并安装文件.\n     *\n     * @param context the context\n     * @param file    apk文件路径\n     */\n    public static void installApk(Context context, File file) {\n        Intent intent = new Intent();\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.setAction(android.content.Intent.ACTION_VIEW);\n        intent.setDataAndType(Uri.fromFile(file),\n                \"application/vnd.android.package-archive\");\n        context.startActivity(intent);\n    }\n\n    /**\n     * 描述：卸载程序.\n     *\n     * @param context     the context\n     * @param packageName 包名\n     */\n    public static void uninstallApk(Context context, String packageName) {\n        Intent intent = new Intent(Intent.ACTION_DELETE);\n        Uri packageURI = Uri.parse(\"package:\" + packageName);\n        intent.setData(packageURI);\n        context.startActivity(intent);\n    }\n\n\n    /**\n     * 用来判断服务是否运行.\n     *\n     * @param ctx       the ctx\n     * @param className 判断的服务名字 \"com.xxx.xx..XXXService\"\n     * @return true 在运行 false 不在运行\n     */\n    public static boolean isServiceRunning(Context ctx, String className) {\n        boolean isRunning = false;\n        ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);\n        List<RunningServiceInfo> servicesList = activityManager.getRunningServices(Integer.MAX_VALUE);\n        Iterator<RunningServiceInfo> l = servicesList.iterator();\n        while (l.hasNext()) {\n            RunningServiceInfo si = (RunningServiceInfo) l.next();\n            if (className.equals(si.service.getClassName())) {\n                isRunning = true;\n            }\n        }\n        return isRunning;\n    }\n\n    /**\n     * 停止服务.\n     *\n     * @param ctx       the ctx\n     * @param className the class name\n     * @return true, if successful\n     */\n    public static boolean stopRunningService(Context ctx, String className) {\n        Intent intent_service = null;\n        boolean ret = false;\n        try {\n            intent_service = new Intent(ctx, Class.forName(className));\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        if (intent_service != null) {\n            ret = ctx.stopService(intent_service);\n        }\n        return ret;\n    }\n\n\n    /**\n     * Gets the number of cores available in this device, across all processors.\n     * Requires: Ability to peruse the filesystem at \"/sys/devices/system/cpu\"\n     *\n     * @return The number of cores, or 1 if failed to get result\n     */\n    public static int getNumCores() {\n        try {\n            //Get directory containing CPU info\n            File dir = new File(\"/sys/devices/system/cpu/\");\n            //Filter to only list the devices we care about\n            File[] files = dir.listFiles(new FileFilter() {\n\n                @Override\n                public boolean accept(File pathname) {\n                    //Check if filename is \"cpu\", followed by a single digit number\n                    if (Pattern.matches(\"cpu[0-9]\", pathname.getName())) {\n                        return true;\n                    }\n                    return false;\n                }\n\n            });\n            //Return the number of cores (virtual CPU devices)\n            return files.length;\n        } catch (Exception e) {\n            //Default to return 1 core\n            return 1;\n        }\n    }\n\n\n    /**\n     * 描述：判断网络是否有效.\n     *\n     * @param context the context\n     * @return true, if is network available\n     */\n    public static boolean isNetworkAvailable(Context context) {\n        try {\n            ConnectivityManager connectivity = (ConnectivityManager) context\n                    .getSystemService(Context.CONNECTIVITY_SERVICE);\n            if (connectivity != null) {\n                NetworkInfo info = connectivity.getActiveNetworkInfo();\n                if (info != null && info.isConnected()) {\n                    if (info.getState() == NetworkInfo.State.CONNECTED) {\n                        return true;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return false;\n        }\n        return false;\n    }\n\n    /**\n     * Gps是否打开\n     * 需要<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />权限\n     *\n     * @param context the context\n     * @return true, if is gps enabled\n     */\n    public static boolean isGpsEnabled(Context context) {\n        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);\n        return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);\n    }\n\n\n    /**\n     * 判断当前网络是否是移动数据网络.\n     *\n     * @param context the context\n     * @return boolean\n     */\n    public static boolean isMobile(Context context) {\n        ConnectivityManager connectivityManager = (ConnectivityManager) context\n                .getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();\n        if (activeNetInfo != null\n                && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 导入数据库.\n     *\n     * @param context the context\n     * @param dbName  the db name\n     * @param rawRes  the raw res\n     * @return true, if successful\n     */\n    public static boolean importDatabase(Context context, String dbName, int rawRes) {\n        int buffer_size = 1024;\n        InputStream is = null;\n        FileOutputStream fos = null;\n        boolean flag = false;\n\n        try {\n            String dbPath = \"/data/data/\" + context.getPackageName() + \"/databases/\" + dbName;\n            File dbfile = new File(dbPath);\n            //判断数据库文件是否存在，若不存在则执行导入，否则直接打开数据库\n            if (!dbfile.exists()) {\n                //欲导入的数据库\n                if (!dbfile.getParentFile().exists()) {\n                    dbfile.getParentFile().mkdirs();\n                }\n                dbfile.createNewFile();\n                is = context.getResources().openRawResource(rawRes);\n                fos = new FileOutputStream(dbfile);\n                byte[] buffer = new byte[buffer_size];\n                int count = 0;\n                while ((count = is.read(buffer)) > 0) {\n                    fos.write(buffer, 0, count);\n                }\n                fos.flush();\n            }\n            flag = true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                } catch (Exception e) {\n                }\n            }\n            if (is != null) {\n                try {\n                    is.close();\n                } catch (Exception e) {\n                }\n            }\n        }\n        return flag;\n    }\n\n    /**\n     * 获取屏幕尺寸与密度.\n     *\n     * @param context the context\n     * @return mDisplayMetrics\n     */\n    public static DisplayMetrics getDisplayMetrics(Context context) {\n        Resources mResources;\n        if (context == null) {\n            mResources = Resources.getSystem();\n\n        } else {\n            mResources = context.getResources();\n        }\n        //DisplayMetrics{density=1.5, width=480, height=854, scaledDensity=1.5, xdpi=160.421, ydpi=159.497}\n        //DisplayMetrics{density=2.0, width=720, height=1280, scaledDensity=2.0, xdpi=160.42105, ydpi=160.15764}\n        DisplayMetrics mDisplayMetrics = mResources.getDisplayMetrics();\n        return mDisplayMetrics;\n    }\n\n    /**\n     * 打开键盘.\n     *\n     * @param context the context\n     */\n    public static void showSoftInput(Context context) {\n        InputMethodManager inputMethodManager = (InputMethodManager) context\n                .getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 关闭键盘事件.\n     *\n     * @param context the context\n     */\n    public static void closeSoftInput(Context context) {\n        InputMethodManager inputMethodManager = (InputMethodManager) context\n                .getSystemService(Context.INPUT_METHOD_SERVICE);\n        if (inputMethodManager != null && ((Activity) context).getCurrentFocus() != null) {\n            inputMethodManager.hideSoftInputFromWindow(((Activity) context).getCurrentFocus()\n                    .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);\n        }\n    }\n\n    /**\n     * 获取包信息.\n     *\n     * @param context the context\n     */\n    public static PackageInfo getPackageInfo(Context context) {\n        PackageInfo info = null;\n        try {\n            String packageName = context.getPackageName();\n            info = context.getPackageManager().getPackageInfo(packageName, 0);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return info;\n    }\n\n    /**\n     * 获取当前版本号\n     *\n     * @return\n     * @throws Exception\n     */\n    public static String getVersionName(Context context) {\n        StringBuilder builder = new StringBuilder(\"v\");\n        try {\n            PackageInfo packInfo = getPackageInfo(context);\n            builder.append(packInfo.versionName);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return builder.toString();\n    }\n\n    /**\n     * 获取开发版本号\n     *\n     * @param context\n     * @return\n     */\n    public static String getVersionCode(Context context) {\n        StringBuilder builder = new StringBuilder();\n        try {\n            PackageInfo packInfo = getPackageInfo(context);\n            builder.append(packInfo.versionCode);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return builder.toString();\n    }\n\n\n    /**\n     * 是否存在该包名的应用\n     *\n     * @param context\n     * @return\n     */\n    public static boolean exitAppBy(Context context, String packageName) {\n        final PackageManager packageManager = context.getPackageManager();// 获取packagemanager\n        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息\n        if (pinfo != null) {\n            for (int i = 0; i < pinfo.size(); i++) {\n                String pn = pinfo.get(i).packageName;\n                if (pn.equals(packageName)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbDateUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn 名称：AbDateUtil.java 描述：日期处理类.\n *\n */\npublic class AbDateUtil {\n\n\t/** 时间日期格式化到年月日时分秒. */\n\tpublic static final String dateFormatYMDHMS = \"yyyy-MM-dd HH:mm:ss\";\n\n\t/** 时间日期格式化到年月日. */\n\tpublic static final String dateFormatYMD = \"yyyy-MM-dd\";\n\n\t/** 时间日期格式化到年月. */\n\tpublic static final String dateFormatYM = \"yyyy-MM\";\n\n\t/** 时间日期格式化到年月日时分. */\n\tpublic static final String dateFormatYMDHM = \"yyyy-MM-dd HH:mm\";\n\n\t/** 时间日期格式化到月日. */\n\tpublic static final String dateFormatMD = \"MM/dd\";\n\n\t/** 时分秒. */\n\tpublic static final String dateFormatHMS = \"HH:mm:ss\";\n\n\t/** 时分. */\n\tpublic static final String dateFormatHM = \"HH:mm\";\n\n\t/** 上午. */\n\tpublic static final String AM = \"AM\";\n\n\t/** 下午. */\n\tpublic static final String PM = \"PM\";\n\n\t/**\n\t * 描述：String类型的日期时间转化为Date类型.\n\t *\n\t * @param strDate\n\t *            String形式的日期时间\n\t * @param format\n\t *            格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @return Date Date类型日期时间\n\t */\n\tpublic static Date getDateByFormat(String strDate, String format) {\n\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\tDate date = null;\n\t\ttry {\n\t\t\tdate = mSimpleDateFormat.parse(strDate);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn date;\n\t}\n\n\t/**\n\t * 描述：获取偏移之后的Date.\n\t * \n\t * @param date\n\t *            日期时间\n\t * @param calendarField\n\t *            Calendar属性，对应offset的值，\n\t *            如(Calendar.DATE,表示+offset天,Calendar.HOUR_OF_DAY,表示＋offset小时)\n\t * @param offset\n\t *            偏移(值大于0,表示+,值小于0,表示－)\n\t * @return Date 偏移之后的日期时间\n\t */\n\tpublic Date getDateByOffset(Date date, int calendarField, int offset) {\n\t\tCalendar c = new GregorianCalendar();\n\t\ttry {\n\t\t\tc.setTime(date);\n\t\t\tc.add(calendarField, offset);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn c.getTime();\n\t}\n\n\t/**\n\t * 描述：获取指定日期时间的字符串(可偏移).\n\t *\n\t * @param strDate\n\t *            String形式的日期时间\n\t * @param format\n\t *            格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @param calendarField\n\t *            Calendar属性，对应offset的值，\n\t *            如(Calendar.DATE,表示+offset天,Calendar.HOUR_OF_DAY,表示＋offset小时)\n\t * @param offset\n\t *            偏移(值大于0,表示+,值小于0,表示－)\n\t * @return String String类型的日期时间\n\t */\n\tpublic static String getStringByOffset(String strDate, String format, int calendarField, int offset) {\n\t\tString mDateTime = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tc.setTime(mSimpleDateFormat.parse(strDate));\n\t\t\tc.add(calendarField, offset);\n\t\t\tmDateTime = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mDateTime;\n\t}\n\n\t/**\n\t * 描述：Date类型转化为String类型(可偏移).\n\t *\n\t * @param date\n\t *            the date\n\t * @param format\n\t *            the format\n\t * @param calendarField\n\t *            the calendar field\n\t * @param offset\n\t *            the offset\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getStringByOffset(Date date, String format, int calendarField, int offset) {\n\t\tString strDate = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tc.setTime(date);\n\t\t\tc.add(calendarField, offset);\n\t\t\tstrDate = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn strDate;\n\t}\n\n\t/**\n\t * 描述：Date类型转化为String类型.\n\t *\n\t * @param date\n\t *            the date\n\t * @param format\n\t *            the format\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getStringByFormat(Date date, String format) {\n\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\tString strDate = null;\n\t\ttry {\n\t\t\tstrDate = mSimpleDateFormat.format(date);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn strDate;\n\t}\n\n\t/**\n\t * 描述：获取指定日期时间的字符串,用于导出想要的格式.\n\t *\n\t * @param strDate\n\t *            String形式的日期时间，必须为yyyy-MM-dd HH:mm:ss格式\n\t * @param format\n\t *            输出格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @return String 转换后的String类型的日期时间\n\t */\n\tpublic static String getStringByFormat(String strDate, String format) {\n\t\tString mDateTime = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(dateFormatYMDHMS);\n\t\t\tc.setTime(mSimpleDateFormat.parse(strDate));\n\t\t\tSimpleDateFormat mSimpleDateFormat2 = new SimpleDateFormat(format);\n\t\t\tmDateTime = mSimpleDateFormat2.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mDateTime;\n\t}\n\n\t/**\n\t * 描述：获取milliseconds表示的日期时间的字符串.\n\t *\n\t * @param milliseconds\n\t *            the milliseconds\n\t * @param format\n\t *            格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @return String 日期时间字符串\n\t */\n\tpublic static String getStringByFormat(long milliseconds, String format) {\n\t\tString thisDateTime = null;\n\t\ttry {\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tthisDateTime = mSimpleDateFormat.format(milliseconds);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn thisDateTime;\n\t}\n\n\t/**\n\t * 描述：获取表示当前日期时间的字符串.\n\t *\n\t * @param format\n\t *            格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @return String String类型的当前日期时间\n\t */\n\tpublic static String getCurrentDate(String format) {\n\t\tAbLogUtil.d(AbDateUtil.class, \"getCurrentDate:\" + format);\n\t\tString curDateTime = null;\n\t\ttry {\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tcurDateTime = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn curDateTime;\n\n\t}\n\n\t/**\n\t * 描述：获取表示当前日期时间的字符串(可偏移).\n\t *\n\t * @param format\n\t *            格式化字符串，如：\"yyyy-MM-dd HH:mm:ss\"\n\t * @param calendarField\n\t *            Calendar属性，对应offset的值，\n\t *            如(Calendar.DATE,表示+offset天,Calendar.HOUR_OF_DAY,表示＋offset小时)\n\t * @param offset\n\t *            偏移(值大于0,表示+,值小于0,表示－)\n\t * @return String String类型的日期时间\n\t */\n\tpublic static String getCurrentDateByOffset(String format, int calendarField, int offset) {\n\t\tString mDateTime = null;\n\t\ttry {\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tc.add(calendarField, offset);\n\t\t\tmDateTime = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mDateTime;\n\n\t}\n\n\t/**\n\t * 描述：计算两个日期所差的天数.\n\t *\n\t * @param milliseconds1\n\t *            the milliseconds1\n\t * @param milliseconds2\n\t *            the milliseconds2\n\t * @return int 所差的天数\n\t */\n\tpublic static int getOffectDay(long milliseconds1, long milliseconds2) {\n\t\tCalendar calendar1 = Calendar.getInstance();\n\t\tcalendar1.setTimeInMillis(milliseconds1);\n\t\tCalendar calendar2 = Calendar.getInstance();\n\t\tcalendar2.setTimeInMillis(milliseconds2);\n\t\t// 先判断是否同年\n\t\tint y1 = calendar1.get(Calendar.YEAR);\n\t\tint y2 = calendar2.get(Calendar.YEAR);\n\t\tint d1 = calendar1.get(Calendar.DAY_OF_YEAR);\n\t\tint d2 = calendar2.get(Calendar.DAY_OF_YEAR);\n\t\tint maxDays = 0;\n\t\tint day = 0;\n\t\tif (y1 - y2 > 0) {\n\t\t\tmaxDays = calendar2.getActualMaximum(Calendar.DAY_OF_YEAR);\n\t\t\tday = d1 - d2 + maxDays;\n\t\t} else if (y1 - y2 < 0) {\n\t\t\tmaxDays = calendar1.getActualMaximum(Calendar.DAY_OF_YEAR);\n\t\t\tday = d1 - d2 - maxDays;\n\t\t} else {\n\t\t\tday = d1 - d2;\n\t\t}\n\t\treturn day;\n\t}\n\n\t/**\n\t * 描述：计算两个日期所差的小时数.\n\t *\n\t * @param date1\n\t *            第一个时间的毫秒表示\n\t * @param date2\n\t *            第二个时间的毫秒表示\n\t * @return int 所差的小时数\n\t */\n\tpublic static int getOffectHour(long date1, long date2) {\n\t\tCalendar calendar1 = Calendar.getInstance();\n\t\tcalendar1.setTimeInMillis(date1);\n\t\tCalendar calendar2 = Calendar.getInstance();\n\t\tcalendar2.setTimeInMillis(date2);\n\t\tint h1 = calendar1.get(Calendar.HOUR_OF_DAY);\n\t\tint h2 = calendar2.get(Calendar.HOUR_OF_DAY);\n\t\tint h = 0;\n\t\tint day = getOffectDay(date1, date2);\n\t\th = h1 - h2 + day * 24;\n\t\treturn h;\n\t}\n\n\t/**\n\t * 描述：计算两个日期所差的分钟数.\n\t *\n\t * @param date1\n\t *            第一个时间的毫秒表示\n\t * @param date2\n\t *            第二个时间的毫秒表示\n\t * @return int 所差的分钟数\n\t */\n\tpublic static int getOffectMinutes(long date1, long date2) {\n\t\tCalendar calendar1 = Calendar.getInstance();\n\t\tcalendar1.setTimeInMillis(date1);\n\t\tCalendar calendar2 = Calendar.getInstance();\n\t\tcalendar2.setTimeInMillis(date2);\n\t\tint m1 = calendar1.get(Calendar.MINUTE);\n\t\tint m2 = calendar2.get(Calendar.MINUTE);\n\t\tint h = getOffectHour(date1, date2);\n\t\tint m = 0;\n\t\tm = m1 - m2 + h * 60;\n\t\treturn m;\n\t}\n\n\t/**\n\t * 描述：获取本周一.\n\t *\n\t * @param format\n\t *            the format\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getFirstDayOfWeek(String format) {\n\t\treturn getDayOfWeek(format, Calendar.MONDAY);\n\t}\n\n\t/**\n\t * 描述：获取本周日.\n\t *\n\t * @param format\n\t *            the format\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getLastDayOfWeek(String format) {\n\t\treturn getDayOfWeek(format, Calendar.SUNDAY);\n\t}\n\n\t/**\n\t * 描述：获取本周的某一天.\n\t *\n\t * @param format\n\t *            the format\n\t * @param calendarField\n\t *            the calendar field\n\t * @return String String类型日期时间\n\t */\n\tprivate static String getDayOfWeek(String format, int calendarField) {\n\t\tString strDate = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\tint week = c.get(Calendar.DAY_OF_WEEK);\n\t\t\tif (week == calendarField) {\n\t\t\t\tstrDate = mSimpleDateFormat.format(c.getTime());\n\t\t\t} else {\n\t\t\t\tint offectDay = calendarField - week;\n\t\t\t\tif (calendarField == Calendar.SUNDAY) {\n\t\t\t\t\toffectDay = 7 - Math.abs(offectDay);\n\t\t\t\t}\n\t\t\t\tc.add(Calendar.DATE, offectDay);\n\t\t\t\tstrDate = mSimpleDateFormat.format(c.getTime());\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn strDate;\n\t}\n\n\t/**\n\t * 描述：获取本月第一天.\n\t *\n\t * @param format\n\t *            the format\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getFirstDayOfMonth(String format) {\n\t\tString strDate = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\t// 当前月的第一天\n\t\t\tc.set(GregorianCalendar.DAY_OF_MONTH, 1);\n\t\t\tstrDate = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn strDate;\n\n\t}\n\n\t/**\n\t * 描述：获取本月最后一天.\n\t *\n\t * @param format\n\t *            the format\n\t * @return String String类型日期时间\n\t */\n\tpublic static String getLastDayOfMonth(String format) {\n\t\tString strDate = null;\n\t\ttry {\n\t\t\tCalendar c = new GregorianCalendar();\n\t\t\tSimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);\n\t\t\t// 当前月的最后一天\n\t\t\tc.set(Calendar.DATE, 1);\n\t\t\tc.roll(Calendar.DATE, -1);\n\t\t\tstrDate = mSimpleDateFormat.format(c.getTime());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn strDate;\n\t}\n\n\t/**\n\t * 描述：获取表示当前日期的0点时间毫秒数.\n\t *\n\t * @return the first time of day\n\t */\n\tpublic static long getFirstTimeOfDay() {\n\t\tDate date = null;\n\t\ttry {\n\t\t\tString currentDate = getCurrentDate(dateFormatYMD);\n\t\t\tdate = getDateByFormat(currentDate + \" 00:00:00\", dateFormatYMDHMS);\n\t\t\treturn date.getTime();\n\t\t} catch (Exception e) {\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * 描述：获取表示当前日期24点时间毫秒数.\n\t *\n\t * @return the last time of day\n\t */\n\tpublic static long getLastTimeOfDay() {\n\t\tDate date = null;\n\t\ttry {\n\t\t\tString currentDate = getCurrentDate(dateFormatYMD);\n\t\t\tdate = getDateByFormat(currentDate + \" 24:00:00\", dateFormatYMDHMS);\n\t\t\treturn date.getTime();\n\t\t} catch (Exception e) {\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * 描述：判断是否是闰年()\n\t * <p>\n\t * (year能被4整除 并且 不能被100整除) 或者 year能被400整除,则该年为闰年.\n\t *\n\t * @param year\n\t *            年代（如2012）\n\t * @return boolean 是否为闰年\n\t */\n\tpublic static boolean isLeapYear(int year) {\n\t\tif ((year % 4 == 0 && year % 400 != 0) || year % 400 == 0) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * 描述：根据时间返回格式化后的时间的描述. 小于1小时显示多少分钟前 大于1小时显示今天＋实际日期，大于今天全部显示实际时间\n\t *\n\t * @param strDate\n\t *            the str date\n\t * @param outFormat\n\t *            the out format\n\t * @return the string\n\t */\n\tpublic static String formatDateStr2Desc(String strDate, String outFormat) {\n\n\t\tDateFormat df = new SimpleDateFormat(dateFormatYMDHMS);\n\t\tCalendar c1 = Calendar.getInstance();\n\t\tCalendar c2 = Calendar.getInstance();\n\t\ttry {\n\t\t\tc2.setTime(df.parse(strDate));\n\t\t\tc1.setTime(new Date());\n\t\t\tint d = getOffectDay(c1.getTimeInMillis(), c2.getTimeInMillis());\n\t\t\tif (d == 0) {\n\t\t\t\tint h = getOffectHour(c1.getTimeInMillis(), c2.getTimeInMillis());\n\t\t\t\tif (h > 0) {\n\t\t\t\t\treturn \"今天\" + getStringByFormat(strDate, dateFormatHM);\n\t\t\t\t\t// return h + \"小时前\";\n\t\t\t\t} else if (h < 0) {\n\t\t\t\t\t// return Math.abs(h) + \"小时后\";\n\t\t\t\t} else if (h == 0) {\n\t\t\t\t\tint m = getOffectMinutes(c1.getTimeInMillis(), c2.getTimeInMillis());\n\t\t\t\t\tif (m > 0) {\n\t\t\t\t\t\treturn m + \"分钟前\";\n\t\t\t\t\t} else if (m < 0) {\n\t\t\t\t\t\t// return Math.abs(m) + \"分钟后\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn \"刚刚\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if (d > 0) {\n\t\t\t\tif (d == 1) {\n\t\t\t\t\t// return \"昨天\"+getStringByFormat(strDate,outFormat);\n\t\t\t\t} else if (d == 2) {\n\t\t\t\t\t// return \"前天\"+getStringByFormat(strDate,outFormat);\n\t\t\t\t}\n\t\t\t} else if (d < 0) {\n\t\t\t\tif (d == -1) {\n\t\t\t\t\t// return \"明天\"+getStringByFormat(strDate,outFormat);\n\t\t\t\t} else if (d == -2) {\n\t\t\t\t\t// return \"后天\"+getStringByFormat(strDate,outFormat);\n\t\t\t\t} else {\n\t\t\t\t\t// return Math.abs(d) +\n\t\t\t\t\t// \"天后\"+getStringByFormat(strDate,outFormat);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tString out = getStringByFormat(strDate, outFormat);\n\t\t\tif (!AbStrUtil.isEmpty(out)) {\n\t\t\t\treturn out;\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t}\n\n\t\treturn strDate;\n\t}\n\n\t/**\n\t * 取指定日期为星期几.\n\t *\n\t * @param strDate\n\t *            指定日期\n\t * @param inFormat\n\t *            指定日期格式\n\t * @return String 星期几\n\t */\n\tpublic static String getWeekNumber(String strDate, String inFormat) {\n\t\tString week = \"星期日\";\n\t\tCalendar calendar = new GregorianCalendar();\n\t\tDateFormat df = new SimpleDateFormat(inFormat);\n\t\ttry {\n\t\t\tcalendar.setTime(df.parse(strDate));\n\t\t} catch (Exception e) {\n\t\t\treturn \"错误\";\n\t\t}\n\t\tint intTemp = calendar.get(Calendar.DAY_OF_WEEK) - 1;\n\t\tswitch (intTemp) {\n\t\tcase 0:\n\t\t\tweek = \"星期日\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tweek = \"星期一\";\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tweek = \"星期二\";\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tweek = \"星期三\";\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tweek = \"星期四\";\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tweek = \"星期五\";\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tweek = \"星期六\";\n\t\t\tbreak;\n\t\t}\n\t\treturn week;\n\t}\n\n\t/**\n\t * 根据给定的日期判断是否为上下午.\n\t *\n\t * @param strDate\n\t *            the str date\n\t * @param format\n\t *            the format\n\t * @return the time quantum\n\t */\n\tpublic static String getTimeQuantum(String strDate, String format) {\n\t\tDate mDate = getDateByFormat(strDate, format);\n\t\tint hour = mDate.getHours();\n\t\tif (hour >= 12)\n\t\t\treturn \"PM\";\n\t\telse\n\t\t\treturn \"AM\";\n\t}\n\n\t/**\n\t * 根据给定的毫秒数算得时间的描述.\n\t *\n\t * @param milliseconds\n\t *            the milliseconds\n\t * @return the time description\n\t */\n\tpublic static String getTimeDescription(long milliseconds) {\n\t\tif (milliseconds > 1000) {\n\t\t\t// 大于一分\n\t\t\tif (milliseconds / 1000 / 60 > 1) {\n\t\t\t\tlong minute = milliseconds / 1000 / 60;\n\t\t\t\tlong second = milliseconds / 1000 % 60;\n\t\t\t\treturn minute + \"分\" + second + \"秒\";\n\t\t\t} else {\n\t\t\t\t// 显示秒\n\t\t\t\treturn milliseconds / 1000 + \"秒\";\n\t\t\t}\n\t\t} else {\n\t\t\treturn milliseconds + \"毫秒\";\n\t\t}\n\t}\n\n\t/**\n\t * 解析时间按照小时：分：秒格式输出\n\t * \n\t * @param iTimeSeconds 秒\n\t * @return\n\t */\n\tpublic static String getTime(int iTimeSeconds) {\n\t\tString strUserTime = iTimeSeconds / 60 + \" : \"\n\t\t\t\t+ ((iTimeSeconds % 60) < 10 ? (\"0\" + iTimeSeconds % 60) : iTimeSeconds % 60);\n\t\treturn strUserTime;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbFileUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.os.StatFs;\nimport android.util.Log;\n\nimport com.ab.global.AbAppConfig;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.BufferedReader;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.Comparator;\nimport java.util.Enumeration;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn 名称：AbFileUtil.java 描述：文件操作类.\n */\npublic class AbFileUtil {\n\n\t/** 默认APP根目录. */\n\tprivate static String downloadRootDir = null;\n\n\t/** 默认下载图片文件目录. */\n\tprivate static String imageDownloadDir = null;\n\n\t/** 默认下载文件目录. */\n\tprivate static String fileDownloadDir = null;\n\n\t/** 默认缓存目录. */\n\tprivate static String cacheDownloadDir = null;\n\n\t/** 默认下载数据库文件的目录. */\n\tprivate static String dbDownloadDir = null;\n\n\t/** 剩余空间大于200M才使用SD缓存. */\n\tprivate static int freeSdSpaceNeededToCache = 200 * 1024 * 1024;\n\n\t/**\n\t * 描述：通过文件的网络地址从SD卡中读取图片，如果SD中没有则自动下载并保存.\n\t * \n\t * @param url\n\t *            文件的网络地址\n\t * @param type\n\t *            图片的处理类型（剪切或者缩放到指定大小，参考AbImageUtil类） 如果设置为原图，则后边参数无效，得到原图\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap getBitmapFromSD(String url, int type, int desiredWidth, int desiredHeight) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\tif (AbStrUtil.isEmpty(url)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// SD卡不存在 或者剩余空间不足了就不缓存到SD卡了\n\t\t\tif (!isCanUseSD() || freeSdSpaceNeededToCache < freeSpaceOnSD()) {\n\t\t\t\tbitmap = getBitmapFromURL(url, type, desiredWidth, desiredHeight);\n\t\t\t\treturn bitmap;\n\t\t\t}\n\t\t\t// 下载文件，如果不存在就下载，存在直接返回地址\n\t\t\tString downFilePath = downloadFile(url, imageDownloadDir);\n\t\t\tif (downFilePath != null) {\n\t\t\t\t// 获取图片\n\t\t\t\treturn getBitmapFromSD(new File(downFilePath), type, desiredWidth, desiredHeight);\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 描述：通过文件的本地地址从SD卡读取图片.\n\t *\n\t * @param file\n\t *            the file\n\t * @param type\n\t *            图片的处理类型（剪切或者缩放到指定大小，参考AbConstant类） 如果设置为原图，则后边参数无效，得到原图\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap getBitmapFromSD(File file, int type, int desiredWidth, int desiredHeight) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\t// SD卡是否存在\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// 文件是否存在\n\t\t\tif (!file.exists()) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// 文件存在\n\t\t\tif (type == AbImageUtil.CUTIMG) {\n\t\t\t\tbitmap = AbImageUtil.cutImg(file, desiredWidth, desiredHeight);\n\t\t\t} else if (type == AbImageUtil.SCALEIMG) {\n\t\t\t\tbitmap = AbImageUtil.scaleImg(file, desiredWidth, desiredHeight);\n\t\t\t} else {\n\t\t\t\tbitmap = AbImageUtil.getBitmap(file);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 描述：通过文件的本地地址从SD卡读取图片.\n\t *\n\t * @param file\n\t *            the file\n\t * @return Bitmap 图片\n\t */\n\tpublic static Bitmap getBitmapFromSD(File file) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\t// SD卡是否存在\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 文件是否存在\n\t\t\tif (!file.exists()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 文件存在\n\t\t\tbitmap = AbImageUtil.getBitmap(file);\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 描述：将图片的byte[]写入本地文件.\n\t * \n\t * @param imgByte\n\t *            图片的byte[]形势\n\t * @param fileName\n\t *            文件名称，需要包含后缀，如.jpg\n\t * @param type\n\t *            图片的处理类型（剪切或者缩放到指定大小，参考AbConstant类）\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap getBitmapFromByte(byte[] imgByte, String fileName, int type, int desiredWidth,\n\t\t\tint desiredHeight) {\n\t\tFileOutputStream fos = null;\n\t\tDataInputStream dis = null;\n\t\tByteArrayInputStream bis = null;\n\t\tBitmap bitmap = null;\n\t\tFile file = null;\n\t\ttry {\n\t\t\tif (imgByte != null) {\n\n\t\t\t\tfile = new File(imageDownloadDir + fileName);\n\t\t\t\tif (!file.exists()) {\n\t\t\t\t\tfile.createNewFile();\n\t\t\t\t}\n\t\t\t\tfos = new FileOutputStream(file);\n\t\t\t\tint readLength = 0;\n\t\t\t\tbis = new ByteArrayInputStream(imgByte);\n\t\t\t\tdis = new DataInputStream(bis);\n\t\t\t\tbyte[] buffer = new byte[1024];\n\n\t\t\t\twhile ((readLength = dis.read(buffer)) != -1) {\n\t\t\t\t\tfos.write(buffer, 0, readLength);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tThread.sleep(500);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfos.flush();\n\n\t\t\t\tbitmap = getBitmapFromSD(file, type, desiredWidth, desiredHeight);\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (dis != null) {\n\t\t\t\ttry {\n\t\t\t\t\tdis.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bis != null) {\n\t\t\t\ttry {\n\t\t\t\t\tbis.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (fos != null) {\n\t\t\t\ttry {\n\t\t\t\t\tfos.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 描述：根据URL从互连网获取图片.\n\t * \n\t * @param url\n\t *            要下载文件的网络地址\n\t * @param type\n\t *            图片的处理类型（剪切或者缩放到指定大小，参考AbConstant类）\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap getBitmapFromURL(String url, int type, int desiredWidth, int desiredHeight) {\n\t\tBitmap bit = null;\n\t\ttry {\n\t\t\tbit = AbImageUtil.getBitmap(url, type, desiredWidth, desiredHeight);\n\t\t} catch (Exception e) {\n\t\t\tAbLogUtil.d(AbFileUtil.class, \"下载图片异常：\" + e.getMessage());\n\t\t}\n\t\treturn bit;\n\t}\n\n\t/**\n\t * 描述：获取src中的图片资源.\n\t *\n\t * @param src\n\t *            图片的src路径，如（“image/arrow.png”）\n\t * @return Bitmap 图片\n\t */\n\tpublic static Bitmap getBitmapFromSrc(String src) {\n\t\tBitmap bit = null;\n\t\ttry {\n\t\t\tbit = BitmapFactory.decodeStream(AbFileUtil.class.getResourceAsStream(src));\n\t\t} catch (Exception e) {\n\t\t\tAbLogUtil.d(AbFileUtil.class, \"获取图片异常：\" + e.getMessage());\n\t\t}\n\t\treturn bit;\n\t}\n\n\t/**\n\t * 描述：获取Asset中的图片资源.\n\t *\n\t * @param context\n\t *            the context\n\t * @param fileName\n\t *            the file name\n\t * @return Bitmap 图片\n\t */\n\tpublic static Bitmap getBitmapFromAsset(Context context, String fileName) {\n\t\tBitmap bit = null;\n\t\ttry {\n\t\t\tAssetManager assetManager = context.getAssets();\n\t\t\tInputStream is = assetManager.open(fileName);\n\t\t\tbit = BitmapFactory.decodeStream(is);\n\t\t} catch (Exception e) {\n\t\t\tAbLogUtil.d(AbFileUtil.class, \"获取图片异常：\" + e.getMessage());\n\t\t}\n\t\treturn bit;\n\t}\n\n\t/**\n\t * 描述：获取Asset中的图片资源.\n\t *\n\t * @param context\n\t *            the context\n\t * @param fileName\n\t *            the file name\n\t * @return Drawable 图片\n\t */\n\tpublic static Drawable getDrawableFromAsset(Context context, String fileName) {\n\t\tDrawable drawable = null;\n\t\ttry {\n\t\t\tAssetManager assetManager = context.getAssets();\n\t\t\tInputStream is = assetManager.open(fileName);\n\t\t\tdrawable = Drawable.createFromStream(is, null);\n\t\t} catch (Exception e) {\n\t\t\tAbLogUtil.d(AbFileUtil.class, \"获取图片异常：\" + e.getMessage());\n\t\t}\n\t\treturn drawable;\n\t}\n\n\t/**\n\t * 下载网络文件到SD卡中.如果SD中存在同名文件将不再下载\n\t *\n\t * @param url\n\t *            要下载文件的网络地址\n\t * @param dirPath\n\t *            the dir path\n\t * @return 下载好的本地文件地址\n\t */\n\tpublic static String downloadFile(String url, String dirPath) {\n\t\tInputStream in = null;\n\t\tFileOutputStream fileOutputStream = null;\n\t\tHttpURLConnection connection = null;\n\t\tString downFilePath = null;\n\t\tFile file = null;\n\t\ttry {\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 先判断SD卡中有没有这个文件，不比较后缀部分比较\n\t\t\tString fileNameNoMIME = getCacheFileNameFromUrl(url);\n\t\t\tFile parentFile = new File(imageDownloadDir);\n\t\t\tFile[] files = parentFile.listFiles();\n\t\t\tfor (int i = 0; i < files.length; ++i) {\n\t\t\t\tString fileName = files[i].getName();\n\t\t\t\tString name = fileName.substring(0, fileName.lastIndexOf(\".\"));\n\t\t\t\tif (name.equals(fileNameNoMIME)) {\n\t\t\t\t\t// 文件已存在\n\t\t\t\t\treturn files[i].getPath();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tURL mUrl = new URL(url);\n\t\t\tconnection = (HttpURLConnection) mUrl.openConnection();\n\t\t\tconnection.connect();\n\t\t\t// 获取文件名，下载文件\n\t\t\tString fileName = getCacheFileNameFromUrl(url, connection);\n\n\t\t\tfile = new File(imageDownloadDir, fileName);\n\t\t\tdownFilePath = file.getPath();\n\t\t\tif (!file.exists()) {\n\t\t\t\tfile.createNewFile();\n\t\t\t} else {\n\t\t\t\t// 文件已存在\n\t\t\t\treturn file.getPath();\n\t\t\t}\n\t\t\tin = connection.getInputStream();\n\t\t\tfileOutputStream = new FileOutputStream(file);\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint temp = 0;\n\t\t\twhile ((temp = in.read(b)) != -1) {\n\t\t\t\tfileOutputStream.write(b, 0, temp);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tAbLogUtil.e(AbFileUtil.class, \"有文件下载出错了,已删除\");\n\t\t\t// 检查文件大小,如果文件为0B说明网络不好没有下载成功，要将建立的空文件删除\n\t\t\tif (file != null) {\n\t\t\t\tfile.delete();\n\t\t\t}\n\t\t\tfile = null;\n\t\t\tdownFilePath = null;\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (in != null) {\n\t\t\t\t\tin.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (fileOutputStream != null) {\n\t\t\t\t\tfileOutputStream.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (connection != null) {\n\t\t\t\t\tconnection.disconnect();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn downFilePath;\n\t}\n\n\t/**\n\t * 描述：获取网络文件的大小.\n\t *\n\t * @param Url\n\t *            图片的网络路径\n\t * @return int 网络文件的大小\n\t */\n\tpublic static int getContentLengthFromUrl(String Url) {\n\t\tint mContentLength = 0;\n\t\ttry {\n\t\t\tURL url = new URL(Url);\n\t\t\tHttpURLConnection mHttpURLConnection = (HttpURLConnection) url.openConnection();\n\t\t\tmHttpURLConnection.setConnectTimeout(5 * 1000);\n\t\t\tmHttpURLConnection.setRequestMethod(\"GET\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Accept\",\n\t\t\t\t\t\"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Accept-Language\", \"zh-CN\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Referer\", Url);\n\t\t\tmHttpURLConnection.setRequestProperty(\"Charset\", \"UTF-8\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"User-Agent\",\n\t\t\t\t\t\"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Connection\", \"Keep-Alive\");\n\t\t\tmHttpURLConnection.connect();\n\t\t\tif (mHttpURLConnection.getResponseCode() == 200) {\n\t\t\t\t// 根据响应获取文件大小\n\t\t\t\tmContentLength = mHttpURLConnection.getContentLength();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tAbLogUtil.d(AbFileUtil.class, \"获取长度异常：\" + e.getMessage());\n\t\t}\n\t\treturn mContentLength;\n\t}\n\n\t/**\n\t * 获取文件名，通过网络获取.\n\t * \n\t * @param url\n\t *            文件地址\n\t * @return 文件名\n\t */\n\tpublic static String getRealFileNameFromUrl(String url) {\n\t\tString name = null;\n\t\ttry {\n\t\t\tif (AbStrUtil.isEmpty(url)) {\n\t\t\t\treturn name;\n\t\t\t}\n\n\t\t\tURL mUrl = new URL(url);\n\t\t\tHttpURLConnection mHttpURLConnection = (HttpURLConnection) mUrl.openConnection();\n\t\t\tmHttpURLConnection.setConnectTimeout(5 * 1000);\n\t\t\tmHttpURLConnection.setRequestMethod(\"GET\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Accept\",\n\t\t\t\t\t\"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Accept-Language\", \"zh-CN\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Referer\", url);\n\t\t\tmHttpURLConnection.setRequestProperty(\"Charset\", \"UTF-8\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"User-Agent\", \"\");\n\t\t\tmHttpURLConnection.setRequestProperty(\"Connection\", \"Keep-Alive\");\n\t\t\tmHttpURLConnection.connect();\n\t\t\tif (mHttpURLConnection.getResponseCode() == 200) {\n\t\t\t\tfor (int i = 0;; i++) {\n\t\t\t\t\tString mine = mHttpURLConnection.getHeaderField(i);\n\t\t\t\t\tif (mine == null) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"content-disposition\".equals(mHttpURLConnection.getHeaderFieldKey(i).toLowerCase())) {\n\t\t\t\t\t\tMatcher m = Pattern.compile(\".*filename=(.*)\").matcher(mine.toLowerCase());\n\t\t\t\t\t\tif (m.find())\n\t\t\t\t\t\t\treturn m.group(1).replace(\"\\\"\", \"\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tAbLogUtil.e(AbFileUtil.class, \"网络上获取文件名失败\");\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * 获取真实文件名（xx.后缀），通过网络获取.\n\t * \n\t * @param connection\n\t *            连接\n\t * @return 文件名\n\t */\n\tpublic static String getRealFileName(HttpURLConnection connection) {\n\t\tString name = null;\n\t\ttry {\n\t\t\tif (connection == null) {\n\t\t\t\treturn name;\n\t\t\t}\n\t\t\tif (connection.getResponseCode() == 200) {\n\t\t\t\tfor (int i = 0;; i++) {\n\t\t\t\t\tString mime = connection.getHeaderField(i);\n\t\t\t\t\tif (mime == null) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// \"Content-Disposition\",\"attachment; filename=1.txt\"\n\t\t\t\t\t// Content-Length\n\t\t\t\t\tif (\"content-disposition\".equals(connection.getHeaderFieldKey(i).toLowerCase())) {\n\t\t\t\t\t\tMatcher m = Pattern.compile(\".*filename=(.*)\").matcher(mime.toLowerCase());\n\t\t\t\t\t\tif (m.find()) {\n\t\t\t\t\t\t\treturn m.group(1).replace(\"\\\"\", \"\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tAbLogUtil.e(AbFileUtil.class, \"网络上获取文件名失败\");\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * 获取文件名（不含后缀）.\n\t *\n\t * @param url\n\t *            文件地址\n\t * @return 文件名\n\t */\n\tpublic static String getCacheFileNameFromUrl(String url) {\n\t\tif (AbStrUtil.isEmpty(url)) {\n\t\t\treturn null;\n\t\t}\n\t\tString name = null;\n\t\ttry {\n\t\t\tname = AbMd5.MD5(url);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * 获取文件名（.后缀），外链模式和通过网络获取.\n\t *\n\t * @param url\n\t *            文件地址\n\t * @param connection\n\t *            the connection\n\t * @return 文件名\n\t */\n\tpublic static String getCacheFileNameFromUrl(String url, HttpURLConnection connection) {\n\t\tif (AbStrUtil.isEmpty(url)) {\n\t\t\treturn null;\n\t\t}\n\t\tString name = null;\n\t\ttry {\n\t\t\t// 获取后缀\n\t\t\tString suffix = getMIMEFromUrl(url, connection);\n\t\t\tif (AbStrUtil.isEmpty(suffix)) {\n\t\t\t\tsuffix = \".ab\";\n\t\t\t}\n\t\t\tname = AbMd5.MD5(url) + suffix;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * 获取文件后缀，本地.\n\t *\n\t * @param url\n\t *            文件地址\n\t * @param connection\n\t *            the connection\n\t * @return 文件后缀\n\t */\n\tpublic static String getMIMEFromUrl(String url, HttpURLConnection connection) {\n\n\t\tif (AbStrUtil.isEmpty(url)) {\n\t\t\treturn null;\n\t\t}\n\t\tString suffix = null;\n\t\ttry {\n\t\t\t// 获取后缀\n\t\t\tif (url.lastIndexOf(\".\") != -1) {\n\t\t\t\tsuffix = url.substring(url.lastIndexOf(\".\"));\n\t\t\t\tif (suffix.indexOf(\"/\") != -1 || suffix.indexOf(\"?\") != -1 || suffix.indexOf(\"&\") != -1) {\n\t\t\t\t\tsuffix = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (AbStrUtil.isEmpty(suffix)) {\n\t\t\t\t// 获取文件名 这个效率不高\n\t\t\t\tString fileName = getRealFileName(connection);\n\t\t\t\tif (fileName != null && fileName.lastIndexOf(\".\") != -1) {\n\t\t\t\t\tsuffix = fileName.substring(fileName.lastIndexOf(\".\"));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn suffix;\n\t}\n\n\t/**\n\t * 描述：从sd卡中的文件读取到byte[].\n\t *\n\t * @param path\n\t *            sd卡中文件路径\n\t * @return byte[]\n\t */\n\tpublic static byte[] getByteArrayFromSD(String path) {\n\t\tbyte[] bytes = null;\n\t\tByteArrayOutputStream out = null;\n\t\ttry {\n\t\t\tFile file = new File(path);\n\t\t\t// SD卡是否存在\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 文件是否存在\n\t\t\tif (!file.exists()) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlong fileSize = file.length();\n\t\t\tif (fileSize > Integer.MAX_VALUE) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tFileInputStream in = new FileInputStream(path);\n\t\t\tout = new ByteArrayOutputStream(1024);\n\t\t\tbyte[] buffer = new byte[1024];\n\t\t\tint size = 0;\n\t\t\twhile ((size = in.read(buffer)) != -1) {\n\t\t\t\tout.write(buffer, 0, size);\n\t\t\t}\n\t\t\tin.close();\n\t\t\tbytes = out.toByteArray();\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (out != null) {\n\t\t\t\ttry {\n\t\t\t\t\tout.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn bytes;\n\t}\n\n\t/**\n\t * 描述：将byte数组写入文件.\n\t *\n\t * @param path\n\t *            the path\n\t * @param content\n\t *            the content\n\t * @param create\n\t *            the create\n\t */\n\tpublic static void writeByteArrayToSD(String path, byte[] content, boolean create) {\n\n\t\tFileOutputStream fos = null;\n\t\ttry {\n\t\t\tFile file = new File(path);\n\t\t\t// SD卡是否存在\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// 文件是否存在\n\t\t\tif (!file.exists()) {\n\t\t\t\tif (create) {\n\t\t\t\t\tFile parent = file.getParentFile();\n\t\t\t\t\tif (!parent.exists()) {\n\t\t\t\t\t\tparent.mkdirs();\n\t\t\t\t\t\tfile.createNewFile();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfos = new FileOutputStream(path);\n\t\t\tfos.write(content);\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (fos != null) {\n\t\t\t\ttry {\n\t\t\t\t\tfos.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 描述：SD卡是否能用.\n\t *\n\t * @return true 可用,false不可用\n\t */\n\tpublic static boolean isCanUseSD() {\n\t\ttry {\n\t\t\treturn Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 描述：初始化存储目录.\n\t *\n\t * @param context\n\t *            the context\n\t */\n\tpublic static void initFileDir(Context context) {\n\n\t\tPackageInfo info = AbAppUtil.getPackageInfo(context);\n\n\t\t// 默认下载文件根目录.\n\t\tString downloadRootPath = File.separator + AbAppConfig.DOWNLOAD_ROOT_DIR + File.separator + info.packageName\n\t\t\t\t+ File.separator;\n\n\t\t// 默认下载图片文件目录.\n\t\tString imageDownloadPath = downloadRootPath + AbAppConfig.DOWNLOAD_IMAGE_DIR + File.separator;\n\n\t\t// 默认下载文件目录.\n\t\tString fileDownloadPath = downloadRootPath + AbAppConfig.DOWNLOAD_FILE_DIR + File.separator;\n\n\t\t// 默认缓存目录.\n\t\tString cacheDownloadPath = downloadRootPath + AbAppConfig.CACHE_DIR + File.separator;\n\n\t\t// 默认DB目录.\n\t\tString dbDownloadPath = downloadRootPath + AbAppConfig.DB_DIR + File.separator;\n\n\t\ttry {\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn;\n\t\t\t} else {\n\n\t\t\t\tFile root = Environment.getExternalStorageDirectory();\n\t\t\t\tFile downloadDir = new File(root.getAbsolutePath() + downloadRootPath);\n\t\t\t\tif (!downloadDir.exists()) {\n\t\t\t\t\tdownloadDir.mkdirs();\n\t\t\t\t}\n\t\t\t\tdownloadRootDir = downloadDir.getPath();\n\n\t\t\t\tFile cacheDownloadDirFile = new File(root.getAbsolutePath() + cacheDownloadPath);\n\t\t\t\tif (!cacheDownloadDirFile.exists()) {\n\t\t\t\t\tcacheDownloadDirFile.mkdirs();\n\t\t\t\t}\n\t\t\t\tcacheDownloadDir = cacheDownloadDirFile.getPath();\n\n\t\t\t\tFile imageDownloadDirFile = new File(root.getAbsolutePath() + imageDownloadPath);\n\t\t\t\tif (!imageDownloadDirFile.exists()) {\n\t\t\t\t\timageDownloadDirFile.mkdirs();\n\t\t\t\t}\n\t\t\t\timageDownloadDir = imageDownloadDirFile.getPath();\n\n\t\t\t\tFile fileDownloadDirFile = new File(root.getAbsolutePath() + fileDownloadPath);\n\t\t\t\tif (!fileDownloadDirFile.exists()) {\n\t\t\t\t\tfileDownloadDirFile.mkdirs();\n\t\t\t\t}\n\t\t\t\tfileDownloadDir = fileDownloadDirFile.getPath();\n\n\t\t\t\tFile dbDownloadDirFile = new File(root.getAbsolutePath() + dbDownloadPath);\n\t\t\t\tif (!dbDownloadDirFile.exists()) {\n\t\t\t\t\tdbDownloadDirFile.mkdirs();\n\t\t\t\t}\n\t\t\t\tdbDownloadDir = dbDownloadDirFile.getPath();\n\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 计算sdcard上的剩余空间.\n\t *\n\t * @return the int\n\t */\n\tpublic static int freeSpaceOnSD() {\n\t\tStatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());\n\t\tdouble sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / 1024 * 1024;\n\t\treturn (int) sdFreeMB;\n\t}\n\n\t/**\n\t * 根据文件的最后修改时间进行排序.\n\t */\n\tpublic static class FileLastModifSort implements Comparator<File> {\n\n\t\t/*\n\t\t * (non-Javadoc)\n\t\t * \n\t\t * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)\n\t\t */\n\t\tpublic int compare(File arg0, File arg1) {\n\t\t\tif (arg0.lastModified() > arg1.lastModified()) {\n\t\t\t\treturn 1;\n\t\t\t} else if (arg0.lastModified() == arg1.lastModified()) {\n\t\t\t\treturn 0;\n\t\t\t} else {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 删除所有缓存文件.\n\t *\n\t * @return true, if successful\n\t */\n\tpublic static boolean clearDownloadFile() {\n\n\t\ttry {\n\t\t\tif (!isCanUseSD()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tFile path = Environment.getExternalStorageDirectory();\n\t\t\tFile fileDirectory = new File(path.getAbsolutePath() + downloadRootDir);\n\t\t\tFile[] files = fileDirectory.listFiles();\n\t\t\tif (files == null) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (int i = 0; i < files.length; i++) {\n\t\t\t\tfiles[i].delete();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 描述：读取Assets目录的文件内容.\n\t *\n\t * @param context\n\t *            the context\n\t * @param name\n\t *            the name\n\t * @param encoding\n\t *            the encoding\n\t * @return the string\n\t */\n\tpublic static String readAssetsByName(Context context, String name, String encoding) {\n\t\tString text = null;\n\t\tInputStreamReader inputReader = null;\n\t\tBufferedReader bufReader = null;\n\t\ttry {\n\t\t\tinputReader = new InputStreamReader(context.getAssets().open(name));\n\t\t\tbufReader = new BufferedReader(inputReader);\n\t\t\tString line = null;\n\t\t\tStringBuffer buffer = new StringBuffer();\n\t\t\twhile ((line = bufReader.readLine()) != null) {\n\t\t\t\tbuffer.append(line);\n\t\t\t}\n\t\t\ttext = new String(buffer.toString().getBytes(), encoding);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (bufReader != null) {\n\t\t\t\t\tbufReader.close();\n\t\t\t\t}\n\t\t\t\tif (inputReader != null) {\n\t\t\t\t\tinputReader.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * 描述：读取Raw目录的文件内容.\n\t *\n\t * @param context\n\t *            the context\n\t * @param id\n\t *            the id\n\t * @param encoding\n\t *            the encoding\n\t * @return the string\n\t */\n\tpublic static String readRawByName(Context context, int id, String encoding) {\n\t\tString text = null;\n\t\tInputStreamReader inputReader = null;\n\t\tBufferedReader bufReader = null;\n\t\ttry {\n\t\t\tinputReader = new InputStreamReader(context.getResources().openRawResource(id));\n\t\t\tbufReader = new BufferedReader(inputReader);\n\t\t\tString line = null;\n\t\t\tStringBuffer buffer = new StringBuffer();\n\t\t\twhile ((line = bufReader.readLine()) != null) {\n\t\t\t\tbuffer.append(line);\n\t\t\t}\n\t\t\ttext = new String(buffer.toString().getBytes(), encoding);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (bufReader != null) {\n\t\t\t\t\tbufReader.close();\n\t\t\t\t}\n\t\t\t\tif (inputReader != null) {\n\t\t\t\t\tinputReader.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * 解压缩功能. 将zipFile文件解压到folderPath目录下.\n\t * \n\t * @param zipFile\n\t *            zip文件地址\n\t * @param folderPath\n\t *            解压目的文件\n\t * @return\n\t */\n\tpublic int upZipFile(File zipFile, String folderPath) {\n\t\ttry {\n\t\t\tZipFile zfile = new ZipFile(zipFile);\n\t\t\tEnumeration zList = zfile.entries();\n\t\t\tZipEntry ze = null;\n\t\t\tbyte[] buf = new byte[1024];\n\t\t\twhile (zList.hasMoreElements()) {\n\t\t\t\tze = (ZipEntry) zList.nextElement();\n\t\t\t\tif (ze.isDirectory()) {\n\t\t\t\t\tLog.d(\"upZipFile\", \"ze.getName() = \" + ze.getName());\n\t\t\t\t\tString dirstr = folderPath + ze.getName();\n\t\t\t\t\t// dirstr.trim();\n\t\t\t\t\tdirstr = new String(dirstr.getBytes(\"8859_1\"), \"GB2312\");\n\t\t\t\t\tLog.d(\"upZipFile\", \"str = \" + dirstr);\n\t\t\t\t\tFile f = new File(dirstr);\n\t\t\t\t\tf.mkdir();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tLog.d(\"upZipFile\", \"ze.getName() = \" + ze.getName());\n\t\t\t\tOutputStream os = new BufferedOutputStream(\n\t\t\t\t\t\tnew FileOutputStream(getRealFileName(folderPath, ze.getName())));\n\t\t\t\tInputStream is = new BufferedInputStream(zfile.getInputStream(ze));\n\t\t\t\tint readLen = 0;\n\t\t\t\twhile ((readLen = is.read(buf, 0, 1024)) != -1) {\n\t\t\t\t\tos.write(buf, 0, readLen);\n\t\t\t\t}\n\t\t\t\tis.close();\n\t\t\t\tos.close();\n\t\t\t}\n\t\t\tzfile.close();\n\t\t} catch (IOException e) {\n\t\t\tLog.e(\"tag\", \"解压失败!\");\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 给定根目录，返回一个相对路径所对应的实际文件名.（压缩文件）\n\t * \n\t * @param baseDir\n\t *            指定根目录\n\t * @param absFileName\n\t *            相对路径名，来自于ZipEntry中的name\n\t * @return java.io.File 实际的文件\n\t */\n\tpublic static File getRealFileName(String baseDir, String absFileName) {\n\t\tString[] dirs = absFileName.split(\"/\");\n\t\tFile ret = new File(baseDir);\n\t\tString substr = null;\n\t\tif (dirs.length > 1) {\n\t\t\tfor (int i = 0; i < dirs.length - 1; i++) {\n\t\t\t\tsubstr = dirs[i];\n\t\t\t\ttry {\n\t\t\t\t\tsubstr = new String(substr.getBytes(\"8859_1\"), \"GB2312\");\n\t\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tret = new File(ret, substr);\n\t\t\t}\n\t\t\tLog.d(\"upZipFile\", \"1ret = \" + ret);\n\t\t\tif (!ret.exists())\n\t\t\t\tret.mkdirs();\n\t\t\tsubstr = dirs[dirs.length - 1];\n\t\t\ttry {\n\t\t\t\tsubstr = new String(substr.getBytes(\"8859_1\"), \"GB2312\");\n\t\t\t\tLog.d(\"upZipFile\", \"substr = \" + substr);\n\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tret = new File(ret, substr);\n\t\t\tLog.d(\"upZipFile\", \"2ret = \" + ret);\n\t\t\treturn ret;\n\t\t}\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 打开pdf文件\n\t * \n\t * @param strPath\n\t *            文件的地址\n\t * @param context\n\t *            对于的contenxt\n\t */\n\tpublic String openPdfFile(String strPath, Context context) {\n\t\tFile file = new File(strPath);\n\t\tif (file.exists()) {\n\t\t\tUri path = Uri.fromFile(file);\n\t\t\tIntent intent = new Intent(Intent.ACTION_VIEW);\n\t\t\tintent.setDataAndType(path, \"application/pdf\");\n\t\t\tintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n\t\t\ttry {\n\t\t\t\tcontext.startActivity(intent);\n\t\t\t\treturn \"true\";\n\t\t\t} catch (ActivityNotFoundException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t\treturn \"请安装wps\";\n\t\t\t}\n\t\t} else {\n\t\t\treturn \"文件地址不对、或者文件不存在\";\n\t\t}\n\t}\n\n\t/**\n\t * 删除文件，可以是单个文件或文件夹\n\t * \n\t * @param fileName\n\t *            待删除的文件名\n\t * @return 文件删除成功返回true,否则返回false\n\t */\n\tpublic static boolean delete(String fileName) {\n\t\tFile file = new File(fileName);\n\t\tif (!file.exists()) {\n\t\t\tSystem.out.println(\"删除文件失败：\" + fileName + \"文件不存在\");\n\t\t\treturn false;\n\t\t} else {\n\t\t\tif (file.isFile()) {\n\n\t\t\t\treturn deleteFile(fileName);\n\t\t\t} else {\n\t\t\t\treturn deleteDirectory(fileName, false);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 删除单个文件\n\t * \n\t * @param fileName\n\t *            被删除文件的文件名\n\t * @return 单个文件删除成功返回true,否则返回false\n\t */\n\tpublic static boolean deleteFile(String fileName) {\n\t\tFile file = new File(fileName);\n\t\tif (file.isFile() && file.exists()) {\n\t\t\tfile.delete();\n\t\t\tSystem.out.println(\"删除单个文件\" + fileName + \"成功！\");\n\t\t\treturn true;\n\t\t} else {\n\t\t\tSystem.out.println(\"删除单个文件\" + fileName + \"失败！\");\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * 删除目录（文件夹）以及目录下的文件\n\t * \n\t * @param dir\n\t *            被删除目录的文件路径\n\t * @param isSave\n\t *            是否保存文件\n\t * @return 目录删除成功返回true,否则返回false\n\t */\n\tpublic static boolean deleteDirectory(String dir, boolean isSave) {\n\t\t// 如果dir不以文件分隔符结尾，自动添加文件分隔符\n\t\tif (!dir.endsWith(File.separator)) {\n\t\t\tdir = dir + File.separator;\n\t\t}\n\t\tFile dirFile = new File(dir);\n\t\t// 如果dir对应的文件不存在，或者不是一个目录，则退出\n\t\tif (!dirFile.exists() || !dirFile.isDirectory()) {\n\t\t\tSystem.out.println(\"删除目录失败\" + dir + \"目录不存在！\");\n\t\t\treturn false;\n\t\t}\n\t\tboolean flag = true;\n\t\t// 删除文件夹下的所有文件(包括子目录)\n\t\tFile[] files = dirFile.listFiles();\n\t\tfor (int i = 0; i < files.length; i++) {\n\t\t\t// 删除子文件\n\t\t\tif (files[i].isFile()) {\n\t\t\t\tflag = deleteFile(files[i].getAbsolutePath());\n\t\t\t\tif (!flag) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 删除子目录\n\t\t\telse {\n\t\t\t\tflag = deleteDirectory(files[i].getAbsolutePath(), false);\n\t\t\t\tif (!flag) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!flag) {\n\t\t\tSystem.out.println(\"删除目录失败\");\n\t\t\treturn false;\n\t\t}\n\n\t\tif (isSave) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\t// 删除当前目录\n\t\t\tif (dirFile.delete()) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"删除目录\" + dir + \"失败！\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets the download root dir.\n\t *\n\t * @param context\n\t *            the context\n\t * @return the download root dir\n\t */\n\tpublic static String getDownloadRootDir(Context context) {\n\t\tif (downloadRootDir == null) {\n\t\t\tinitFileDir(context);\n\t\t}\n\t\treturn downloadRootDir;\n\t}\n\n\t/**\n\t * Gets the image download dir.\n\t *\n\t * @param context\n\t *            the context\n\t * @return the image download dir\n\t */\n\tpublic static String getImageDownloadDir(Context context) {\n\t\tif (downloadRootDir == null) {\n\t\t\tinitFileDir(context);\n\t\t}\n\t\treturn imageDownloadDir;\n\t}\n\n\t/**\n\t * Gets the file download dir.\n\t *\n\t * @param context\n\t *            the context\n\t * @return the file download dir\n\t */\n\tpublic static String getFileDownloadDir(Context context) {\n\t\tif (downloadRootDir == null) {\n\t\t\tinitFileDir(context);\n\t\t}\n\t\treturn fileDownloadDir;\n\t}\n\n\t/**\n\t * Gets the cache download dir.\n\t *\n\t * @param context\n\t *            the context\n\t * @return the cache download dir\n\t */\n\tpublic static String getCacheDownloadDir(Context context) {\n\t\tif (downloadRootDir == null) {\n\t\t\tinitFileDir(context);\n\t\t}\n\t\treturn cacheDownloadDir;\n\t}\n\n\t/**\n\t * Gets the db download dir.\n\t *\n\t * @param context\n\t *            the context\n\t * @return the db download dir\n\t */\n\tpublic static String getDbDownloadDir(Context context) {\n\t\tif (downloadRootDir == null) {\n\t\t\tinitFileDir(context);\n\t\t}\n\t\treturn dbDownloadDir;\n\t}\n\n\t/**\n\t * Gets the free sd space needed to cache.\n\t *\n\t * @return the free sd space needed to cache\n\t */\n\tpublic static int getFreeSdSpaceNeededToCache() {\n\t\treturn freeSdSpaceNeededToCache;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbGraphicUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint.FontMetrics;\nimport android.text.Layout;\nimport android.text.TextPaint;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn\n * 名称：AbGraphic.java \n * 描述：图形处理类.\n */\npublic final class AbGraphicUtil {\n    \n     /**\n      * 描述：获取字符的所在位置（按像素获取最大能容纳的）.\n      *\n      * @param str 指定的字符串\n      * @param maxPix 要取到的位置（像素）\n      * @param paint the paint\n      * @return 字符的所在位置\n      */\n     public static int subStringLength(String str,int maxPix,TextPaint paint) {\n    \t if(AbStrUtil.isEmpty(str)){\n    \t\t return 0;\n    \t }\n    \t int currentIndex = 0;\n         for (int i = 0; i < str.length(); i++) {\n             //获取一个字符 \n             String temp = str.substring(0, i + 1);\n             float valueLength  = paint.measureText(temp);\n             if(valueLength > maxPix){\n            \t currentIndex = i-1;\n            \t break;\n             }else if(valueLength == maxPix){\n            \t currentIndex = i;\n            \t break;\n             }\n         }\n         //短于最大像素返回最后一个字符位置\n         if(currentIndex==0){\n        \t currentIndex = str.length()-1 ;\n         }\n         return currentIndex;\n     }\n     \n     /**\n      * 描述：获取文字的像素宽.\n      *\n      * @param str the str\n      * @param paint the paint\n      * @return the string width\n      */\n     public static float getStringWidth(String str,TextPaint paint) {\n    \t float strWidth  = paint.measureText(str);\n         return strWidth;\n     }\n     \n     /**\n      * 获得文字的宽度\n      * @param str the str\n      * @param paint the paint\n      * @return the string width\n      */\n     public static float getDesiredWidth(String str,TextPaint paint) {\n    \t float strWidth = Layout.getDesiredWidth(str, paint);\n         return strWidth;\n     }\n     \n     /**\n      * 获取文字的高度\n      * @param paint the textPaint\n      * @return the string height\n      */\n     public static float getDesiredHeight(TextPaint paint) {\n    \t FontMetrics  fm  = paint.getFontMetrics();\n         return (float)Math.ceil(fm.descent - fm.ascent);\n     }\n\n     /**\n      * 解析成行.\n      * @param text the text\n      * @param maxWPix the max w pix\n      * @param paint the paint\n      * @return the draw row count\n      */\n     public static List<String> getDrawRowStr(String text,int maxWPix,TextPaint paint) {\n     \tString [] texts = null;\n     \tif(text.indexOf(\"\\n\")!=-1){\n     \t\t texts = text.split(\"\\n\");\n     \t}else{\n     \t\t texts  = new String [1];\n     \t\t texts[0] = text;\n     \t}\n     \t//共多少行\n     \tList<String> mStrList  = new ArrayList<String>();\n     \t\n     \tfor(int i=0;i<texts.length;i++){\n   \t\t    String textLine = texts[i];\n   \t\t    //计算这个文本显示为几行\n            while(true){\n\t           \t //可容纳的最后一个字的位置\n\t           \t int endIndex = subStringLength(textLine,maxWPix,paint);\n\t           \t if(endIndex<=0){\n\t           \t\tmStrList.add(textLine);\n\t           \t }else{\n\t           \t\tif(endIndex == textLine.length()-1){\n\t           \t\t\tmStrList.add(textLine);\n\t           \t\t}else{\n\t           \t\t\tmStrList.add(textLine.substring(0,endIndex+1));\n\t           \t\t}\n\t           \t\t \n\t           \t }\n\t           \t //获取剩下的\n\t           \t if(textLine.length()>endIndex+1){\n\t           \t\t //还有剩下的\n\t           \t\t textLine = textLine.substring(endIndex+1);\n\t           \t }else{\n\t           \t\t break;\n\t           \t }\n            }\n   \t     }\n        \n         return mStrList;\n     }\n     \n     /**\n      * \n      * 描述：获取这段文本多少行.\n      * @param text\n      * @param maxWPix\n      * @return\n      */\n     public static int getDrawRowCount(String text,int maxWPix,TextPaint paint) {\n    \t\n    \tString [] texts = null;\n     \tif(text.indexOf(\"\\n\")!=-1){\n     \t\t texts = text.split(\"\\n\");\n     \t}else{\n     \t\t texts  = new String [1];\n     \t\t texts[0] = text;\n     \t}\n     \t//共多少行\n     \tList<String> mStrList  = new ArrayList<String>();\n     \t\n     \tfor(int i=0;i<texts.length;i++){\n   \t\t    String textLine = texts[i];\n   \t\t    //计算这个文本显示为几行\n            while(true){\n\t           \t //可容纳的最后一个字的位置\n\t           \t int endIndex = subStringLength(textLine,maxWPix,paint);\n\t           \t if(endIndex<=0){\n\t           \t\tmStrList.add(textLine);\n\t           \t }else{\n\t           \t\tif(endIndex == textLine.length()-1){\n\t           \t\t\tmStrList.add(textLine);\n\t           \t\t}else{\n\t           \t\t\tmStrList.add(textLine.substring(0,endIndex+1));\n\t           \t\t}\n\t           \t\t \n\t           \t }\n\t           \t //获取剩下的\n\t           \t if(textLine.length()>endIndex+1){\n\t           \t\t //还有剩下的\n\t           \t\t textLine = textLine.substring(endIndex+1);\n\t           \t }else{\n\t           \t\t break;\n\t           \t }\n            }\n   \t     }\n        \n         return mStrList.size();\n     }\n     \n     /**\n      * 描述：绘制文本，支持换行.\n      *\n      * @param canvas the canvas\n      * @param text the text\n      * @param maxWPix the max w pix\n      * @param paint the paint\n      * @param left the left\n      * @param top the top\n      * @return the int\n      */\n     public static int drawText(Canvas canvas,String text,int maxWPix,TextPaint paint,int left,int top) {\n    \tif(AbStrUtil.isEmpty(text)){\n    \t\treturn 1;\n    \t}\n    \t//需要根据文字长度控制换行\n        //测量文字的长度\n    \tList<String> mStrList  = getDrawRowStr(text,maxWPix,paint);\n         \n        int hSize = (int)getDesiredHeight(paint);\n         \n        for(int i=0;i<mStrList.size();i++){\n        \t //计算坐标\n        \t int x = left;\n             int y = top+hSize/2+hSize*i;\n    \t\t String textLine = mStrList.get(i);\n             canvas.drawText(textLine,x,y, paint); \n             \n        }\n        return mStrList.size();\n     }\n     \n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbImageUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\n\nimport android.app.Activity;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.LinearGradient;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.PorterDuff.Mode;\nimport android.graphics.PorterDuffXfermode;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.Shader.TileMode;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.net.Uri;\nimport android.provider.MediaStore.MediaColumns;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.MeasureSpec;\nimport android.widget.ImageView;\n\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn 名称：AbImageUtil.java 描述：图片处理类.\n */\npublic class AbImageUtil {\n\n\t/** 图片处理：裁剪. */\n\tpublic static final int CUTIMG = 0;\n\n\t/** 图片处理：缩放. */\n\tpublic static final int SCALEIMG = 1;\n\n\t/** 图片处理：不处理. */\n\tpublic static final int ORIGINALIMG = 2;\n\n\t/** 图片最大宽度. */\n\tpublic static final int MAX_WIDTH = 4096 / 2;\n\n\t/** 图片最大高度. */\n\tpublic static final int MAX_HEIGHT = 4096 / 2;\n\t\n\t\n\n\t/**\n\t * 解析bitmap\n\t * \n\t * @param bitmap\n\t * @return\n\t */\n\tpublic static byte[] getBitmapByte(Bitmap bitmap) {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tbitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);\n\t\ttry {\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn out.toByteArray();\n\t}\n\n\t/**\n\t * 直接获取互联网上的图片.\n\t * \n\t * @param url\n\t *            要下载文件的网络地址\n\t * @param type\n\t *            图片的处理类型（剪切或者缩放到指定大小，参考AbConstant类）\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap getBitmap(String url, int type, int desiredWidth, int desiredHeight) {\n\t\tBitmap bm = null;\n\t\tURLConnection con = null;\n\t\tInputStream is = null;\n\t\ttry {\n\t\t\tURL imageURL = new URL(url);\n\t\t\tcon = imageURL.openConnection();\n\t\t\tcon.setDoInput(true);\n\t\t\tcon.connect();\n\t\t\tis = con.getInputStream();\n\t\t\t// 获取资源图片\n\t\t\tBitmap wholeBm = BitmapFactory.decodeStream(is, null, null);\n\t\t\tif (type == CUTIMG) {\n\t\t\t\tbm = cutImg(wholeBm, desiredWidth, desiredHeight);\n\t\t\t} else if (type == SCALEIMG) {\n\t\t\t\tbm = scaleImg(wholeBm, desiredWidth, desiredHeight);\n\t\t\t} else {\n\t\t\t\tbm = wholeBm;\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tAbLogUtil.d(AbImageUtil.class, \"\" + e.getMessage());\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (is != null) {\n\t\t\t\t\tis.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn bm;\n\t}\n\n\t/**\n\t * 描述：获取原图.\n\t * \n\t * @param file\n\t *            File对象\n\t * @return Bitmap 图片\n\t */\n\tpublic static Bitmap getBitmap(File file) {\n\t\tBitmap resizeBmp = null;\n\t\ttry {\n\t\t\tresizeBmp = BitmapFactory.decodeFile(file.getPath());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn resizeBmp;\n\t}\n\n\t/**\n\t * 描述：缩放图片.压缩\n\t * \n\t * @param file\n\t *            File对象\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap scaleImg(File file, int desiredWidth, int desiredHeight) {\n\n\t\tBitmap resizeBmp = null;\n\t\tBitmapFactory.Options opts = new BitmapFactory.Options();\n\t\t// 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息\n\t\topts.inJustDecodeBounds = true;\n\t\tBitmapFactory.decodeFile(file.getPath(), opts);\n\n\t\t// 获取图片的原始宽度高度\n\t\tint srcWidth = opts.outWidth;\n\t\tint srcHeight = opts.outHeight;\n\t\tint[] size = resizeToMaxSize(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tdesiredWidth = size[0];\n\t\tdesiredHeight = size[1];\n\n\t\t// 缩放的比例\n\t\tfloat scale = getMinScale(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tint destWidth = srcWidth;\n\t\tint destHeight = srcHeight;\n\t\tif (scale != 0) {\n\t\t\tdestWidth = (int) (srcWidth * scale);\n\t\t\tdestHeight = (int) (srcHeight * scale);\n\t\t}\n\n\t\t// 默认为ARGB_8888.\n\t\topts.inPreferredConfig = Bitmap.Config.RGB_565;\n\t\t// 以下两个字段需一起使用：\n\t\t// 产生的位图将得到像素空间，如果系统gc，那么将被清空。当像素再次被访问，如果Bitmap已经decode，那么将被自动重新解码\n\t\topts.inPurgeable = true;\n\t\t// 位图可以共享一个参考输入数据(inputstream、阵列等)\n\t\topts.inInputShareable = true;\n\n\t\t// inSampleSize=2 表示图片宽高都为原来的二分之一，即图片为原来的四分之一\n\t\t// 缩放的比例，SDK中建议其值是2的指数值，通过inSampleSize来进行缩放，其值表明缩放的倍数\n\t\tif (scale < 0.25) {\n\t\t\t// 缩小到4分之一\n\t\t\topts.inSampleSize = 2;\n\t\t} else if (scale < 0.125) {\n\t\t\t// 缩小到8分之一\n\t\t\topts.inSampleSize = 4;\n\t\t} else {\n\t\t\topts.inSampleSize = 1;\n\t\t}\n\n\t\t// 设置大小\n\t\topts.outWidth = destWidth;\n\t\topts.outHeight = destHeight;\n\n\t\t// 创建内存\n\t\topts.inJustDecodeBounds = false;\n\t\t// 使图片不抖动\n\t\topts.inDither = false;\n\n\t\tresizeBmp = BitmapFactory.decodeFile(file.getPath(), opts);\n\t\t// 缩小或者放大\n\t\tresizeBmp = scaleImg(resizeBmp, scale);\n\t\treturn resizeBmp;\n\t}\n\n\t/**\n\t * 描述：缩放图片,不压缩的缩放.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap scaleImg(Bitmap bitmap, int desiredWidth, int desiredHeight) {\n\n\t\tif (!checkBitmap(bitmap)) {\n\t\t\treturn null;\n\t\t}\n\t\tBitmap resizeBmp = null;\n\n\t\t// 获得图片的宽高\n\t\tint srcWidth = bitmap.getWidth();\n\t\tint srcHeight = bitmap.getHeight();\n\n\t\tint[] size = resizeToMaxSize(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tdesiredWidth = size[0];\n\t\tdesiredHeight = size[1];\n\n\t\tfloat scale = getMinScale(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tresizeBmp = scaleImg(bitmap, scale);\n\t\t// 超出的裁掉\n\t\tif (resizeBmp.getWidth() > desiredWidth || resizeBmp.getHeight() > desiredHeight) {\n\t\t\tresizeBmp = cutImg(resizeBmp, desiredWidth, desiredHeight);\n\t\t}\n\t\treturn resizeBmp;\n\t}\n\n\t/**\n\t * 描述：根据等比例缩放图片.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param scale\n\t *            比例\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap scaleImg(Bitmap bitmap, float scale) {\n\n\t\tif (!checkBitmap(bitmap)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (scale == 1) {\n\t\t\treturn bitmap;\n\t\t}\n\n\t\tBitmap resizeBmp = null;\n\t\ttry {\n\t\t\t// 获取Bitmap资源的宽和高\n\t\t\tint bmpW = bitmap.getWidth();\n\t\t\tint bmpH = bitmap.getHeight();\n\n\t\t\t// 注意这个Matirx是android.graphics底下的那个\n\t\t\tMatrix matrix = new Matrix();\n\t\t\t// 设置缩放系数，分别为原来的0.8和0.8\n\t\t\tmatrix.postScale(scale, scale);\n\t\t\tresizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bmpW, bmpH, matrix, true);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (resizeBmp != bitmap) {\n\t\t\t\tbitmap.recycle();\n\t\t\t}\n\t\t}\n\t\treturn resizeBmp;\n\t}\n\n\t/**\n\t * 描述：裁剪图片.\n\t * \n\t * @param file\n\t *            File对象\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap cutImg(File file, int desiredWidth, int desiredHeight) {\n\n\t\tBitmap resizeBmp = null;\n\n\t\tBitmapFactory.Options opts = new BitmapFactory.Options();\n\t\t// 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息\n\t\topts.inJustDecodeBounds = true;\n\t\tBitmapFactory.decodeFile(file.getPath(), opts);\n\n\t\t// 获取图片的原始宽度\n\t\tint srcWidth = opts.outWidth;\n\t\t// 获取图片原始高度\n\t\tint srcHeight = opts.outHeight;\n\n\t\tint[] size = resizeToMaxSize(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tdesiredWidth = size[0];\n\t\tdesiredHeight = size[1];\n\n\t\t// 缩放的比例\n\t\tfloat scale = getMinScale(srcWidth, srcHeight, desiredWidth, desiredHeight);\n\t\tint destWidth = srcWidth;\n\t\tint destHeight = srcHeight;\n\t\tif (scale != 1) {\n\t\t\tdestWidth = (int) (srcWidth * scale);\n\t\t\tdestHeight = (int) (srcHeight * scale);\n\t\t}\n\n\t\t// 默认为ARGB_8888.\n\t\topts.inPreferredConfig = Bitmap.Config.RGB_565;\n\t\t// 以下两个字段需一起使用：\n\t\t// 产生的位图将得到像素空间，如果系统gc，那么将被清空。当像素再次被访问，如果Bitmap已经decode，那么将被自动重新解码\n\t\topts.inPurgeable = true;\n\t\t// 位图可以共享一个参考输入数据(inputstream、阵列等)\n\t\topts.inInputShareable = true;\n\t\t// 缩放的比例，缩放是很难按准备的比例进行缩放的，通过inSampleSize来进行缩放，其值表明缩放的倍数，SDK中建议其值是2的指数值\n\t\tif (scale < 0.25) {\n\t\t\t// 缩小到4分之一\n\t\t\topts.inSampleSize = 2;\n\t\t} else if (scale < 0.125) {\n\t\t\t// 缩小\n\t\t\topts.inSampleSize = 4;\n\t\t} else {\n\t\t\topts.inSampleSize = 1;\n\t\t}\n\t\t// 设置大小\n\t\topts.outHeight = destHeight;\n\t\topts.outWidth = destWidth;\n\t\t// 创建内存\n\t\topts.inJustDecodeBounds = false;\n\t\t// 使图片不抖动\n\t\topts.inDither = false;\n\t\tBitmap bitmap = BitmapFactory.decodeFile(file.getPath(), opts);\n\t\tif (bitmap != null) {\n\t\t\tresizeBmp = cutImg(bitmap, desiredWidth, desiredHeight);\n\t\t}\n\t\treturn resizeBmp;\n\t}\n\n\t/**\n\t * 描述：裁剪图片.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param desiredWidth\n\t *            新图片的宽\n\t * @param desiredHeight\n\t *            新图片的高\n\t * @return Bitmap 新图片\n\t */\n\tpublic static Bitmap cutImg(Bitmap bitmap, int desiredWidth, int desiredHeight) {\n\n\t\tif (!checkBitmap(bitmap)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (!checkSize(desiredWidth, desiredHeight)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tBitmap resizeBmp = null;\n\n\t\ttry {\n\t\t\tint width = bitmap.getWidth();\n\t\t\tint height = bitmap.getHeight();\n\n\t\t\tint offsetX = 0;\n\t\t\tint offsetY = 0;\n\n\t\t\tif (width > desiredWidth) {\n\t\t\t\toffsetX = (width - desiredWidth) / 2;\n\t\t\t} else {\n\t\t\t\tdesiredWidth = width;\n\t\t\t}\n\n\t\t\tif (height > desiredHeight) {\n\t\t\t\toffsetY = (height - desiredHeight) / 2;\n\t\t\t} else {\n\t\t\t\tdesiredHeight = height;\n\t\t\t}\n\n\t\t\tresizeBmp = Bitmap.createBitmap(bitmap, offsetX, offsetY, desiredWidth, desiredHeight);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (resizeBmp != bitmap) {\n\t\t\t\tbitmap.recycle();\n\t\t\t}\n\t\t}\n\t\treturn resizeBmp;\n\t}\n\n\tprivate static float getMinScale(int srcWidth, int srcHeight, int desiredWidth, int desiredHeight) {\n\t\t// 缩放的比例\n\t\tfloat scale = 0;\n\t\t// 计算缩放比例，宽高的最小比例\n\t\tfloat scaleWidth = (float) desiredWidth / srcWidth;\n\t\tfloat scaleHeight = (float) desiredHeight / srcHeight;\n\t\tif (scaleWidth > scaleHeight) {\n\t\t\tscale = scaleWidth;\n\t\t} else {\n\t\t\tscale = scaleHeight;\n\t\t}\n\n\t\treturn scale;\n\t}\n\n\tprivate static int[] resizeToMaxSize(int srcWidth, int srcHeight, int desiredWidth, int desiredHeight) {\n\t\tint[] size = new int[2];\n\t\tif (desiredWidth <= 0) {\n\t\t\tdesiredWidth = srcWidth;\n\t\t}\n\t\tif (desiredHeight <= 0) {\n\t\t\tdesiredHeight = srcHeight;\n\t\t}\n\t\tif (desiredWidth > MAX_WIDTH) {\n\t\t\t// 重新计算大小\n\t\t\tdesiredWidth = MAX_WIDTH;\n\t\t\tfloat scaleWidth = (float) desiredWidth / srcWidth;\n\t\t\tdesiredHeight = (int) (desiredHeight * scaleWidth);\n\t\t}\n\n\t\tif (desiredHeight > MAX_HEIGHT) {\n\t\t\t// 重新计算大小\n\t\t\tdesiredHeight = MAX_HEIGHT;\n\t\t\tfloat scaleHeight = (float) desiredHeight / srcHeight;\n\t\t\tdesiredWidth = (int) (desiredWidth * scaleHeight);\n\t\t}\n\t\tsize[0] = desiredWidth;\n\t\tsize[1] = desiredHeight;\n\t\treturn size;\n\t}\n\n\tprivate static boolean checkBitmap(Bitmap bitmap) {\n\t\tif (bitmap == null) {\n\t\t\tAbLogUtil.e(AbImageUtil.class, \"原图Bitmap为空了\");\n\t\t\treturn false;\n\t\t}\n\n\t\tif (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {\n\t\t\tAbLogUtil.e(AbImageUtil.class, \"原图Bitmap大小为0\");\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate static boolean checkSize(int desiredWidth, int desiredHeight) {\n\t\tif (desiredWidth <= 0 || desiredHeight <= 0) {\n\t\t\tAbLogUtil.e(AbImageUtil.class, \"请求Bitmap的宽高参数必须大于0\");\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Drawable转Bitmap.\n\t * \n\t * @param drawable\n\t *            要转化的Drawable\n\t * @return Bitmap\n\t */\n\tpublic static Bitmap drawableToBitmap(Drawable drawable) {\n\t\tBitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),\n\t\t\t\tdrawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);\n\t\tCanvas canvas = new Canvas(bitmap);\n\t\tdrawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());\n\t\tdrawable.draw(canvas);\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * Bitmap对象转换Drawable对象.\n\t * \n\t * @param bitmap\n\t *            要转化的Bitmap对象\n\t * @return Drawable 转化完成的Drawable对象\n\t */\n\tpublic static Drawable bitmapToDrawable(Bitmap bitmap) {\n\t\tBitmapDrawable mBitmapDrawable = null;\n\t\ttry {\n\t\t\tif (bitmap == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tmBitmapDrawable = new BitmapDrawable(bitmap);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmapDrawable;\n\t}\n\n\t/**\n\t * Bitmap对象转换TransitionDrawable对象.\n\t * \n\t * @param bitmap\n\t *            要转化的Bitmap对象 imageView.setImageDrawable(td);\n\t *            td.startTransition(200);\n\t * @return Drawable 转化完成的Drawable对象\n\t */\n\tpublic static TransitionDrawable bitmapToTransitionDrawable(Bitmap bitmap) {\n\t\tTransitionDrawable mBitmapDrawable = null;\n\t\ttry {\n\t\t\tif (bitmap == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tmBitmapDrawable = new TransitionDrawable(\n\t\t\t\t\tnew Drawable[] { new ColorDrawable(android.R.color.transparent), new BitmapDrawable(bitmap) });\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmapDrawable;\n\t}\n\n\t/**\n\t * Drawable对象转换TransitionDrawable对象.\n\t * \n\t * @param drawable\n\t *            要转化的Drawable对象 imageView.setImageDrawable(td);\n\t *            td.startTransition(200);\n\t * @return Drawable 转化完成的Drawable对象\n\t */\n\tpublic static TransitionDrawable drawableToTransitionDrawable(Drawable drawable) {\n\t\tTransitionDrawable mBitmapDrawable = null;\n\t\ttry {\n\t\t\tif (drawable == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tmBitmapDrawable = new TransitionDrawable(\n\t\t\t\t\tnew Drawable[] { new ColorDrawable(android.R.color.transparent), drawable });\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmapDrawable;\n\t}\n\n\t/**\n\t * 将Bitmap转换为byte[].\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param mCompressFormat\n\t *            图片格式 Bitmap.CompressFormat.JPEG,CompressFormat.PNG\n\t * @param needRecycle\n\t *            是否需要回收\n\t * @return byte[] 图片的byte[]\n\t */\n\tpublic static byte[] bitmap2Bytes(Bitmap bitmap, Bitmap.CompressFormat mCompressFormat, final boolean needRecycle) {\n\t\tbyte[] result = null;\n\t\tByteArrayOutputStream output = null;\n\t\ttry {\n\t\t\toutput = new ByteArrayOutputStream();\n\t\t\tbitmap.compress(mCompressFormat, 100, output);\n\t\t\tresult = output.toByteArray();\n\t\t\tif (needRecycle) {\n\t\t\t\tbitmap.recycle();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (output != null) {\n\t\t\t\ttry {\n\t\t\t\t\toutput.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 获取Bitmap大小.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param mCompressFormat\n\t *            图片格式 Bitmap.CompressFormat.JPEG,CompressFormat.PNG\n\t * @return 图片的大小\n\t */\n\tpublic static int getByteCount(Bitmap bitmap, Bitmap.CompressFormat mCompressFormat) {\n\t\tint size = 0;\n\t\tByteArrayOutputStream output = null;\n\t\ttry {\n\t\t\toutput = new ByteArrayOutputStream();\n\t\t\tbitmap.compress(mCompressFormat, 100, output);\n\t\t\tbyte[] result = output.toByteArray();\n\t\t\tsize = result.length;\n\t\t\tresult = null;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (output != null) {\n\t\t\t\ttry {\n\t\t\t\t\toutput.close();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn size;\n\t}\n\n\t/**\n\t * 描述：将byte[]转换为Bitmap.\n\t * \n\t * @param b\n\t *            图片格式的byte[]数组\n\t * @return bitmap 得到的Bitmap\n\t */\n\tpublic static Bitmap bytes2Bimap(byte[] b) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\tif (b.length != 0) {\n\t\t\t\tbitmap = BitmapFactory.decodeByteArray(b, 0, b.length);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 将ImageView转换为Bitmap.\n\t * \n\t * @param view\n\t *            要转换为bitmap的View\n\t * @return byte[] 图片的byte[]\n\t */\n\tpublic static Bitmap imageView2Bitmap(ImageView view) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\tbitmap = Bitmap.createBitmap(view.getDrawingCache());\n\t\t\tview.setDrawingCacheEnabled(false);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 将View转换为Drawable.需要最上层布局为Linearlayout\n\t * \n\t * @param view\n\t *            要转换为Drawable的View\n\t * @return BitmapDrawable Drawable\n\t */\n\tpublic static Drawable view2Drawable(View view) {\n\t\tBitmapDrawable mBitmapDrawable = null;\n\t\ttry {\n\t\t\tBitmap newbmp = view2Bitmap(view);\n\t\t\tif (newbmp != null) {\n\t\t\t\tmBitmapDrawable = new BitmapDrawable(newbmp);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmapDrawable;\n\t}\n\n\t/**\n\t * 将View转换为Bitmap.需要最上层布局为Linearlayout\n\t * \n\t * @param view\n\t *            要转换为bitmap的View\n\t * @return byte[] 图片的byte[]\n\t */\n\tpublic static Bitmap view2Bitmap(View view) {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\tif (view != null) {\n\t\t\t\tview.setDrawingCacheEnabled(true);\n\t\t\t\tview.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),\n\t\t\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\t\t\t\tview.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());\n\t\t\t\tview.buildDrawingCache();\n\t\t\t\tbitmap = view.getDrawingCache();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 将View转换为byte[].\n\t * \n\t * @param view\n\t *            要转换为byte[]的View\n\t * @param compressFormat\n\t *            the compress format\n\t * @return byte[] View图片的byte[]\n\t */\n\tpublic static byte[] view2Bytes(View view, Bitmap.CompressFormat compressFormat) {\n\t\tbyte[] b = null;\n\t\ttry {\n\t\t\tBitmap bitmap = AbImageUtil.view2Bitmap(view);\n\t\t\tb = AbImageUtil.bitmap2Bytes(bitmap, compressFormat, true);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\t/**\n\t * 描述：旋转Bitmap为一定的角度.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param degrees\n\t *            the degrees\n\t * @return the bitmap\n\t */\n\tpublic static Bitmap rotateBitmap(Bitmap bitmap, float degrees) {\n\t\tBitmap mBitmap = null;\n\t\ttry {\n\t\t\tMatrix m = new Matrix();\n\t\t\tm.setRotate(degrees % 360);\n\t\t\tmBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, false);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmap;\n\t}\n\n\t/**\n\t * 描述：旋转Bitmap为一定的角度并四周暗化处理.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @param degrees\n\t *            the degrees\n\t * @return the bitmap\n\t */\n\tpublic static Bitmap rotateBitmapTranslate(Bitmap bitmap, float degrees) {\n\t\tBitmap mBitmap = null;\n\t\tint width;\n\t\tint height;\n\t\ttry {\n\t\t\tMatrix matrix = new Matrix();\n\t\t\tif ((degrees / 90) % 2 != 0) {\n\t\t\t\twidth = bitmap.getWidth();\n\t\t\t\theight = bitmap.getHeight();\n\t\t\t} else {\n\t\t\t\twidth = bitmap.getHeight();\n\t\t\t\theight = bitmap.getWidth();\n\t\t\t}\n\t\t\tint cx = width / 2;\n\t\t\tint cy = height / 2;\n\t\t\tmatrix.preTranslate(-cx, -cy);\n\t\t\tmatrix.postRotate(degrees);\n\t\t\tmatrix.postTranslate(cx, cy);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn mBitmap;\n\t}\n\n\t/**\n\t * 转换图片转换成圆形.\n\t * \n\t * @param bitmap\n\t *            传入Bitmap对象\n\t * @return the bitmap\n\t */\n\tpublic static Bitmap toRoundBitmap(Bitmap bitmap) {\n\t\tif (bitmap == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint width = bitmap.getWidth();\n\t\tint height = bitmap.getHeight();\n\t\tfloat roundPx;\n\t\tfloat left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;\n\t\tif (width <= height) {\n\t\t\troundPx = width / 2;\n\t\t\ttop = 0;\n\t\t\tbottom = width;\n\t\t\tleft = 0;\n\t\t\tright = width;\n\t\t\theight = width;\n\t\t\tdst_left = 0;\n\t\t\tdst_top = 0;\n\t\t\tdst_right = width;\n\t\t\tdst_bottom = width;\n\t\t} else {\n\t\t\troundPx = height / 2;\n\t\t\tfloat clip = (width - height) / 2;\n\t\t\tleft = clip;\n\t\t\tright = width - clip;\n\t\t\ttop = 0;\n\t\t\tbottom = height;\n\t\t\twidth = height;\n\t\t\tdst_left = 0;\n\t\t\tdst_top = 0;\n\t\t\tdst_right = height;\n\t\t\tdst_bottom = height;\n\t\t}\n\n\t\tBitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);\n\t\tCanvas canvas = new Canvas(output);\n\t\tfinal int color = 0xff424242;\n\t\tfinal Paint paint = new Paint();\n\t\tfinal Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);\n\t\tfinal Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);\n\t\tfinal RectF rectF = new RectF(dst);\n\t\tpaint.setAntiAlias(true);\n\t\tcanvas.drawARGB(0, 0, 0, 0);\n\t\tpaint.setColor(color);\n\t\tcanvas.drawRoundRect(rectF, roundPx, roundPx, paint);\n\t\tpaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));\n\t\tcanvas.drawBitmap(bitmap, src, dst, paint);\n\t\treturn output;\n\t}\n\n\t/**\n\t * 转换图片转换成圆形通过指定的弧度\n\t * \n\t * @param bitmap\n\t * @param roundPx\n\t * @return\n\t */\n\tpublic static Bitmap toRoundBitmap(Bitmap bitmap, float roundPx) {\n\t\tif (bitmap == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint width = bitmap.getWidth();\n\t\tint height = bitmap.getHeight();\n\t\tfloat left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;\n\t\tif (width <= height) {\n\t\t\ttop = 0;\n\t\t\tbottom = width;\n\t\t\tleft = 0;\n\t\t\tright = width;\n\t\t\theight = width;\n\t\t\tdst_left = 0;\n\t\t\tdst_top = 0;\n\t\t\tdst_right = width;\n\t\t\tdst_bottom = width;\n\t\t} else {\n\t\t\tfloat clip = (width - height) / 2;\n\t\t\tleft = clip;\n\t\t\tright = width - clip;\n\t\t\ttop = 0;\n\t\t\tbottom = height;\n\t\t\twidth = height;\n\t\t\tdst_left = 0;\n\t\t\tdst_top = 0;\n\t\t\tdst_right = height;\n\t\t\tdst_bottom = height;\n\t\t}\n\n\t\tBitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);\n\t\tCanvas canvas = new Canvas(output);\n\t\tfinal int color = 0xff424242;\n\t\tfinal Paint paint = new Paint();\n\t\tfinal Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);\n\t\tfinal Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);\n\t\tfinal RectF rectF = new RectF(dst);\n\t\tpaint.setAntiAlias(true);\n\t\tcanvas.drawARGB(0, 0, 0, 0);\n\t\tpaint.setColor(color);\n\t\tcanvas.drawRoundRect(rectF, roundPx, roundPx, paint);\n\t\tpaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));\n\t\tcanvas.drawBitmap(bitmap, src, dst, paint);\n\t\treturn output;\n\t}\n\n\t/**\n\t * 转换图片转换成镜面效果的图片.\n\t * \n\t * @param bitmap\n\t *            传入Bitmap对象\n\t * @return the bitmap\n\t */\n\tpublic static Bitmap toReflectionBitmap(Bitmap bitmap) {\n\t\tif (bitmap == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tint reflectionGap = 1;\n\t\t\tint width = bitmap.getWidth();\n\t\t\tint height = bitmap.getHeight();\n\n\t\t\t// This will not scale but will flip on the Y axis\n\t\t\tMatrix matrix = new Matrix();\n\t\t\tmatrix.preScale(1, -1);\n\n\t\t\t// Create a Bitmap with the flip matrix applied to it.\n\t\t\t// We only want the bottom half of the image\n\t\t\tBitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height / 2, width, height / 2, matrix, false);\n\n\t\t\t// Create a new bitmap with same width but taller to fit\n\t\t\t// reflection\n\t\t\tBitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Config.ARGB_8888);\n\n\t\t\t// Create a new Canvas with the bitmap that's big enough for\n\t\t\t// the image plus gap plus reflection\n\t\t\tCanvas canvas = new Canvas(bitmapWithReflection);\n\t\t\t// Draw in the original image\n\t\t\tcanvas.drawBitmap(bitmap, 0, 0, null);\n\t\t\t// Draw in the gap\n\t\t\tPaint deafaultPaint = new Paint();\n\t\t\tcanvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);\n\t\t\t// Draw in the reflection\n\t\t\tcanvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);\n\t\t\t// Create a shader that is a linear gradient that covers the\n\t\t\t// reflection\n\t\t\tPaint paint = new Paint();\n\t\t\tLinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,\n\t\t\t\t\tbitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP);\n\t\t\t// Set the paint to use this shader (linear gradient)\n\t\t\tpaint.setShader(shader);\n\t\t\t// Set the Transfer mode to be porter duff and destination in\n\t\t\tpaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));\n\t\t\t// Draw a rectangle using the paint with our linear gradient\n\t\t\tcanvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);\n\n\t\t\tbitmap = bitmapWithReflection;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\t/**\n\t * 释放Bitmap对象.\n\t * \n\t * @param bitmap\n\t *            要释放的Bitmap\n\t */\n\tpublic static void releaseBitmap(Bitmap bitmap) {\n\t\tif (bitmap != null) {\n\t\t\ttry {\n\t\t\t\tif (!bitmap.isRecycled()) {\n\t\t\t\t\tAbLogUtil.d(AbImageUtil.class, \"Bitmap释放\" + bitmap.toString());\n\t\t\t\t\tbitmap.recycle();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t\tbitmap = null;\n\t\t}\n\t}\n\n\t/**\n\t * 释放Bitmap数组.\n\t * \n\t * @param bitmaps\n\t *            要释放的Bitmap数组\n\t */\n\tpublic static void releaseBitmapArray(Bitmap[] bitmaps) {\n\t\tif (bitmaps != null) {\n\t\t\ttry {\n\t\t\t\tfor (Bitmap bitmap : bitmaps) {\n\t\t\t\t\tif (bitmap != null && !bitmap.isRecycled()) {\n\t\t\t\t\t\tAbLogUtil.d(AbImageUtil.class, \"Bitmap释放\" + bitmap.toString());\n\t\t\t\t\t\tbitmap.recycle();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 描述：简单的图像的特征值，用于缩略图找原图比较好.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @return the hash code\n\t */\n\tpublic static String getHashCode(Bitmap bitmap) {\n\t\t// 第一步，缩小尺寸。\n\t\t// 将图片缩小到8x8的尺寸，总共64个像素。这一步的作用是去除图片的细节，\n\t\t// 只保留结构、明暗等基本信息，摒弃不同尺寸、比例带来的图片差异。\n\n\t\tBitmap temp = Bitmap.createScaledBitmap(bitmap, 8, 8, false);\n\n\t\tint width = temp.getWidth();\n\t\tint height = temp.getHeight();\n\t\tLog.i(\"th\", \"将图片缩小到8x8的尺寸:\" + width + \"*\" + height);\n\n\t\t// 第二步，第二步，简化色彩。\n\t\t// 将缩小后的图片，转为64级灰度。也就是说，所有像素点总共只有64种颜色。\n\t\tint[] pixels = new int[width * height];\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tfor (int j = 0; j < height; j++) {\n\t\t\t\tpixels[i * height + j] = rgbToGray(temp.getPixel(i, j));\n\t\t\t}\n\t\t}\n\n\t\treleaseBitmap(temp);\n\n\t\t// 第三步，计算平均值。\n\t\t// 计算所有64个像素的灰度平均值。\n\t\tint avgPixel = AbMathUtil.average(pixels);\n\n\t\t// 第四步，比较像素的灰度。\n\t\t// 将每个像素的灰度，与平均值进行比较。大于或等于平均值，记为1；小于平均值，记为0。\n\t\tint[] comps = new int[width * height];\n\t\tfor (int i = 0; i < comps.length; i++) {\n\t\t\tif (pixels[i] >= avgPixel) {\n\t\t\t\tcomps[i] = 1;\n\t\t\t} else {\n\t\t\t\tcomps[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\t// 第五步，计算哈希值。\n\t\t// 将上一步的比较结果，组合在一起，就构成了一个64位的整数，\n\t\t// 这就是这张图片的指纹。\n\t\tStringBuffer hashCode = new StringBuffer();\n\t\tfor (int i = 0; i < comps.length; i += 4) {\n\t\t\tint result = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2)\n\t\t\t\t\t+ comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 2];\n\t\t\thashCode.append(AbMathUtil.binaryToHex(result));\n\t\t}\n\t\tString sourceHashCode = hashCode.toString();\n\t\t// 得到指纹以后，就可以对比不同的图片，看看64位中有多少位是不一样的。\n\t\t// 在理论上，这等同于计算\"汉明距离\"（Hamming distance）。\n\t\t// 如果不相同的数据位不超过5，就说明两张图片很相似；如果大于10，就说明这是两张不同的图片。\n\t\treturn sourceHashCode;\n\t}\n\n\t/**\n\t * 描述：图像的特征值颜色分布 将颜色分4个区，0,1,2,3 区组合共64组，计算每个像素点属于哪个区.\n\t * \n\t * @param bitmap\n\t *            the bitmap\n\t * @return the color histogram\n\t */\n\tpublic static int[] getColorHistogram(Bitmap bitmap) {\n\n\t\tint width = bitmap.getWidth();\n\t\tint height = bitmap.getHeight();\n\t\t// 区颜色分布\n\t\tint[] areaColor = new int[64];\n\n\t\t// 获取色彩数组。\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tfor (int j = 0; j < height; j++) {\n\t\t\t\tint pixels = bitmap.getPixel(i, j);\n\t\t\t\tint alpha = (pixels >> 24) & 0xFF;\n\t\t\t\tint red = (pixels >> 16) & 0xFF;\n\t\t\t\tint green = (pixels >> 8) & 0xFF;\n\t\t\t\tint blue = (pixels) & 0xFF;\n\t\t\t\tint redArea = 0;\n\t\t\t\tint greenArea = 0;\n\t\t\t\tint blueArea = 0;\n\t\t\t\t// 0-63 64-127 128-191 192-255\n\t\t\t\tif (red >= 192) {\n\t\t\t\t\tredArea = 3;\n\t\t\t\t} else if (red >= 128) {\n\t\t\t\t\tredArea = 2;\n\t\t\t\t} else if (red >= 64) {\n\t\t\t\t\tredArea = 1;\n\t\t\t\t} else if (red >= 0) {\n\t\t\t\t\tredArea = 0;\n\t\t\t\t}\n\n\t\t\t\tif (green >= 192) {\n\t\t\t\t\tgreenArea = 3;\n\t\t\t\t} else if (green >= 128) {\n\t\t\t\t\tgreenArea = 2;\n\t\t\t\t} else if (green >= 64) {\n\t\t\t\t\tgreenArea = 1;\n\t\t\t\t} else if (green >= 0) {\n\t\t\t\t\tgreenArea = 0;\n\t\t\t\t}\n\n\t\t\t\tif (blue >= 192) {\n\t\t\t\t\tblueArea = 3;\n\t\t\t\t} else if (blue >= 128) {\n\t\t\t\t\tblueArea = 2;\n\t\t\t\t} else if (blue >= 64) {\n\t\t\t\t\tblueArea = 1;\n\t\t\t\t} else if (blue >= 0) {\n\t\t\t\t\tblueArea = 0;\n\t\t\t\t}\n\t\t\t\tint index = redArea * 16 + greenArea * 4 + blueArea;\n\t\t\t\t// 加入\n\t\t\t\tareaColor[index] += 1;\n\t\t\t}\n\t\t}\n\t\treturn areaColor;\n\t}\n\n\t/**\n\t * 计算\"汉明距离\"（Hamming distance）。\n\t * 如果不相同的数据位不超过5，就说明两张图片很相似；如果大于10，就说明这是两张不同的图片。.\n\t * \n\t * @param sourceHashCode\n\t *            源hashCode\n\t * @param hashCode\n\t *            与之比较的hashCode\n\t * @return the int\n\t */\n\tpublic static int hammingDistance(String sourceHashCode, String hashCode) {\n\t\tint difference = 0;\n\t\tint len = sourceHashCode.length();\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\tif (sourceHashCode.charAt(i) != hashCode.charAt(i)) {\n\t\t\t\tdifference++;\n\t\t\t}\n\t\t}\n\t\treturn difference;\n\t}\n\n\t/**\n\t * 灰度值计算.\n\t * \n\t * @param pixels\n\t *            像素\n\t * @return int 灰度值\n\t */\n\tprivate static int rgbToGray(int pixels) {\n\t\t// int _alpha = (pixels >> 24) & 0xFF;\n\t\tint _red = (pixels >> 16) & 0xFF;\n\t\tint _green = (pixels >> 8) & 0xFF;\n\t\tint _blue = (pixels) & 0xFF;\n\t\treturn (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);\n\t}\n\n\t/**\n\t * 压缩图片\n\t * \n\t * @param sourcePath\n\t *            目标路径\n\t * @param targetPath\n\t *            压缩完图片路径\n\t * @param maxSize\n\t *            压缩后大小\n\t */\n\tpublic static void compressBitmap(String sourcePath, String targetPath, float maxSize) {\n\t\tBitmapFactory.Options options = new BitmapFactory.Options();\n\t\toptions.inJustDecodeBounds = true;\n\n\t\tBitmapFactory.decodeFile(sourcePath, options);\n\n\t\tfinal float originalWidth = options.outWidth;\n\t\tfinal float originalHeight = options.outHeight;\n\n\t\tfloat convertedWidth;\n\t\tfloat convertedHeight;\n\n\t\tif (originalWidth > originalHeight) {\n\t\t\tconvertedWidth = maxSize;\n\t\t\tconvertedHeight = maxSize / originalWidth * originalHeight;\n\t\t} else {\n\t\t\tconvertedHeight = maxSize;\n\t\t\tconvertedWidth = maxSize / originalHeight * originalWidth;\n\t\t}\n\n\t\tfinal float ratio = originalWidth / convertedWidth;\n\n\t\toptions.inSampleSize = (int) ratio;\n\t\toptions.inJustDecodeBounds = false;\n\n\t\tBitmap convertedBitmap = BitmapFactory.decodeFile(sourcePath, options);\n\t\tByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n\t\tconvertedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);\n\t\tFileOutputStream fileOutputStream;\n\t\ttry {\n\t\t\tFile file = new File(targetPath);\n\t\t\tif (!file.exists()) {\n\t\t\t\tfile.mkdirs();\n\t\t\t}\n\t\t\tfileOutputStream = new FileOutputStream(new File(targetPath));\n\t\t\tfileOutputStream.write(byteArrayOutputStream.toByteArray());\n\t\t\tfileOutputStream.flush();\n\t\t\tfileOutputStream.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 根据URI获取图片物理路径\n\t */\n\tpublic static String getAbsoluteImagePath(Uri uri, Activity activity) {\n\t\tString[] proj = { MediaColumns.DATA };\n\t\tCursor cursor = activity.managedQuery(uri, proj, null, null, null);\n\t\tint column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);\n\t\tcursor.moveToFirst();\n\t\treturn cursor.getString(column_index);\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbLogUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport java.util.Calendar;\n\nimport android.content.Context;\nimport android.util.Log;\n\n// TODO: Auto-generated Javadoc\n/**\n * © 2012 amsoft.cn\n * 名称：AbLogUtil.java \n * 描述：日志工具类.\n */\npublic class AbLogUtil {\n\t\n    /** debug开关. */\n\tpublic static boolean D = true;\n\t\n\t/** info开关. */\n\tpublic static boolean I = true;\n\t\n\t/** error开关. */\n\tpublic static boolean E = true;\n\t\n\t/** 起始执行时间. */\n\tpublic static long startLogTimeInMillis = 0;\n\n\t/**\n\t * debug日志\n\t * @param tag\n\t * @param message\n\t */\n\tpublic static void d(String tag,String message) {\n\t\tif(D) Log.d(tag, message);\n\t}\n\t\n\t/**\n\t * debug日志\n\t * @param context\n\t * @param message\n\t */\n\tpublic static void d(Context context,String message) {\n\t\tString tag = context.getClass().getSimpleName();\n\t\td(tag, message);\n\t}\n\t\n\t/**\n\t * debug日志\n\t * @param clazz\n\t * @param message\n\t */\n\tpublic static void d(Class<?> clazz,String message) {\n\t\tString tag = clazz.getSimpleName();\n\t\td(tag, message);\n\t}\n\t\n\t/**\n\t * info日志\n\t * @param tag\n\t * @param message\n\t */\n\tpublic static void i(String tag,String message) {\n\t\tLog.i(tag, message);\n\t}\n\t\n\t/**\n\t * info日志\n\t * @param context\n\t * @param message\n\t */\n\tpublic static void i(Context context,String message) {\n\t\tString tag = context.getClass().getSimpleName();\n\t\ti(tag, message);\n\t}\n\t\n\t/**\n\t * info日志\n\t * @param clazz\n\t * @param message\n\t */\n\tpublic static void i(Class<?> clazz,String message) {\n\t\tString tag = clazz.getSimpleName();\n\t\ti(tag, message);\n\t}\n\t\n\t\n\t\n\t/**\n\t * error日志\n\t * @param tag\n\t * @param message\n\t */\n\tpublic static void e(String tag,String message) {\n\t\tLog.e(tag, message);\n\t}\n\t\n\t/**\n\t * error日志\n\t * @param context\n\t * @param message\n\t */\n\tpublic static void e(Context context,String message) {\n\t\tString tag = context.getClass().getSimpleName();\n\t\te(tag, message);\n\t}\n\t\n\t/**\n\t * error日志\n\t * @param clazz\n\t * @param message\n\t */\n\tpublic static void e(Class<?> clazz,String message) {\n\t\tString tag = clazz.getSimpleName();\n\t\te(tag, message);\n\t}\n\t\n\t/**\n\t * 描述：记录当前时间毫秒.\n\t * \n\t */\n\tpublic static void prepareLog(String tag) {\n\t\tCalendar current = Calendar.getInstance();\n\t\tstartLogTimeInMillis = current.getTimeInMillis();\n\t\tLog.d(tag,\"日志计时开始：\"+startLogTimeInMillis);\n\t}\n\t\n\t/**\n\t * 描述：记录当前时间毫秒.\n\t * \n\t */\n\tpublic static void prepareLog(Context context) {\n\t\tString tag = context.getClass().getSimpleName();\n\t\tprepareLog(tag);\n\t}\n\t\n\t/**\n\t * 描述：记录当前时间毫秒.\n\t * \n\t */\n\tpublic static void prepareLog(Class<?> clazz) {\n\t\tString tag = clazz.getSimpleName();\n\t\tprepareLog(tag);\n\t}\n\t\n\t/**\n\t * 描述：打印这次的执行时间毫秒，需要首先调用prepareLog().\n\t *\n\t * @param tag 标记\n\t * @param message 描述\n\t * @param printTime 是否打印时间\n\t */\n\tpublic static void d(String tag, String message,boolean printTime) {\n\t\tCalendar current = Calendar.getInstance();\n\t\tlong endLogTimeInMillis = current.getTimeInMillis();\n\t\tLog.d(tag,message+\":\"+(endLogTimeInMillis-startLogTimeInMillis)+\"ms\");\n\t}\n\t\n\t\n\t/**\n\t * 描述：打印这次的执行时间毫秒，需要首先调用prepareLog().\n\t *\n\t * @param tag 标记\n\t * @param message 描述\n\t * @param printTime 是否打印时间\n\t */\n\tpublic static void d(Context context,String message,boolean printTime) {\n\t\tString tag = context.getClass().getSimpleName();\n\t    d(tag,message,printTime);\n\t}\n\t\n\t/**\n\t * 描述：打印这次的执行时间毫秒，需要首先调用prepareLog().\n\t *\n\t * @param clazz 标记\n\t * @param message 描述\n\t * @param printTime 是否打印时间\n\t */\n\tpublic static void d(Class<?> clazz,String message,boolean printTime) {\n\t\tString tag = clazz.getSimpleName();\n\t\td(tag,message,printTime);\n\t}\n\n\t/**\n\t * debug日志的开关\n\t * @param d\n\t */\n\tpublic static void debug(boolean d) {\n\t\tD  = d;\n\t}\n\t\n\t/**\n\t * info日志的开关\n\t * @param i\n\t */\n\tpublic static void info(boolean i) {\n\t\tI  = i;\n\t}\n\t\n\t/**\n\t * error日志的开关\n\t * @param e\n\t */\n\tpublic static void error(boolean e) {\n\t\tE  = e;\n\t}\n\t\n\t/**\n\t * 设置日志的开关\n\t * @param e\n\t */\n\tpublic static void setVerbose(boolean d,boolean i,boolean e) {\n\t\tD  = d;\n\t\tI  = i;\n\t\tE  = e;\n\t}\n\t\n\t/**\n\t * 打开所有日志，默认全打开\n\t * @param d\n\t */\n\tpublic static void openAll() {\n\t\tD  = true;\n\t\tI  = true;\n\t\tE  = true;\n\t}\n\t\n\t/**\n\t * 关闭所有日志\n\t * @param d\n\t */\n\tpublic static void closeAll() {\n\t\tD  = false;\n\t\tI  = false;\n\t\tE  = false;\n\t}\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbMathUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport java.math.BigDecimal;\n\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn\n * 名称：AbMathUtil.java \n * 描述：数学处理类.\n */\npublic class AbMathUtil{\n\n  /**\n   * 四舍五入.\n   *\n   * @param number  原数\n   * @param decimal 保留几位小数\n   * @return 四舍五入后的值\n   */\n  public static BigDecimal round(double number, int decimal){\n    return new BigDecimal(number).setScale(decimal, BigDecimal.ROUND_HALF_UP);\n  }\n  \n  /**\n   * 描述：字节数组转换成16进制串.\n   *\n   * @param b the b\n   * @param length the length\n   * @return the string\n   */\n  public static String byte2HexStr(byte[] b, int length){\n    String hs = \"\";\n    String stmp = \"\";\n    for (int n = 0; n < length; ++n) {\n      stmp = Integer.toHexString(b[n] & 0xFF);\n      if (stmp.length() == 1)\n        hs = hs + \"0\" + stmp;\n      else {\n        hs = hs + stmp;\n      }\n      hs = hs + \",\";\n    }\n    return hs.toUpperCase();\n  } \n  \n  /**\n   * 二进制转为十六进制.\n   *\n   * @param binary the binary\n   * @return char hex\n   */\n\tpublic static char binaryToHex(int binary) {\n\t\tchar ch = ' ';\n\t\tswitch (binary){\n\t\tcase 0:\n\t\t\tch = '0';\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tch = '1';\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tch = '2';\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tch = '3';\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tch = '4';\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tch = '5';\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tch = '6';\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tch = '7';\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tch = '8';\n\t\t\tbreak;\n\t\tcase 9:\n\t\t\tch = '9';\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\tch = 'a';\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tch = 'b';\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tch = 'c';\n\t\t\tbreak;\n\t\tcase 13:\n\t\t\tch = 'd';\n\t\t\tbreak;\n\t\tcase 14:\n\t\t\tch = 'e';\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\tch = 'f';\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tch = ' ';\n\t\t}\n\t\treturn ch;\n\t}\n\t\n\t\n\t/**\n\t *  \n\t * 一维数组转为二维数组 \n\t *  \n\t *\n\t * @param m the m\n\t * @param width the width\n\t * @param height the height\n\t * @return the int[][]\n\t */  \n    public static int[][] arrayToMatrix(int[] m, int width, int height) {  \n        int[][] result = new int[height][width];  \n        for (int i = 0; i < height; i++) {  \n            for (int j = 0; j < width; j++) {  \n                int p = j * height + i;  \n                result[i][j] = m[p];  \n            }  \n        }  \n        return result;  \n    }  \n\n\t\n\t/**\n\t *  \n\t * 二维数组转为一维数组 \n\t *  \n\t *\n\t * @param m the m\n\t * @return the double[]\n\t */  \n    public static double[] matrixToArray(double[][] m) {  \n        int p = m.length * m[0].length;  \n        double[] result = new double[p];  \n        for (int i = 0; i < m.length; i++) {  \n            for (int j = 0; j < m[i].length; j++) {  \n                int q = j * m.length + i;  \n                result[q] = m[i][j];  \n            }  \n        }  \n        return result;  \n    }  \n\n    /**\n     * 描述：int数组转换为double数组.\n     *\n     * @param input the input\n     * @return the double[]\n     */\n    public static double[] intToDoubleArray(int[] input) {  \n        int length = input.length;  \n        double[] output = new double[length];  \n        for (int i = 0; i < length; i++){  \n            output[i] = Double.valueOf(String.valueOf(input[i]));  \n        }\n        return output;  \n    }  \n    \n    /**\n     * 描述：int二维数组转换为double二维数组.\n     *\n     * @param input the input\n     * @return the double[][]\n     */\n    public static double[][] intToDoubleMatrix(int[][] input) {  \n        int height = input.length;  \n        int width = input[0].length;  \n        double[][] output = new double[height][width];  \n        for (int i = 0; i < height; i++) {  \n            // 列   \n            for (int j = 0; j < width; j++) {  \n                // 行   \n                output[i][j] = Double.valueOf(String.valueOf(input[i][j]));  \n            }  \n        }  \n        return output;  \n    }  \n\n    /**\n     * 计算数组的平均值.\n     *\n     * @param pixels 数组\n     * @return int 平均值\n     */\n    public static int average(int[] pixels) {\n\t\tfloat m = 0;\n\t\tfor (int i = 0; i < pixels.length; ++i) {\n\t\t\tm += pixels[i];\n\t\t}\n\t\tm = m / pixels.length;\n\t\treturn (int) m;\n\t}\n    \n    /**\n     * 计算数组的平均值.\n     *\n     * @param pixels 数组\n     * @return int 平均值\n     */\n    public static int average(double[] pixels) {\n\t\tfloat m = 0;\n\t\tfor (int i = 0; i < pixels.length; ++i) {\n\t\t\tm += pixels[i];\n\t\t}\n\t\tm = m / pixels.length;\n\t\treturn (int) m;\n\t}\n    \n    /**\n     * \n     * 描述：点在直线上.\n     * 点A（x，y）,B(x1,y1),C(x2,y2) 点A在直线BC上吗?\n     * @param x\n     * @param y\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @return\n     */\n    public boolean pointAtSLine(double x,double y,double x1,double y1,double x2,double y2){\n        double result = ( x - x1 ) * ( y2 - y1 ) - ( y - y1 ) * ( x2 - x1 );\n    \tif(result==0){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n    }\n    \n    \n\t/**\n\t * \n\t * 描述：点在线段上.\n\t * 点A（x，y）,B(x1,y1),C(x2,y2)   点A在线段BC上吗?\n\t * @param x\n\t * @param y\n\t * @param x1\n\t * @param y1\n\t * @param x2\n\t * @param y2\n\t * @return\n\t */\n    public static boolean pointAtELine(double x,double y,double x1,double y1,double x2,double y2){\n    \tdouble result = ( x - x1 ) * ( y2 - y1 ) - ( y - y1 ) * ( x2 - x1 );\n    \tif(result==0){\n    \t\tif(x >= Math.min(x1, x2) && x <= Math.max(x1,x2) \n    \t\t    && y >= Math.min(y1, y2) && y <= Math.max(y1,y2)){\n    \t\t    return true;\n\t    \t}else{\n\t    \t    return false;\n\t    \t}\n    \t}else{\n    \t\treturn false;\n    \t}\n    }\n    \n    /**\n     * \n     * 描述：两条直线相交.\n     * 点A（x1，y1）,B(x2,y2),C(x3,y3),D(x4,y4)   直线AB与直线CD相交吗?\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @param x3\n     * @param y3\n     * @param x4\n     * @param y4\n     * @return\n     */\n    public  static boolean LineAtLine(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){\n\t    double k1 = ( y2-y1 )/(x2-x1);\n\t    double k2 = ( y4-y3 )/(x4-x3);\n\t\tif(k1==k2){\n\t\t\t//System.out.println(\"平行线\");\n\t\t\treturn false;\n\t\t}else{\n\t\t  double x = ((x1*y2-y1*x2)*(x3-x4)-(x3*y4-y3*x4)*(x1-x2))/((y2-y1)*(x3-x4)-(y4-y3)*(x1-x2));\n\t\t  double y = ( x1*y2-y1*x2 - x*(y2-y1) ) / (x1-x2);\n\t\t  //System.out.println(\"直线的交点(\"+x+\",\"+y+\")\");\n\t\t  return true;\n\t\t}\n\t}\n    \n    /**\n     * \n     * 描述：线段与线段相交.\n     * 点A（x1，y1）,B(x2,y2),C(x3,y3),D(x4,y4)   \n     * 线段AB与线段CD相交吗?\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @param x3\n     * @param y3\n     * @param x4\n     * @param y4\n     * @return\n     */\n    public static boolean eLineAtELine(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){\n\t\t    double k1 = ( y2-y1 )/(x2-x1);\n\t\t    double k2 = ( y4-y3 )/(x4-x3);\n\t\t\tif(k1==k2){\n\t\t\t\t//System.out.println(\"平行线\");\n\t\t\t\treturn false;\n\t\t\t}else{\n\t\t\t  double x = ((x1*y2-y1*x2)*(x3-x4)-(x3*y4-y3*x4)*(x1-x2))/((y2-y1)*(x3-x4)-(y4-y3)*(x1-x2));\n\t\t\t  double y = ( x1*y2-y1*x2 - x*(y2-y1) ) / (x1-x2);\n\t\t\t  //System.out.println(\"直线的交点(\"+x+\",\"+y+\")\");\n\t\t\t  if(x >= Math.min(x1, x2) && x <= Math.max(x1,x2) \n\t\t\t\t\t  && y >= Math.min(y1, y2) && y <= Math.max(y1,y2)\n\t\t\t\t      && x >= Math.min(x3, x4) && x <= Math.max(x3,x4) \n\t\t\t\t      && y >= Math.min(y3, y4) && y <= Math.max(y3,y4) ){\n\t\t\t\t\t//System.out.println(\"交点（\"+x+\",\"+y+\"）在线段上\");\n\t\t\t\treturn true;\n\t\t\t  }else{\n\t\t\t\t//System.out.println(\"交点（\"+x+\",\"+y+\"）不在线段上\");\n\t\t\t\treturn false;\n\t\t\t  } \n\t       }\n\t}\n    \n    /**\n     * \n     * 描述：线段直线相交.\n     * 点A（x1，y1）,B(x2,y2),C(x3,y3),D(x4,y4)   \n     * 线段AB与直线CD相交吗?\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @param x3\n     * @param y3\n     * @param x4\n     * @param y4\n     * @return\n     */\n    public static boolean eLineAtLine(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){\n\t\t    double k1 = ( y2-y1 )/(x2-x1);\n\t\t    double k2 = ( y4-y3 )/(x4-x3);\n\t\t\tif(k1==k2){\n\t\t\t\t//System.out.println(\"平行线\");\n\t\t\t\treturn false;\n\t\t\t}else{\n\t\t\t  double x = ((x1*y2-y1*x2)*(x3-x4)-(x3*y4-y3*x4)*(x1-x2))/((y2-y1)*(x3-x4)-(y4-y3)*(x1-x2));\n\t\t\t  double y = ( x1*y2-y1*x2 - x*(y2-y1) ) / (x1-x2);\n\t\t\t  //System.out.println(\"交点(\"+x+\",\"+y+\")\");\n\t\t\t  if(x >= Math.min(x1, x2) && x <= Math.max(x1,x2) \n\t\t\t\t\t  && y >= Math.min(y1, y2) && y <= Math.max(y1,y2)){\n\t\t\t\t\t//System.out.println(\"交点（\"+x+\",\"+y+\"）在线段上\");\n\t\t\t\t  return true;\n\t\t\t  }else{\n\t\t\t\t\t\t\t//System.out.println(\"交点（\"+x+\",\"+y+\"）不在线段上\");\n\t\t\t\treturn false;\n\t\t\t  } \n\t\t}\n\t}\n    \n    /**\n     * \n     * 描述：点在矩形内.\n     * 矩形的边都是与坐标系平行或垂直的。\n     * 只要判断该点的横坐标和纵坐标是否夹在矩形的左右边和上下边之间。\n     * 点A（x，y）,B(x1,y1),C(x2,y2)   点A在以直线BC为对角线的矩形中吗?\n     * @param x\n     * @param y\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @return\n     */\n    public static boolean pointAtRect(double x,double y,double x1,double y1,double x2,double y2){\n\t      if(x >= Math.min(x1, x2) && x <= Math.max(x1,x2) && y >= Math.min(y1, y2) && y <= Math.max(y1,y2)){\n    \t     //System.out.println(\"点（\"+x+\",\"+y+\"）在矩形内上\");\n    \t     return true;\n\t      }else{\n\t    \t //System.out.println(\"点（\"+x+\",\"+y+\"）不在矩形内上\");\n\t    \t return false;\n\t\t  }\n\t}\n    \n    /**\n     * \n     * 描述：矩形在矩形内.\n     * 只要对角线的两点都在另一个矩形中就可以了.\n     * 点A(x1,y1),B(x2,y2)，C(x1,y1),D(x2,y2) 以直线AB为对角线的矩形在以直线BC为对角线的矩形中吗?\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @param x3\n     * @param y3\n     * @param x4\n     * @param y4\n     * @return\n     */\n    public static boolean rectAtRect(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){\n\t      if(x1 >= Math.min(x3, x4) && x1 <= Math.max(x3,x4) \n\t\t\t  && y1 >= Math.min(y3, y4) && y1 <= Math.max(y3,y4)\n\t\t\t  && x2 >= Math.min(x3, x4) && x2 <= Math.max(x3,x4) \n\t\t\t  && y2 >= Math.min(y3, y4) && y2 <= Math.max(y3,y4)){\n    \t     //System.out.println(\"矩形在矩形内\");\n    \t     return true;\n\t      }else{\n    \t     //System.out.println(\"矩形不在矩形内\");\n    \t     return false;\n\t\t  }\n\t}\n    \n    /**\n     * \n     * 描述：圆心在矩形内 .\n     * 圆心在矩形中且圆的半径小于等于圆心到矩形四边的距离的最小值。\n     * 圆心(x,y) 半径r  矩形对角点A（x1，y1），B(x2，y2)\n     * @param x\n     * @param y\n     * @param r\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @return\n     */\n    public static boolean circleAtRect(double x,double y,double r,double x1,double y1,double x2,double y2){\n\t\t//圆心在矩形内   \n\t\tif(x >= Math.min(x1, x2) && x <= Math.max(x1,x2) \n\t\t\t\t\t\t  && y >= Math.min(y1, y2) && y <= Math.max(y1,y2)){\n\t\t//圆心到4条边的距离\t\t  \n        double l1= Math.abs(x-x1);\n\t\tdouble l2= Math.abs(y-y2);\n\t\tdouble l3= Math.abs(x-x2);\n\t\tdouble l4= Math.abs(y-y2);\n    \tif(r<=l1 && r<=l2 && r<=l3 && r<=l4){\n    \t\t  //System.out.println(\"圆在矩形内\");\n\t    \t  return true;\n    \t  }else{\n    \t\t  //System.out.println(\"圆不在矩形内\");\n\t    \t  return false;\n    \t  }\n    \t \n       }else{\n    \t     //System.out.println(\"圆不在矩形内\");\n    \t    return false;\n\t   }\n\t}\n\n    /**\n     *  \n     * 描述：获取两点间的距离.\n     * @param x1\n     * @param y1\n     * @param x2\n     * @param y2\n     * @return\n     */\n    public static double getDistance(double x1,double y1,double x2,double y2) {  \n    \tdouble x = x1 - x2;  \n    \tdouble y = y1 - y2;  \n        return Math.sqrt(x * x + y * y);  \n    }  \n    \n    \n    /**\n\t * 矩形碰撞检测 参数为x,y,width,height\n\t * @param x1 第一个矩形的x\n\t * @param y1 第一个矩形的y\n\t * @param w1 第一个矩形的w\n\t * @param h1 第一个矩形的h\n\t * @param x2 第二个矩形的x\n\t * @param y2 第二个矩形的y\n\t * @param w2 第二个矩形的w\n\t * @param h2 第二个矩形的h\n\t * @return 是否碰撞\n\t */\n\tpublic static boolean isRectCollision(float x1, float y1, float w1,\n\t\t\tfloat h1, float x2, float y2, float w2, float h2) {\n\t\tif (x2 > x1 && x2 > x1 + w1) {\n\t\t\treturn false;\n\t\t} else if (x2 < x1 && x2 < x1 - w2) {\n\t\t\treturn false;\n\t\t} else if (y2 > y1 && y2 > y1 + h1) {\n\t\t\treturn false;\n\t\t} else if (y2 < y1 && y2 < y1 - h2) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t}\n \n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbMd5.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport java.security.MessageDigest;\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn 名称：AbMd5.java 描述：MD5加密.\n *\n */\npublic class AbMd5 {\n\n\t/**\n\t * 描述：MD5加密.\n\t * \n\t * @param str\n\t *            要加密的字符串\n\t * @return String 加密的字符串\n\t */\n\tpublic final static String MD5(String str) {\n\t\tchar hexDigits[] = { // 用来将字节转换成 16 进制表示的字符\n\t\t\t\t'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\t\ttry {\n\t\t\tbyte[] strTemp = str.getBytes();\n\t\t\tMessageDigest mdTemp = MessageDigest.getInstance(\"MD5\");\n\t\t\tmdTemp.update(strTemp);\n\t\t\tbyte tmp[] = mdTemp.digest(); // MD5 的计算结果是一个 128 位的长整数，\n\t\t\t// 用字节表示就是 16 个字节\n\t\t\tchar strs[] = new char[16 * 2]; // 每个字节用 16 进制表示的话，使用两个字符，\n\t\t\t// 所以表示成 16 进制需要 32 个字符\n\t\t\tint k = 0; // 表示转换结果中对应的字符位置\n\t\t\tfor (int i = 0; i < 16; i++) { // 从第一个字节开始，对 MD5 的每一个字节\n\t\t\t\t// 转换成 16 进制字符的转换\n\t\t\t\tbyte byte0 = tmp[i]; // 取第 i 个字节\n\t\t\t\tstrs[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,\n\t\t\t\t// >>> 为逻辑右移，将符号位一起右移\n\t\t\t\tstrs[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换\n\t\t\t}\n\t\t\t// return new String(strs).toUpperCase(); // 换后的结果转换为字符串\n\t\t\t return new String(strs).toLowerCase(); // 换后的结果转换为字符串\n\t\t} catch (Exception e) {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbSharedUtil.java",
    "content": "package com.ab.util;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\n\nimport com.ab.global.AbAppConfig;\n\n//TODO: Auto-generated Javadoc\n\n/**\n* © 2012 amsoft.cn\n* 名称：AbSharedUtil.java \n* 描述：保存到 SharedPreferences 的数据.    \n*\n*/\npublic class AbSharedUtil {\n\n\tprivate static final String SHARED_PATH = AbAppConfig.SHARED_PATH;\n\n\tpublic static SharedPreferences getDefaultSharedPreferences(Context context) {\n\t\treturn context.getSharedPreferences(SHARED_PATH, Context.MODE_PRIVATE);\n\t}\n\t\n\tpublic static void putInt(Context context,String key, int value) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\tEditor edit = sharedPreferences.edit();\n\t\tedit.putInt(key, value);\n\t\tedit.commit();\n\t}\n\n\tpublic static int getInt(Context context,String key) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\treturn sharedPreferences.getInt(key, 0);\n\t}\n\t\n\tpublic static void putString(Context context,String key, String value) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\tEditor edit = sharedPreferences.edit();\n\t\tedit.putString(key, value);\n\t\tedit.commit();\n\t}\n\n\tpublic static String getString(Context context,String key) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\treturn sharedPreferences.getString(key,null);\n\t}\n\t\n\tpublic static void putBoolean(Context context,String key, boolean value) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\tEditor edit = sharedPreferences.edit();\n\t\tedit.putBoolean(key, value);\n\t\tedit.commit();\n\t}\n\n\tpublic static boolean getBoolean(Context context,String key,boolean defValue) {\n\t\tSharedPreferences sharedPreferences = getDefaultSharedPreferences(context);\n\t\treturn sharedPreferences.getBoolean(key,defValue);\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbStrUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport android.content.Context;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.style.ForegroundColorSpan;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n\n// TODO: Auto-generated Javadoc\n\n/**\n * © 2012 amsoft.cn\n * 名称：AbStrUtil.java\n * 描述：字符串处理类.\n */\npublic class AbStrUtil {\n\n\n    /**\n     * 给填写搜索单词的关键词显示 特殊颜色\n     *\n     * @param word\n     * @return\n     */\n    public static SpannableStringBuilder changeTextColor(String word, String input, int color, Context context) {\n        int len = input.length();\n        int start = 0;\n        int end = 0;\n        int position = 0;\n        SpannableStringBuilder style = new SpannableStringBuilder(word);\n        while (true) {\n            position = word.indexOf(input, end);\n            if (-1 == position) {\n                break;\n            }\n            start = position;\n            end = start + len;\n            style.setSpan(new ForegroundColorSpan(context.getResources().getColor(color)), start, end,\n                    Spannable.SPAN_EXCLUSIVE_INCLUSIVE);\n        }\n        return style;\n    }\n\n    /**\n     * 描述：将null转化为“”.\n     *\n     * @param str 指定的字符串\n     * @return 字符串的String类型\n     */\n    public static String parseEmpty(String str) {\n        if (str == null || \"null\".equals(str.trim())) {\n            str = \"\";\n        }\n        return str.trim();\n    }\n\n    /**\n     * 描述：判断一个字符串是否为null或空值.\n     *\n     * @param str 指定的字符串\n     * @return true or false\n     */\n    public static boolean isEmpty(String str) {\n        return str == null || str.trim().length() == 0 || str.equals(\"null\");\n    }\n\n    /**\n     * 集合是否为空\n     *\n     * @param list\n     * @return\n     */\n    public static boolean isEmpty(List list) {\n        if (list != null && list.size() > 0) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 获取字符串中文字符的长度（每个中文算2个字符）.\n     *\n     * @param str 指定的字符串\n     * @return 中文字符的长度\n     */\n    public static int chineseLength(String str) {\n        int valueLength = 0;\n        String chinese = \"[\\u0391-\\uFFE5]\";\n        /* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */\n        if (!isEmpty(str)) {\n            for (int i = 0; i < str.length(); i++) {\n                /* 获取一个字符 */\n                String temp = str.substring(i, i + 1);\n                /* 判断是否为中文字符 */\n                if (temp.matches(chinese)) {\n                    valueLength += 2;\n                }\n            }\n        }\n        return valueLength;\n    }\n\n    /**\n     * 描述：获取字符串的长度.\n     *\n     * @param str 指定的字符串\n     * @return 字符串的长度（中文字符计2个）\n     */\n    public static int strLength(String str) {\n        int valueLength = 0;\n        String chinese = \"[\\u0391-\\uFFE5]\";\n        if (!isEmpty(str)) {\n            //获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1\n            for (int i = 0; i < str.length(); i++) {\n                //获取一个字符\n                String temp = str.substring(i, i + 1);\n                //判断是否为中文字符\n                if (temp.matches(chinese)) {\n                    //中文字符长度为2\n                    valueLength += 2;\n                } else {\n                    //其他字符长度为1\n                    valueLength += 1;\n                }\n            }\n        }\n        return valueLength;\n    }\n\n    /**\n     * 描述：获取指定长度的字符所在位置.\n     *\n     * @param str  指定的字符串\n     * @param maxL 要取到的长度（字符长度，中文字符计2个）\n     * @return 字符的所在位置\n     */\n    public static int subStringLength(String str, int maxL) {\n        int currentIndex = 0;\n        int valueLength = 0;\n        String chinese = \"[\\u0391-\\uFFE5]\";\n        //获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1\n        for (int i = 0; i < str.length(); i++) {\n            //获取一个字符\n            String temp = str.substring(i, i + 1);\n            //判断是否为中文字符\n            if (temp.matches(chinese)) {\n                //中文字符长度为2\n                valueLength += 2;\n            } else {\n                //其他字符长度为1\n                valueLength += 1;\n            }\n            if (valueLength >= maxL) {\n                currentIndex = i;\n                break;\n            }\n        }\n        return currentIndex;\n    }\n\n    /**\n     * 描述：手机号格式验证.\n     *\n     * @param str 指定的手机号码字符串\n     * @return 是否为手机号码格式:是为true，否则false\n     */\n    public static Boolean isMobileNo(String str) {\n        Boolean isMobileNo = false;\n        try {\n            Pattern p = Pattern.compile(\"^((13[0-9])|(15[0-9])|(18[0-9])|(14[0-9])|(17[0-9]))\\\\d{8}$\");\n            Matcher m = p.matcher(str);\n            isMobileNo = m.matches();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return isMobileNo;\n    }\n\n    /**\n     * 描述：是否只是字母和数字.\n     *\n     * @param str 指定的字符串\n     * @return 是否只是字母和数字:是为true，否则false\n     */\n    public static Boolean isNumberLetter(String str) {\n        Boolean isNoLetter = false;\n        String expr = \"^[A-Za-z0-9]+$\";\n        if (str.matches(expr)) {\n            isNoLetter = true;\n        }\n        return isNoLetter;\n    }\n\n    /**\n     * 描述：是否只是数字.\n     *\n     * @param str 指定的字符串\n     * @return 是否只是数字:是为true，否则false\n     */\n    public static Boolean isNumber(String str) {\n        Boolean isNumber = false;\n        String expr = \"^[0-9]+$\";\n        if (str.matches(expr)) {\n            isNumber = true;\n        }\n        return isNumber;\n    }\n\n    /**\n     * 描述：是否是邮箱.\n     *\n     * @param str 指定的字符串\n     * @return 是否是邮箱:是为true，否则false\n     */\n    public static Boolean isEmail(String str) {\n        Boolean isEmail = false;\n        String expr = \"^([a-z0-9A-Z]+[-|\\\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\\\.)+[a-zA-Z]{2,}$\";\n        if (str.matches(expr)) {\n            isEmail = true;\n        }\n        return isEmail;\n    }\n\n    /**\n     * 描述：是否是中文.\n     *\n     * @param str 指定的字符串\n     * @return 是否是中文:是为true，否则false\n     */\n    public static Boolean isChinese(String str) {\n        Boolean isChinese = true;\n        String chinese = \"[\\u0391-\\uFFE5]\";\n        if (!isEmpty(str)) {\n            //获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1\n            for (int i = 0; i < str.length(); i++) {\n                //获取一个字符\n                String temp = str.substring(i, i + 1);\n                //判断是否为中文字符\n                if (temp.matches(chinese)) {\n                } else {\n                    isChinese = false;\n                }\n            }\n        }\n        return isChinese;\n    }\n\n    /**\n     * 描述：是否包含中文.\n     *\n     * @param str 指定的字符串\n     * @return 是否包含中文:是为true，否则false\n     */\n    public static Boolean isContainChinese(String str) {\n        Boolean isChinese = false;\n        String chinese = \"[\\u0391-\\uFFE5]\";\n        if (!isEmpty(str)) {\n            //获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1\n            for (int i = 0; i < str.length(); i++) {\n                //获取一个字符\n                String temp = str.substring(i, i + 1);\n                //判断是否为中文字符\n                if (temp.matches(chinese)) {\n                    isChinese = true;\n                } else {\n\n                }\n            }\n        }\n        return isChinese;\n    }\n\n    /**\n     * 是否包含中文数字字母的用户名\n     * 长度1-20\n     *\n     * @param str\n     * @return\n     */\n    public static boolean isConintChinseUser(String str) {\n        /**此正则表达式将上面二者结合起来进行判断，中文、大小写字母和数字**/\n        String all = \"^[\\\\u4E00-\\\\u9FA5\\\\uF900-\\\\uFA2D\\\\w]{2,10}$\";\n        Pattern pattern = Pattern.compile(all);\n        return pattern.matcher(str).matches();\n    }\n\n    /**\n     * 描述：从输入流中获得String.\n     *\n     * @param is 输入流\n     * @return 获得的String\n     */\n    public static String convertStreamToString(InputStream is) {\n        BufferedReader reader = new BufferedReader(new InputStreamReader(is));\n        StringBuilder sb = new StringBuilder();\n        String line = null;\n        try {\n            while ((line = reader.readLine()) != null) {\n                sb.append(line + \"\\n\");\n            }\n\n            //最后一个\\n删除\n            if (sb.indexOf(\"\\n\") != -1 && sb.lastIndexOf(\"\\n\") == sb.length() - 1) {\n                sb.delete(sb.lastIndexOf(\"\\n\"), sb.lastIndexOf(\"\\n\") + 1);\n            }\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                is.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 描述：标准化日期时间类型的数据，不足两位的补0.\n     *\n     * @param dateTime 预格式的时间字符串，如:2012-3-2 12:2:20\n     * @return String 格式化好的时间字符串，如:2012-03-20 12:02:20\n     */\n    public static String dateTimeFormat(String dateTime) {\n        StringBuilder sb = new StringBuilder();\n        try {\n            if (isEmpty(dateTime)) {\n                return null;\n            }\n            String[] dateAndTime = dateTime.split(\" \");\n            if (dateAndTime.length > 0) {\n                for (String str : dateAndTime) {\n                    if (str.indexOf(\"-\") != -1) {\n                        String[] date = str.split(\"-\");\n                        for (int i = 0; i < date.length; i++) {\n                            String str1 = date[i];\n                            sb.append(strFormat2(str1));\n                            if (i < date.length - 1) {\n                                sb.append(\"-\");\n                            }\n                        }\n                    } else if (str.indexOf(\":\") != -1) {\n                        sb.append(\" \");\n                        String[] date = str.split(\":\");\n                        for (int i = 0; i < date.length; i++) {\n                            String str1 = date[i];\n                            sb.append(strFormat2(str1));\n                            if (i < date.length - 1) {\n                                sb.append(\":\");\n                            }\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 描述：不足2个字符的在前面补“0”.\n     *\n     * @param str 指定的字符串\n     * @return 至少2个字符的字符串\n     */\n    public static String strFormat2(String str) {\n        try {\n            if (str.length() <= 1) {\n                str = \"0\" + str;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return str;\n    }\n\n    /**\n     * 描述：截取字符串到指定字节长度.\n     *\n     * @param str    the str\n     * @param length 指定字节长度\n     * @return 截取后的字符串\n     */\n    public static String cutString(String str, int length) {\n        return cutString(str, length, \"\");\n    }\n\n    /**\n     * 描述：截取字符串到指定字节长度.\n     *\n     * @param str    文本\n     * @param length 字节长度\n     * @param dot    省略符号\n     * @return 截取后的字符串\n     */\n    public static String cutString(String str, int length, String dot) {\n        int strBLen = strlen(str, \"GBK\");\n        if (strBLen <= length) {\n            return str;\n        }\n        int temp = 0;\n        StringBuffer sb = new StringBuffer(length);\n        char[] ch = str.toCharArray();\n        for (char c : ch) {\n            sb.append(c);\n            if (c > 256) {\n                temp += 2;\n            } else {\n                temp += 1;\n            }\n            if (temp >= length) {\n                if (dot != null) {\n                    sb.append(dot);\n                }\n                break;\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 描述：截取字符串从第一个指定字符.\n     *\n     * @param str1   原文本\n     * @param str2   指定字符\n     * @param offset 偏移的索引\n     * @return 截取后的字符串\n     */\n    public static String cutStringFromChar(String str1, String str2, int offset) {\n        if (isEmpty(str1)) {\n            return \"\";\n        }\n        int start = str1.indexOf(str2);\n        if (start != -1) {\n            if (str1.length() > start + offset) {\n                return str1.substring(start + offset);\n            }\n        }\n        return \"\";\n    }\n\n    /**\n     * 描述：获取字节长度.\n     *\n     * @param str     文本\n     * @param charset 字符集（GBK）\n     * @return the int\n     */\n    public static int strlen(String str, String charset) {\n        if (str == null || str.length() == 0) {\n            return 0;\n        }\n        int length = 0;\n        try {\n            length = str.getBytes(charset).length;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return length;\n    }\n\n    /**\n     * 获取大小的描述.\n     *\n     * @param size 字节个数\n     * @return 大小的描述\n     */\n    public static String getSizeDesc(long size) {\n        String suffix = \"B\";\n        if (size >= 1024) {\n            suffix = \"K\";\n            size = size >> 10;\n            if (size >= 1024) {\n                suffix = \"M\";\n                //size /= 1024;\n                size = size >> 10;\n                if (size >= 1024) {\n                    suffix = \"G\";\n                    size = size >> 10;\n                    //size /= 1024;\n                }\n            }\n        }\n        return size + suffix;\n    }\n\n    /**\n     * 描述：ip地址转换为10进制数.\n     *\n     * @param ip the ip\n     * @return the long\n     */\n    public static long ip2int(String ip) {\n        ip = ip.replace(\".\", \",\");\n        String[] items = ip.split(\",\");\n        return Long.valueOf(items[0]) << 24 | Long.valueOf(items[1]) << 16 | Long.valueOf(items[2]) << 8 | Long.valueOf(items[3]);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/ab/util/AbViewUtil.java",
    "content": "/*\n * Copyright (C) 2012 www.amsoft.cn\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ab.util;\n\nimport android.content.Context;\nimport android.graphics.Paint;\nimport android.text.TextPaint;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.View.MeasureSpec;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.MarginLayoutParams;\nimport android.view.ViewParent;\nimport android.widget.AbsListView;\nimport android.widget.GridView;\nimport android.widget.ListAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.ab.global.AbAppConfig;\n\n// TODO: Auto-generated Javadoc\n/**\n * © 2012 amsoft.cn\n * 名称：AbViewUtil.java \n * 描述：View工具类.\n */\n\npublic class AbViewUtil {\n    \n    /**\n     * 无效值\n     */\n    public static final int INVALID = Integer.MIN_VALUE;\n    \n\t/**\n\t * 测量这个view\n\t * 最后通过getMeasuredWidth()获取宽度和高度.\n\t * @param view 要测量的view\n\t * @return 测量过的view\n\t */\n\tpublic static void measureView(View view) {\n\t\tViewGroup.LayoutParams p = view.getLayoutParams();\n\t\tif (p == null) {\n\t\t\tp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,\n\t\t\t\t\tViewGroup.LayoutParams.WRAP_CONTENT);\n\t\t}\n\n\t\tint childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);\n\t\tint lpHeight = p.height;\n\t\tint childHeightSpec;\n\t\tif (lpHeight > 0) {\n\t\t\tchildHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,\n\t\t\t\t\tMeasureSpec.EXACTLY);\n\t\t} else {\n\t\t\tchildHeightSpec = MeasureSpec.makeMeasureSpec(0,\n\t\t\t\t\tMeasureSpec.UNSPECIFIED);\n\t\t}\n\t\tview.measure(childWidthSpec, childHeightSpec);\n\t}\n\t\n\t/**\n\t * 获得这个View的宽度\n\t * 测量这个view，最后通过getMeasuredWidth()获取宽度.\n\t * @param view 要测量的view\n\t * @return 测量过的view的宽度\n\t */\n\tpublic static int getViewWidth(View view) {\n\t\tmeasureView(view);\n\t\treturn view.getMeasuredWidth();\n\t}\n\t\n\t/**\n\t * 获得这个View的高度\n\t * 测量这个view，最后通过getMeasuredHeight()获取高度.\n\t * @param view 要测量的view\n\t * @return 测量过的view的高度\n\t */\n\tpublic static int getViewHeight(View view) {\n\t\tmeasureView(view);\n\t\treturn view.getMeasuredHeight();\n\t}\n\t\n\t/**\n\t * 从父亲布局中移除自己\n\t * @param v\n\t */\n\tpublic static void removeSelfFromParent(View v) {\n\t\tViewParent parent = v.getParent();\n\t\tif(parent != null){\n\t\t\tif(parent instanceof ViewGroup){\n\t\t\t\t((ViewGroup)parent).removeView(v);\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t/**\n     * 描述：dip转换为px.\n     *\n     * @param context the context\n     * @param dipValue the dip value\n     * @return px值\n     */\n    public static float dip2px(Context context, float dipValue) {\n        DisplayMetrics mDisplayMetrics = AbAppUtil.getDisplayMetrics(context);\n        return applyDimension(TypedValue.COMPLEX_UNIT_DIP,dipValue,mDisplayMetrics);\n    }\n\n    /**\n     * 描述：px转换为dip.\n     *\n     * @param context the context\n     * @param pxValue the px value\n     * @return dip值\n     */\n    public static float px2dip(Context context, float pxValue) {\n        DisplayMetrics mDisplayMetrics = AbAppUtil.getDisplayMetrics(context);\n        return pxValue / mDisplayMetrics.density;\n    }\n    \n    /**\n     * 描述：sp转换为px.\n     *\n     * @param context the context\n     * @param spValue the sp value\n     * @return sp值\n     */\n    public static float sp2px(Context context, float spValue) {\n        DisplayMetrics mDisplayMetrics = AbAppUtil.getDisplayMetrics(context);\n        return applyDimension(TypedValue.COMPLEX_UNIT_SP,spValue,mDisplayMetrics);\n    }\n    \n    /**\n     * 描述：px转换为sp.\n     *\n     * @param context the context\n     * @param spValue the sp value\n     * @return sp值\n     */\n    public static float px2sp(Context context, float pxValue) {\n        DisplayMetrics mDisplayMetrics = AbAppUtil.getDisplayMetrics(context);\n        return pxValue / mDisplayMetrics.scaledDensity;\n    }\n\n\t/**\n\t * 描述：根据屏幕大小缩放.\n\t *\n\t * @param context the context\n\t * @param pxValue the px value\n\t * @return the int\n\t */\n\tpublic static int scale(Context context, float value) {\n\t\tDisplayMetrics mDisplayMetrics = AbAppUtil.getDisplayMetrics(context);\n\t\treturn scale(mDisplayMetrics.widthPixels,\n\t\t\t\tmDisplayMetrics.heightPixels, value);\n\t}\n\t\n\t/**\n\t * 描述：根据屏幕大小缩放.\n\t *\n\t * @param displayWidth the display width\n\t * @param displayHeight the display height\n\t * @param pxValue the px value\n\t * @return the int\n\t */\n\tpublic static int scale(int displayWidth, int displayHeight, float pxValue) {\n\t\tif(pxValue == 0 ){\n\t\t\treturn 0;\n\t\t}\n\t\tfloat scale = 1;\n\t\ttry {\n\t\t\tfloat scaleWidth = (float) displayWidth / AbAppConfig.UI_WIDTH;\n\t\t\tfloat scaleHeight = (float) displayHeight / AbAppConfig.UI_HEIGHT;\n\t\t\tscale = Math.min(scaleWidth, scaleHeight);\n\t\t} catch (Exception e) {\n\t\t}\n\t\treturn Math.round(pxValue * scale + 0.5f);\n\t}\n\t\n\t/**\n\t * TypedValue官方源码中的算法，任意单位转换为PX单位\n\t * @param unit  TypedValue.COMPLEX_UNIT_DIP\n\t * @param value 对应单位的值\n\t * @param metrics 密度\n\t * @return px值\n\t */\n    public static float applyDimension(int unit, float value,\n                                       DisplayMetrics metrics){\n        switch (unit) {\n        case TypedValue.COMPLEX_UNIT_PX:\n            return value;\n        case TypedValue.COMPLEX_UNIT_DIP:\n            return value * metrics.density;\n        case TypedValue.COMPLEX_UNIT_SP:\n            return value * metrics.scaledDensity;\n        case TypedValue.COMPLEX_UNIT_PT:\n            return value * metrics.xdpi * (1.0f/72);\n        case TypedValue.COMPLEX_UNIT_IN:\n            return value * metrics.xdpi;\n        case TypedValue.COMPLEX_UNIT_MM:\n            return value * metrics.xdpi * (1.0f/25.4f);\n        }\n        return 0;\n    }\n    \n\t\n\t/**\n\t * \n\t * 描述：View树递归调用做适配.\n\t * AbAppConfig.uiWidth = 1080;\n\t * AbAppConfig.uiHeight = 700;\n\t * scaleContentView((RelativeLayout)findViewById(R.id.rootLayout));\n\t * 要求布局中的单位都用px并且和美工的设计图尺寸一致，包括所有宽高，Padding,Margin,文字大小\n\t * @param contentView\n\t */\n    public static void scaleContentView(ViewGroup contentView){\n        AbViewUtil.scaleView(contentView);\n\t\tif(contentView.getChildCount()>0){\n\t\t\tfor(int i=0;i<contentView.getChildCount();i++){\n\t\t\t\tif(contentView.getChildAt(i) instanceof ViewGroup){\n\t\t\t\t\tscaleContentView((ViewGroup)(contentView.getChildAt(i)));\n\t\t\t\t}else{\n\t\t\t\t\tscaleView(contentView.getChildAt(i));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    }\n    \n    /**\n     * 按比例缩放View，以布局中的尺寸为基准\n     * @param view\n     */\n    public static void scaleView(View view){\n        if (view instanceof TextView){\n            TextView textView = (TextView) view;\n            setTextSize(textView,textView.getTextSize());\n        }\n\n        ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) view.getLayoutParams();\n        if (null != params){\n            int width = INVALID;\n            int height = INVALID;\n            if (params.width != ViewGroup.LayoutParams.WRAP_CONTENT\n                && params.width != ViewGroup.LayoutParams.MATCH_PARENT){\n                width = params.width;\n            }\n\n            if (params.height != ViewGroup.LayoutParams.WRAP_CONTENT\n                && params.height != ViewGroup.LayoutParams.MATCH_PARENT){\n                height = params.height;\n            }\n            \n            //size\n            setViewSize(view,width,height);\n\n            // Padding\n            setPadding(view,view.getPaddingLeft(),view.getPaddingTop(),view.getPaddingRight(),view.getPaddingBottom());\n        }\n        \n        // Margin\n        if(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams){\n            ViewGroup.MarginLayoutParams mMarginLayoutParams = (ViewGroup.MarginLayoutParams) view\n                    .getLayoutParams();\n            if (mMarginLayoutParams != null){\n                setMargin(view,mMarginLayoutParams.leftMargin,mMarginLayoutParams.topMargin,mMarginLayoutParams.rightMargin,mMarginLayoutParams.bottomMargin);\n            }\n        }\n       \n    }\n    \n    /**\n     * 缩放文字大小\n     * @param textView button\n     * @param size sp值\n     * @return\n     */\n    public static void setSPTextSize(TextView textView,float size) {\n    \tfloat scaledSize = scale(textView.getContext(),size);\n        textView.setTextSize(scaledSize);\n    }\n    \n    /**\n     * 缩放文字大小,这样设置的好处是文字的大小不和密度有关，\n     * 能够使文字大小在不同的屏幕上显示比例正确\n     * @param textView button\n     * @param sizePixels px值\n     * @return\n     */\n    public static void setTextSize(TextView textView,float sizePixels) {\n    \tfloat scaledSize = scale(textView.getContext(),sizePixels);\n        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,scaledSize);\n    }\n    \n    /**\n     * 缩放文字大小\n     * @param context\n     * @param textPaint\n     * @param sizePixels px值\n     * @return\n     */\n    public static void setTextSize(Context context,TextPaint textPaint,float sizePixels) {\n    \tfloat scaledSize = scale(context,sizePixels);\n    \ttextPaint.setTextSize(scaledSize);\n    }\n    \n\n   /**\n    * 设置View的PX尺寸\n    * @param view  如果是代码new出来的View，需要设置一个适合的LayoutParams\n    * @param widthPixels\n    * @param heightPixels\n    */\n    public static void setViewSize(View view,int widthPixels, int heightPixels){\n        int scaledWidth = scale(view.getContext(), widthPixels);\n        int scaledHeight = scale(view.getContext(), heightPixels);\n        ViewGroup.LayoutParams params = view.getLayoutParams();\n        if(params == null){\n            AbLogUtil.e(AbViewUtil.class, \"setViewSize出错,如果是代码new出来的View，需要设置一个适合的LayoutParams\");\n            return;\n        }\n        if (widthPixels != INVALID){\n            params.width = scaledWidth;\n        }\n        if (heightPixels != INVALID){\n            params.height = scaledHeight;\n        }\n        view.setLayoutParams(params);\n    }\n\n\t/**\n\t * 设置PX padding.\n\t *\n\t * @param view the view\n\t * @param left the left padding in pixels\n     * @param top the top padding in pixels\n     * @param right the right padding in pixels\n     * @param bottom the bottom padding in pixels\n\t */\n\tpublic static void setPadding(View view, int left,\n\t\t\tint top, int right, int bottom) {\n\t\tint scaledLeft = scale(view.getContext(), left);\n\t\tint scaledTop = scale(view.getContext(), top);\n\t\tint scaledRight = scale(view.getContext(), right);\n\t\tint scaledBottom = scale(view.getContext(), bottom);\n\t\tview.setPadding(scaledLeft, scaledTop, scaledRight, scaledBottom);\n\t}\n\n\t/**\n\t * 设置 PX margin.\n\t * \n\t * @param view the view\n\t * @param left the left margin in pixels\n\t * @param top the top margin in pixels\n\t * @param right the right margin in pixels\n\t * @param bottom the bottom margin in pixels\n\t */\n\tpublic static void setMargin(View view, int left, int top,\n\t\t\tint right, int bottom) {\n\t\tint scaledLeft = scale(view.getContext(), left);\n\t\tint scaledTop = scale(view.getContext(), top);\n\t\tint scaledRight = scale(view.getContext(), right);\n\t\tint scaledBottom = scale(view.getContext(), bottom);\n\t\t\n\t\tif(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams){\n            ViewGroup.MarginLayoutParams mMarginLayoutParams = (ViewGroup.MarginLayoutParams) view\n                    .getLayoutParams();\n            if (mMarginLayoutParams != null){\n                if (left != INVALID) {\n                    mMarginLayoutParams.leftMargin = scaledLeft;\n                }\n                if (right != INVALID) {\n                    mMarginLayoutParams.rightMargin = scaledRight;\n                }\n                if (top != INVALID) {\n                    mMarginLayoutParams.topMargin = scaledTop;\n                }\n                if (bottom != INVALID) {\n                    mMarginLayoutParams.bottomMargin = scaledBottom;\n                }\n                view.setLayoutParams(mMarginLayoutParams);\n            }\n        }\n\t\t\n\t}\n\n}\n"
  }
]