提交 4f8fa0ec 编写于 作者: B Blankj

see 10/12 log

上级 860bf2ab
......@@ -7,8 +7,8 @@ android {
defaultConfig {
minSdkVersion 11
targetSdkVersion 23
versionCode 8
versionName "1.2.1"
versionCode 9
versionName "1.2.2"
}
buildTypes {
release {
......
package com.blankj.utilcode.utils;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import java.util.List;
/**
* <pre>
* author: Blankj
......
......@@ -17,6 +17,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
......@@ -32,36 +33,6 @@ public class AppUtils {
private AppUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 获取应用的 SHA1 值, 可据此判断高德,百度地图 key 是否正确
* @param context 上下文
* @return 应用的 SHA1 字符串, 比如: 53:FD:54:DC:19:0F:11:AC:B5:22:9E:F1:1A:68:88:1B:8B:E8:54:42
*/
public static String getSHA1(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(
context.getPackageName(), PackageManager.GET_SIGNATURES);
byte[] cert = info.signatures[0].toByteArray();
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] publicKey = md.digest(cert);
StringBuilder hexString = new StringBuilder();
for (byte aPublicKey : publicKey) {
String appendString = Integer.toHexString(0xFF & aPublicKey).toUpperCase();
if (appendString.length() == 1)
hexString.append("0");
hexString.append(appendString);
hexString.append(":");
}
String result = hexString.toString();
return result.substring(0, result.length() - 1);
} catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
/**
* 判断App是否安装
......@@ -400,6 +371,31 @@ public class AppUtils {
}
}
/**
* 获取应用签名的的SHA1值
* <p>可据此判断高德,百度地图key是否正确</p>
*
* @param context 上下文
* @return 应用签名的SHA1字符串, 比如:53:FD:54:DC:19:0F:11:AC:B5:22:9E:F1:1A:68:88:1B:8B:E8:54:42
*/
public static String getAppSignatureSHA1(Context context) {
return getAppSignatureSHA1(context, context.getPackageName());
}
/**
* 获取应用签名的的SHA1值
* <p>可据此判断高德,百度地图key是否正确</p>
*
* @param context 上下文
* @return 应用签名的SHA1字符串, 比如:53:FD:54:DC:19:0F:11:AC:B5:22:9E:F1:1A:68:88:1B:8B:E8:54:42
*/
public static String getAppSignatureSHA1(Context context, String packageName) {
Signature[] signature = getAppSignature(context, packageName);
if (signature == null) return null;
return EncryptUtils.encryptSHA1ToString(signature[0].toByteArray()).
replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0");
}
/**
* 判断App是否是系统应用
*
......
......@@ -22,192 +22,192 @@ import java.io.IOException;
*/
public class CameraUtils {
private CameraUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 获取打开照程序界面的Intent
*/
public static Intent getOpenCameraIntent() {
return new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
}
/**
* 获取跳转至相册选择界面的Intent
*/
public static Intent getImagePickerIntent() {
Intent intent = new Intent(Intent.ACTION_PICK, null);
return intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
}
/**
* 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
*/
public static Intent getImagePickerIntent(int outputX, int outputY, Uri fromFileURI,
Uri saveFileURI) {
return getImagePickerIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
}
/**
* 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
*/
public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
Uri saveFileURI) {
return getImagePickerIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
}
/**
* 获取[跳转至相册选择界面,并跳转至裁剪界面,可以指定是否缩放裁剪区域]的Intent
*
* @param aspectX 裁剪框尺寸比例X
* @param aspectY 裁剪框尺寸比例Y
* @param outputX 输出尺寸宽度
* @param outputY 输出尺寸高度
* @param canScale 是否可缩放
* @param fromFileURI 文件来源路径URI
* @param saveFileURI 输出文件路径URI
*/
public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
Uri fromFileURI, Uri saveFileURI) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setDataAndType(fromFileURI, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
intent.putExtra("scale", canScale);
// 图片剪裁不足黑边解决
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// 去除人脸识别
return intent.putExtra("noFaceDetection", true);
}
/**
* 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
*/
public static Intent getCameraIntent(Uri saveFileURI) {
Intent mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
return mIntent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
}
/**
* 获取[跳转至裁剪界面,默认可缩放]的Intent
*/
public static Intent getCropImageIntent(int outputX, int outputY, Uri fromFileURI,
Uri saveFileURI) {
return getCropImageIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
}
/**
* 获取[跳转至裁剪界面,默认可缩放]的Intent
*/
public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
Uri saveFileURI) {
return getCropImageIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
}
/**
* 获取[跳转至裁剪界面]的Intent
*/
public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
Uri fromFileURI, Uri saveFileURI) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(fromFileURI, "image/*");
intent.putExtra("crop", "true");
// X方向上的比例
intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
// Y方向上的比例
intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
intent.putExtra("scale", canScale);
// 图片剪裁不足黑边解决
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra("return-data", false);
// 需要将读取的文件路径和裁剪写入的路径区分,否则会造成文件0byte
intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
// true-->返回数据类型可以设置为Bitmap,但是不能传输太大,截大图用URI,小图用Bitmap或者全部使用URI
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// 取消人脸识别功能
intent.putExtra("noFaceDetection", true);
return intent;
}
/**
* 获得选中相册的图片
*
* @param context 上下文
* @param data onActivityResult返回的Intent
* @return bitmap
*/
public static Bitmap getChoosedImage(Activity context, Intent data) {
if (data == null) return null;
Bitmap bm = null;
ContentResolver cr = context.getContentResolver();
Uri originalUri = data.getData();
try {
bm = MediaStore.Images.Media.getBitmap(cr, originalUri);
} catch (IOException e) {
e.printStackTrace();
}
return bm;
}
/**
* 获得选中相册的图片路径
*
* @param context 上下文
* @param data onActivityResult返回的Intent
* @return
*/
public static String getChoosedImagePath(Activity context, Intent data) {
if (data == null) return null;
String path = "";
ContentResolver resolver = context.getContentResolver();
Uri originalUri = data.getData();
if (null == originalUri) return null;
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = resolver.query(originalUri, projection, null, null, null);
if (null != cursor) {
try {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} finally {
try {
if (!cursor.isClosed()) {
cursor.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return StringUtils.isEmpty(path) ? originalUri.getPath() : null;
}
/**
* 获取拍照之后的照片文件(JPG格式)
*
* @param data onActivityResult回调返回的数据
* @param filePath 文件路径
* @return 文件
*/
public static File getTakePictureFile(Intent data, String filePath) {
if (data == null) return null;
Bundle extras = data.getExtras();
if (extras == null) return null;
Bitmap photo = extras.getParcelable("data");
File file = new File(filePath);
if (ImageUtils.save(photo, file, Bitmap.CompressFormat.JPEG)) return file;
return null;
}
// private CameraUtils() {
// throw new UnsupportedOperationException("u can't instantiate me...");
// }
//
// /**
// * 获取打开照程序界面的Intent
// */
// public static Intent getOpenCameraIntent() {
// return new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// }
//
// /**
// * 获取跳转至相册选择界面的Intent
// */
// public static Intent getImagePickerIntent() {
// Intent intent = new Intent(Intent.ACTION_PICK, null);
// return intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
// }
//
// /**
// * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
// */
// public static Intent getImagePickerIntent(int outputX, int outputY, Uri fromFileURI,
// Uri saveFileURI) {
// return getImagePickerIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
// }
//
// /**
// * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
// */
// public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
// Uri saveFileURI) {
// return getImagePickerIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
// }
//
// /**
// * 获取[跳转至相册选择界面,并跳转至裁剪界面,可以指定是否缩放裁剪区域]的Intent
// *
// * @param aspectX 裁剪框尺寸比例X
// * @param aspectY 裁剪框尺寸比例Y
// * @param outputX 输出尺寸宽度
// * @param outputY 输出尺寸高度
// * @param canScale 是否可缩放
// * @param fromFileURI 文件来源路径URI
// * @param saveFileURI 输出文件路径URI
// */
// public static Intent getImagePickerIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
// Uri fromFileURI, Uri saveFileURI) {
// Intent intent = new Intent(Intent.ACTION_PICK);
// intent.setDataAndType(fromFileURI, "image/*");
// intent.putExtra("crop", "true");
// intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
// intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
// intent.putExtra("outputX", outputX);
// intent.putExtra("outputY", outputY);
// intent.putExtra("scale", canScale);
// // 图片剪裁不足黑边解决
// intent.putExtra("scaleUpIfNeeded", true);
// intent.putExtra("return-data", false);
// intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
// intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// // 去除人脸识别
// return intent.putExtra("noFaceDetection", true);
// }
//
// /**
// * 获取[跳转至相册选择界面,并跳转至裁剪界面,默认可缩放裁剪区域]的Intent
// */
// public static Intent getCameraIntent(Uri saveFileURI) {
// Intent mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// return mIntent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
// }
//
// /**
// * 获取[跳转至裁剪界面,默认可缩放]的Intent
// */
// public static Intent getCropImageIntent(int outputX, int outputY, Uri fromFileURI,
// Uri saveFileURI) {
// return getCropImageIntent(1, 1, outputX, outputY, true, fromFileURI, saveFileURI);
// }
//
// /**
// * 获取[跳转至裁剪界面,默认可缩放]的Intent
// */
// public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, Uri fromFileURI,
// Uri saveFileURI) {
// return getCropImageIntent(aspectX, aspectY, outputX, outputY, true, fromFileURI, saveFileURI);
// }
//
//
// /**
// * 获取[跳转至裁剪界面]的Intent
// */
// public static Intent getCropImageIntent(int aspectX, int aspectY, int outputX, int outputY, boolean canScale,
// Uri fromFileURI, Uri saveFileURI) {
// Intent intent = new Intent("com.android.camera.action.CROP");
// intent.setDataAndType(fromFileURI, "image/*");
// intent.putExtra("crop", "true");
// // X方向上的比例
// intent.putExtra("aspectX", aspectX <= 0 ? 1 : aspectX);
// // Y方向上的比例
// intent.putExtra("aspectY", aspectY <= 0 ? 1 : aspectY);
// intent.putExtra("outputX", outputX);
// intent.putExtra("outputY", outputY);
// intent.putExtra("scale", canScale);
// // 图片剪裁不足黑边解决
// intent.putExtra("scaleUpIfNeeded", true);
// intent.putExtra("return-data", false);
// // 需要将读取的文件路径和裁剪写入的路径区分,否则会造成文件0byte
// intent.putExtra(MediaStore.EXTRA_OUTPUT, saveFileURI);
// // true-->返回数据类型可以设置为Bitmap,但是不能传输太大,截大图用URI,小图用Bitmap或者全部使用URI
// intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// // 取消人脸识别功能
// intent.putExtra("noFaceDetection", true);
// return intent;
// }
//
// /**
// * 获得选中相册的图片
// *
// * @param context 上下文
// * @param data onActivityResult返回的Intent
// * @return bitmap
// */
// public static Bitmap getChoosedImage(Activity context, Intent data) {
// if (data == null) return null;
// Bitmap bm = null;
// ContentResolver cr = context.getContentResolver();
// Uri originalUri = data.getData();
// try {
// bm = MediaStore.Images.Media.getBitmap(cr, originalUri);
// } catch (IOException e) {
// e.printStackTrace();
// }
// return bm;
// }
//
// /**
// * 获得选中相册的图片路径
// *
// * @param context 上下文
// * @param data onActivityResult返回的Intent
// * @return
// */
// public static String getChoosedImagePath(Activity context, Intent data) {
// if (data == null) return null;
// String path = "";
// ContentResolver resolver = context.getContentResolver();
// Uri originalUri = data.getData();
// if (null == originalUri) return null;
// String[] projection = {MediaStore.Images.Media.DATA};
// Cursor cursor = resolver.query(originalUri, projection, null, null, null);
// if (null != cursor) {
// try {
// int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
// cursor.moveToFirst();
// path = cursor.getString(column_index);
// } catch (IllegalArgumentException e) {
// e.printStackTrace();
// } finally {
// try {
// if (!cursor.isClosed()) {
// cursor.close();
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
// return StringUtils.isEmpty(path) ? originalUri.getPath() : null;
// }
//
// /**
// * 获取拍照之后的照片文件(JPG格式)
// *
// * @param data onActivityResult回调返回的数据
// * @param filePath 文件路径
// * @return 文件
// */
// public static File getTakePictureFile(Intent data, String filePath) {
// if (data == null) return null;
// Bundle extras = data.getExtras();
// if (extras == null) return null;
// Bitmap photo = extras.getParcelable("data");
// File file = new File(filePath);
// if (ImageUtils.save(photo, file, Bitmap.CompressFormat.JPEG)) return file;
// return null;
// }
}
package com.blankj.utilcode.utils;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/10/9
* desc : 关闭相关工具类
* </pre>
*/
public class CloseUtils {
private CloseUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 关闭IO
*
* @param closeables closeable
*/
public static void closeIO(Closeable... closeables) {
if (closeables == null) return;
try {
for (Closeable closeable : closeables) {
if (closeable != null) {
closeable.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 安静关闭IO
*
* @param closeables closeable
*/
public static void closeIOQuietly(Closeable... closeables) {
if (closeables == null) return;
try {
for (Closeable closeable : closeables) {
if (closeable != null) {
closeable.close();
}
}
} catch (IOException e) {
// e.printStackTrace();
}
}
}
......@@ -44,12 +44,15 @@ public class ConvertUtils {
* <p>例如:</p>
* bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8
*
* @param bytes byte数组
* @param bytes 字节数组
* @return 16进制大写字符串
*/
public static String bytes2HexString(byte[] bytes) {
char[] ret = new char[bytes.length << 1];
for (int i = 0, j = 0; i < bytes.length; i++) {
if (bytes == null) return null;
int len = bytes.length;
if (len <= 0) return null;
char[] ret = new char[len << 1];
for (int i = 0, j = 0; i < len; i++) {
ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f];
ret[j++] = hexDigits[bytes[i] & 0x0f];
}
......@@ -65,8 +68,9 @@ public class ConvertUtils {
* @return 字节数组
*/
public static byte[] hexString2Bytes(String hexString) {
if (StringUtils.isSpace(hexString)) return null;
int len = hexString.length();
if(len % 2 !=0){
if (len % 2 != 0) {
hexString = "0" + hexString;
len = len + 1;
}
......@@ -101,6 +105,7 @@ public class ConvertUtils {
* @return 字节数组
*/
public static byte[] chars2Bytes(char[] chars) {
if (chars == null || chars.length <= 0) return null;
int len = chars.length;
byte[] bytes = new byte[len];
for (int i = 0; i < len; i++) {
......@@ -116,7 +121,9 @@ public class ConvertUtils {
* @return 字符数组
*/
public static char[] bytes2Chars(byte[] bytes) {
if (bytes == null) return null;
int len = bytes.length;
if (len <= 0) return null;
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
chars[i] = (char) (bytes[i] & 0xff);
......@@ -199,6 +206,48 @@ public class ConvertUtils {
}
}
/**
* bytes转bits
*
* @param bytes 字节数组
* @return bits
*/
public static String bytes2Bits(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
for (int j = 7; j >= 0; --j) {
sb.append(((aByte >> j) & 0x01) == 0 ? '0' : '1');
}
}
return sb.toString();
}
/**
* bits转bytes
*
* @param bits 二进制
* @return bytes
*/
public static byte[] bits2Bytes(String bits) {
int lenMod = bits.length() % 8;
int byteLen = bits.length() / 8;
// 不是8的倍数前面补0
if (lenMod != 0) {
for (int i = lenMod; i < 8; i++) {
bits = "0" + bits;
}
byteLen++;
}
byte[] bytes = new byte[byteLen];
for (int i = 0; i < byteLen; ++i) {
for (int j = 0; j < 8; ++j) {
bytes[i] <<= 1;
bytes[i] |= bits.charAt(i * 8 + j) - '0';
}
}
return bytes;
}
/**
* inputStream转outputStream
*
......@@ -219,7 +268,7 @@ public class ConvertUtils {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(is);
CloseUtils.closeIO(is);
}
}
......@@ -241,6 +290,7 @@ public class ConvertUtils {
* @return 字节数组
*/
public static byte[] inputStream2Bytes(InputStream is) {
if (is == null) return null;
return input2OutputStream(is).toByteArray();
}
......@@ -251,6 +301,7 @@ public class ConvertUtils {
* @return 输入流
*/
public static InputStream bytes2InputStream(byte[] bytes) {
if (bytes == null || bytes.length <= 0) return null;
return new ByteArrayInputStream(bytes);
}
......@@ -272,6 +323,7 @@ public class ConvertUtils {
* @return 字节数组
*/
public static OutputStream bytes2OutputStream(byte[] bytes) {
if (bytes == null || bytes.length <= 0) return null;
ByteArrayOutputStream os = null;
try {
os = new ByteArrayOutputStream();
......@@ -281,7 +333,7 @@ public class ConvertUtils {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(os);
CloseUtils.closeIO(os);
}
}
......@@ -327,7 +379,7 @@ public class ConvertUtils {
* @return 字符串
*/
public static String outputStream2String(OutputStream out, String charsetName) {
if (out == null) return null;
if (out == null || StringUtils.isSpace(charsetName)) return null;
try {
return new String(outputStream2Bytes(out), charsetName);
} catch (UnsupportedEncodingException e) {
......@@ -406,7 +458,7 @@ public class ConvertUtils {
* @return 字节数组
*/
public static byte[] drawable2Bytes(Drawable drawable, Bitmap.CompressFormat format) {
return bitmap2Bytes(drawable2Bitmap(drawable), format);
return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format);
}
/**
......@@ -417,7 +469,7 @@ public class ConvertUtils {
* @return drawable
*/
public static Drawable bytes2Drawable(Resources res, byte[] bytes) {
return bitmap2Drawable(res, bytes2Bitmap(bytes));
return res == null ? null : bitmap2Drawable(res, bytes2Bitmap(bytes));
}
/**
......@@ -433,7 +485,7 @@ public class ConvertUtils {
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null) {
bgDrawable.draw(canvas);
}else {
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
......
package com.blankj.utilcode.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.nio.channels.NonWritableChannelException;
import static android.content.ContentValues.TAG;
/**
* <pre>
......@@ -34,12 +27,12 @@ public class CrashUtils implements Thread.UncaughtExceptionHandler {
private UncaughtExceptionHandler mHandler;
private boolean mInitialized;
private CrashUtils(){
private CrashUtils() {
}
/**
* 获取单例
* <p>在Application中初始化{@code CrashUtils.getInstance().getBuilder(this);}</p>
*
* @return 单例
*/
......@@ -88,7 +81,7 @@ public class CrashUtils implements Thread.UncaughtExceptionHandler {
cause = cause.getCause();
}
} finally {
FileUtils.closeIO(pw);
CloseUtils.closeIO(pw);
}
sb.append(writer.toString());
FileUtils.writeFileFromString(fullPath, sb.toString(), false);
......@@ -102,7 +95,7 @@ public class CrashUtils implements Thread.UncaughtExceptionHandler {
*
* @return 崩溃头
*/
public StringBuilder getCrashHead() {
private StringBuilder getCrashHead() {
StringBuilder sb = new StringBuilder();
try {
PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
......
......@@ -5,7 +5,6 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import java.io.IOException;
import java.io.InputStreamReader;
......@@ -26,15 +25,24 @@ public class DeviceUtils {
}
/**
* 获取系统版本号
* 判断设备是否root
*
* @return {@code true}: 是<br>{@code false}: 否
*/
public static boolean isRoot() {
return ShellUtils.execCmd("echo root", true, false).result == 0;
}
/**
* 获取设备系统版本号
*/
public static int getSDK() {
public static int getSDKVersion() {
return android.os.Build.VERSION.SDK_INT;
}
/**
* 获取AndroidID
* 获取设备AndroidID
*
* @param context 上下文
* @return AndroidID
......@@ -81,7 +89,7 @@ public class DeviceUtils {
} catch (IOException e) {
e.printStackTrace();
} finally {
FileUtils.closeIO(lnr, isr);
CloseUtils.closeIO(lnr, isr);
}
return macAddress == null ? "" : macAddress;
}
......
......@@ -33,21 +33,29 @@ public class EmptyUtils {
public static boolean isEmpty(Object obj) {
if (obj == null) {
return true;
} else if (obj instanceof String && obj.toString().length() == 0) {
}
if (obj instanceof String && obj.toString().length() == 0) {
return true;
} else if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
}
if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
return true;
} else if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
}
if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
return true;
} else if (obj instanceof Map && ((Map) obj).isEmpty()) {
}
if (obj instanceof Map && ((Map) obj).isEmpty()) {
return true;
} else if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
}
if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
return true;
} else if (obj instanceof SparseBooleanArray && ((SparseBooleanArray) obj).size() == 0) {
}
if (obj instanceof SparseBooleanArray && ((SparseBooleanArray) obj).size() == 0) {
return true;
} else if (obj instanceof SparseIntArray && ((SparseIntArray) obj).size() == 0) {
}
if (obj instanceof SparseIntArray && ((SparseIntArray) obj).size() == 0) {
return true;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (obj instanceof SparseLongArray && ((SparseLongArray) obj).size() == 0) {
return true;
}
......@@ -57,33 +65,11 @@ public class EmptyUtils {
/**
* 判断对象是否非空
* <p>不要问我为什么不直接调用{@code !isEmpty(obj);}</p>
*
* @param obj 对象
* @return {@code true}: 非空<br>{@code false}: 空
*/
public static boolean isNotEmpty(Object obj) {
if (obj == null) {
return false;
} else if (obj instanceof String && obj.toString().length() == 0) {
return false;
} else if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
return false;
} else if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
return false;
} else if (obj instanceof Map && ((Map) obj).isEmpty()) {
return false;
} else if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
return false;
} else if (obj instanceof SparseBooleanArray && ((SparseBooleanArray) obj).size() == 0) {
return false;
} else if (obj instanceof SparseIntArray && ((SparseIntArray) obj).size() == 0) {
return false;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (obj instanceof SparseLongArray && ((SparseLongArray) obj).size() == 0) {
return false;
}
}
return true;
return !isEmpty(obj);
}
}
}
\ No newline at end of file
......@@ -5,11 +5,13 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import static com.blankj.utilcode.utils.ConvertUtils.*;
......@@ -56,7 +58,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptMD2(byte[] data) {
return encryptAlgorithm(data, "MD2");
return hashTemplate(data, "MD2");
}
/**
......@@ -98,6 +100,7 @@ public class EncryptUtils {
* @return 16进制加盐密文
*/
public static String encryptMD5ToString(byte[] data, byte[] salt) {
if (data == null || salt == null) return null;
byte[] dataSalt = new byte[data.length + salt.length];
System.arraycopy(data, 0, dataSalt, 0, data.length);
System.arraycopy(salt, 0, dataSalt, data.length, salt.length);
......@@ -111,7 +114,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptMD5(byte[] data) {
return encryptAlgorithm(data, "MD5");
return hashTemplate(data, "MD5");
}
/**
......@@ -121,7 +124,7 @@ public class EncryptUtils {
* @return 文件的16进制密文
*/
public static String encryptMD5File2String(String filePath) {
return encryptMD5File2String(new File(filePath));
return encryptMD5File2String(FileUtils.getFileByPath(filePath));
}
/**
......@@ -131,7 +134,7 @@ public class EncryptUtils {
* @return 文件的MD5校验码
*/
public static byte[] encryptMD5File(String filePath) {
return encryptMD5File(new File(filePath));
return encryptMD5File(FileUtils.getFileByPath(filePath));
}
/**
......@@ -141,7 +144,7 @@ public class EncryptUtils {
* @return 文件的16进制密文
*/
public static String encryptMD5File2String(File file) {
return encryptMD5File(file) != null ? bytes2HexString(encryptMD5File(file)) : "";
return bytes2HexString(encryptMD5File(file));
}
/**
......@@ -151,6 +154,7 @@ public class EncryptUtils {
* @return 文件的MD5校验码
*/
public static byte[] encryptMD5File(File file) {
if (file == null) return null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
......@@ -161,10 +165,10 @@ public class EncryptUtils {
return md.digest();
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(fis);
CloseUtils.closeIO(fis);
}
return null;
}
/**
......@@ -194,7 +198,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptSHA1(byte[] data) {
return encryptAlgorithm(data, "SHA-1");
return hashTemplate(data, "SHA1");
}
/**
......@@ -224,7 +228,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptSHA224(byte[] data) {
return encryptAlgorithm(data, "SHA-224");
return hashTemplate(data, "SHA224");
}
/**
......@@ -254,7 +258,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptSHA256(byte[] data) {
return encryptAlgorithm(data, "SHA-256");
return hashTemplate(data, "SHA256");
}
/**
......@@ -284,7 +288,7 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptSHA384(byte[] data) {
return encryptAlgorithm(data, "SHA-384");
return hashTemplate(data, "SHA384");
}
/**
......@@ -314,25 +318,227 @@ public class EncryptUtils {
* @return 密文字节数组
*/
public static byte[] encryptSHA512(byte[] data) {
return encryptAlgorithm(data, "SHA-512");
return hashTemplate(data, "SHA512");
}
/**
* 对data进行algorithm算法加密
* hash加密模板
*
* @param data 明文字节数组
* @param data 数据
* @param algorithm 加密算法
* @return 密文字节数组
*/
private static byte[] encryptAlgorithm(byte[] data, String algorithm) {
private static byte[] hashTemplate(byte[] data, String algorithm) {
if (data == null || data.length <= 0) return null;
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(data);
return md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return new byte[0];
}
/**
* HmacMD5加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacMD5ToString(String data, String key) {
return encryptHmacMD5ToString(data.getBytes(), key.getBytes());
}
/**
* HmacMD5加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacMD5ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacMD5(data, key));
}
/**
* HmacMD5加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacMD5(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacMD5");
}
/**
* HmacSHA1加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacSHA1ToString(String data, String key) {
return encryptHmacSHA1ToString(data.getBytes(), key.getBytes());
}
/**
* HmacSHA1加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacSHA1ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacSHA1(data, key));
}
/**
* HmacSHA1加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacSHA1(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacSHA1");
}
/**
* HmacSHA224加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacSHA224ToString(String data, String key) {
return encryptHmacSHA224ToString(data.getBytes(), key.getBytes());
}
/**
* HmacSHA224加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacSHA224ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacSHA224(data, key));
}
/**
* HmacSHA224加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacSHA224(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacSHA224");
}
/**
* HmacSHA256加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacSHA256ToString(String data, String key) {
return encryptHmacSHA256ToString(data.getBytes(), key.getBytes());
}
/**
* HmacSHA256加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacSHA256ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacSHA256(data, key));
}
/**
* HmacSHA256加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacSHA256(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacSHA256");
}
/**
* HmacSHA384加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacSHA384ToString(String data, String key) {
return encryptHmacSHA384ToString(data.getBytes(), key.getBytes());
}
/**
* HmacSHA384加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacSHA384ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacSHA384(data, key));
}
/**
* HmacSHA384加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacSHA384(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacSHA384");
}
/**
* HmacSHA512加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptHmacSHA512ToString(String data, String key) {
return encryptHmacSHA512ToString(data.getBytes(), key.getBytes());
}
/**
* HmacSHA512加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptHmacSHA512ToString(byte[] data, byte[] key) {
return bytes2HexString(encryptHmacSHA512(data, key));
}
/**
* HmacSHA512加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptHmacSHA512(byte[] data, byte[] key) {
return hmacTemplate(data, key, "HmacSHA512");
}
/**
* Hmac加密模板
*
* @param data 数据
* @param key 秘钥
* @param algorithm 加密算法
* @return 密文字节数组
*/
private static byte[] hmacTemplate(byte[] data, byte[] key, String algorithm) {
if(data == null || data.length ==0 || key == null || key.length ==0) return null;
try {
SecretKeySpec secretKey = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secretKey);
return mac.doFinal(data);
} catch (InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/************************ DES加密相关 ***********************/
......@@ -345,27 +551,6 @@ public class EncryptUtils {
public static String DES_Transformation = "DES/ECB/NoPadding";
private static final String DES_Algorithm = "DES";
/**
* @param data 数据
* @param key 秘钥
* @param algorithm 采用何种DES算法
* @param transformation 转变
* @param isEncrypt 是否加密
* @return 密文或者明文,适用于DES,3DES,AES
*/
public static byte[] DESTemplet(byte[] data, byte[] key, String algorithm, String transformation, boolean isEncrypt) {
try {
SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(transformation);
SecureRandom random = new SecureRandom();
cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec, random);
return cipher.doFinal(data);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* DES加密后转为Base64编码
*
......@@ -396,7 +581,7 @@ public class EncryptUtils {
* @return 密文
*/
public static byte[] encryptDES(byte[] data, byte[] key) {
return DESTemplet(data, key, DES_Algorithm, DES_Transformation, true);
return desTemplate(data, key, DES_Algorithm, DES_Transformation, true);
}
/**
......@@ -429,7 +614,7 @@ public class EncryptUtils {
* @return 明文
*/
public static byte[] decryptDES(byte[] data, byte[] key) {
return DESTemplet(data, key, DES_Algorithm, DES_Transformation, false);
return desTemplate(data, key, DES_Algorithm, DES_Transformation, false);
}
/************************ 3DES加密相关 ***********************/
......@@ -473,7 +658,7 @@ public class EncryptUtils {
* @return 密文
*/
public static byte[] encrypt3DES(byte[] data, byte[] key) {
return DESTemplet(data, key, TripleDES_Algorithm, TripleDES_Transformation, true);
return desTemplate(data, key, TripleDES_Algorithm, TripleDES_Transformation, true);
}
/**
......@@ -506,7 +691,7 @@ public class EncryptUtils {
* @return 明文
*/
public static byte[] decrypt3DES(byte[] data, byte[] key) {
return DESTemplet(data, key, TripleDES_Algorithm, TripleDES_Transformation, false);
return desTemplate(data, key, TripleDES_Algorithm, TripleDES_Transformation, false);
}
/************************ AES加密相关 ***********************/
......@@ -550,7 +735,7 @@ public class EncryptUtils {
* @return 密文
*/
public static byte[] encryptAES(byte[] data, byte[] key) {
return DESTemplet(data, key, AES_Algorithm, AES_Transformation, true);
return desTemplate(data, key, AES_Algorithm, AES_Transformation, true);
}
/**
......@@ -583,6 +768,30 @@ public class EncryptUtils {
* @return 明文
*/
public static byte[] decryptAES(byte[] data, byte[] key) {
return DESTemplet(data, key, AES_Algorithm, AES_Transformation, false);
return desTemplate(data, key, AES_Algorithm, AES_Transformation, false);
}
/**
* DES加密模板
*
* @param data 数据
* @param key 秘钥
* @param algorithm 加密算法
* @param transformation 转变
* @param isEncrypt {@code true}: 加密 {@code false}: 解密
* @return 密文或者明文,适用于DES,3DES,AES
*/
public static byte[] desTemplate(byte[] data, byte[] key, String algorithm, String transformation, boolean isEncrypt) {
if(data == null || data.length == 0 || key == null || key.length == 0) return null;
try {
SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(transformation);
SecureRandom random = new SecureRandom();
cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec, random);
return cipher.doFinal(data);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ package com.blankj.utilcode.utils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
......@@ -723,7 +723,7 @@ public class FileUtils {
e.printStackTrace();
return false;
} finally {
closeIO(is, os);
CloseUtils.closeIO(is, os);
}
}
......@@ -750,16 +750,16 @@ public class FileUtils {
public static boolean writeFileFromString(File file, String content, boolean append) {
if (file == null || content == null) return false;
if (!createOrExistsFile(file)) return false;
FileWriter fileWriter = null;
BufferedWriter bw = null;
try {
fileWriter = new FileWriter(file, append);
fileWriter.write(content);
bw = new BufferedWriter(new FileWriter(file, append));
bw.write(content);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
closeIO(fileWriter);
CloseUtils.closeIO(bw);
}
}
......@@ -831,7 +831,7 @@ public class FileUtils {
e.printStackTrace();
return null;
} finally {
closeIO(reader);
CloseUtils.closeIO(reader);
}
}
......@@ -873,7 +873,7 @@ public class FileUtils {
e.printStackTrace();
return null;
} finally {
closeIO(reader);
CloseUtils.closeIO(reader);
}
}
......@@ -928,7 +928,7 @@ public class FileUtils {
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(is);
CloseUtils.closeIO(is);
}
switch (p) {
case 0xefbb:
......@@ -973,7 +973,7 @@ public class FileUtils {
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(is);
CloseUtils.closeIO(is);
}
return count;
}
......@@ -990,7 +990,6 @@ public class FileUtils {
/**
* 获取文件大小
* <p>例如:getFileSize(file, ConstUtils.MB); 返回文件大小单位为MB</p>
*
* @param file 文件
* @return 文件大小
......@@ -1020,24 +1019,6 @@ public class FileUtils {
return EncryptUtils.encryptMD5File2String(file);
}
/**
* 关闭IO
*
* @param closeables closeable
*/
public static void closeIO(Closeable... closeables) {
if (closeables == null) return;
try {
for (Closeable closeable : closeables) {
if (closeable != null) {
closeable.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取全路径中的最长目录
*
......
......@@ -163,7 +163,7 @@ public class ImageUtils {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(is);
CloseUtils.closeIO(is);
}
}
......@@ -190,7 +190,7 @@ public class ImageUtils {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(is);
CloseUtils.closeIO(is);
}
}
......@@ -1214,7 +1214,7 @@ public class ImageUtils {
} catch (IOException e) {
e.printStackTrace();
} finally {
FileUtils.closeIO(os);
CloseUtils.closeIO(os);
}
return ret;
}
......@@ -1268,7 +1268,7 @@ public class ImageUtils {
e.printStackTrace();
return null;
} finally {
FileUtils.closeIO(is);
CloseUtils.closeIO(is);
}
}
......
......@@ -17,7 +17,7 @@ import java.io.File;
* author: Blankj
* blog : http://blankj.com
* time : 2016/9/23
* desc : Intent相关工具类
* desc : 意图相关工具类
* </pre>
*/
public class IntentUtils {
......
......@@ -9,15 +9,15 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/9/21
* desc :
* desc : 日志相关工具类
* </pre>
*/
public class LogUtils {
......@@ -26,169 +26,285 @@ public class LogUtils {
throw new UnsupportedOperationException("u can't instantiate me...");
}
private static Boolean LOG_SWITCH = true; // 日志文件总开关
private static Boolean LOG_TO_FILE = false; // 日志写入文件开关
private static String LOG_TAG = "TAG"; // 默认的tag
private static char LOG_TYPE = 'v';// 输入日志类型,v代表输出所有信息,w则只输出警告...
private static int LOG_SAVE_DAYS = 7;// sd卡中日志文件的最多保存天数
private static boolean logSwitch = true;
private static boolean log2FileSwitch = false;
private static char logFilter = 'v';
private static String tag = "TAG";
private static String dir;
private final static SimpleDateFormat LOG_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 日志的输出格式
private final static SimpleDateFormat FILE_SUFFIX = new SimpleDateFormat("yyyy-MM-dd");// 日志文件格式
private static String LOG_FILE_PATH; // 日志文件保存路径
private static String LOG_FILE_NAME;// 日志文件保存名称
public static void init(Context context) { // 在Application中初始化
LOG_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + context.getPackageName();
LOG_FILE_NAME = "Log";
/**
* 初始化函数
* <p>与{@link #getBuilder(Context)}两者选其一</p>
*
* @param context 上下文
* @param logSwitch 日志总开关
* @param log2FileSwitch 日志写入文件开关
* @param logFilter 输入日志类型有{@code v, d, i, w, e}<br>v代表输出所有信息,w则只输出警告...
* @param tag 标签
*/
public static void init(Context context, boolean logSwitch, boolean log2FileSwitch, char logFilter, String tag) {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
dir = context.getExternalCacheDir().getPath() + File.separator;
} else {
dir = context.getCacheDir().getPath() + File.separator;
}
LogUtils.logSwitch = logSwitch;
LogUtils.log2FileSwitch = log2FileSwitch;
LogUtils.logFilter = logFilter;
LogUtils.tag = tag;
}
/****************************
* Warn
*********************************/
public static void w(Object msg) {
w(LOG_TAG, msg);
/**
* 获取LogUtils建造者
* <p>与{@link #init(Context, boolean, boolean, char, String)}两者选其一</p>
*
* @param context 上下文
* @return Builder对象
*/
public static Builder getBuilder(Context context) {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
dir = context.getExternalCacheDir().getPath() + File.separator;
} else {
dir = context.getCacheDir().getPath() + File.separator;
}
return new Builder();
}
public static void w(String tag, Object msg) {
w(tag, msg, null);
}
public static class Builder {
public static void w(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'w');
private boolean logSwitch = true;
private boolean log2FileSwitch = false;
private char logFilter = 'v';
private String tag = "TAG";
public Builder setLogSwitch(boolean logSwitch) {
this.logSwitch = logSwitch;
return this;
}
public Builder setLog2FileSwitch(boolean log2FileSwitch) {
this.log2FileSwitch = log2FileSwitch;
return this;
}
public Builder setLogFilter(char logFilter) {
this.logFilter = logFilter;
return this;
}
public Builder setTag(String tag) {
this.tag = tag;
return this;
}
public void create() {
LogUtils.logSwitch = logSwitch;
LogUtils.log2FileSwitch = log2FileSwitch;
LogUtils.logFilter = logFilter;
LogUtils.tag = tag;
}
}
/***************************
* Error
********************************/
public static void e(Object msg) {
e(LOG_TAG, msg);
/**
* Verbose日志
*
* @param msg 消息
*/
public static void v(Object msg) {
v(tag, msg);
}
public static void e(String tag, Object msg) {
e(tag, msg, null);
/**
* Verbose日志
*
* @param tag 标签
* @param msg 消息
*/
public static void v(String tag, Object msg) {
v(tag, msg, null);
}
public static void e(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'e');
/**
* Verbose日志
*
* @param tag 标签
* @param msg 消息
* @param tr 异常
*/
public static void v(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'v');
}
/***************************
* Debug
********************************/
/**
* Debug日志
*
* @param msg 消息
*/
public static void d(Object msg) {
d(LOG_TAG, msg);
d(tag, msg);
}
/**
* Debug日志
*
* @param tag 标签
* @param msg 消息
*/
public static void d(String tag, Object msg) {// 调试信息
d(tag, msg, null);
}
/**
* Debug日志
*
* @param tag 标签
* @param msg 消息
* @param tr 异常
*/
public static void d(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'd');
}
/****************************
* Info
*********************************/
/**
* Info日志
*
* @param msg 消息
*/
public static void i(Object msg) {
i(LOG_TAG, msg);
i(tag, msg);
}
/**
* Info日志
*
* @param tag 标签
* @param msg 消息
*/
public static void i(String tag, Object msg) {
i(tag, msg, null);
}
/**
* Info日志
*
* @param tag 标签
* @param msg 消息
* @param tr 异常
*/
public static void i(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'i');
}
/**************************
* Verbose
********************************/
public static void v(Object msg) {
v(LOG_TAG, msg);
/**
* Warn日志
*
* @param msg 消息
*/
public static void w(Object msg) {
w(tag, msg);
}
public static void v(String tag, Object msg) {
v(tag, msg, null);
/**
* Warn日志
*
* @param tag 标签
* @param msg 消息
*/
public static void w(String tag, Object msg) {
w(tag, msg, null);
}
public static void v(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'v');
/**
* Warn日志
*
* @param tag 标签
* @param msg 消息
* @param tr 异常
*/
public static void w(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'w');
}
/**
* Error日志
*
* @param msg 消息
*/
public static void e(Object msg) {
e(tag, msg);
}
/**
* Error日志
*
* @param tag 标签
* @param msg 消息
*/
public static void e(String tag, Object msg) {
e(tag, msg, null);
}
/**
* Error日志
*
* @param tag 标签
* @param msg 消息
* @param tr 异常
*/
public static void e(String tag, Object msg, Throwable tr) {
log(tag, msg.toString(), tr, 'e');
}
/**
* 根据tag, msg和等级,输出日志
*
* @param tag
* @param msg
* @param level
* @param tag 标签
* @param msg 消息
* @param tr 异常
* @param type 日志类型
*/
private static void log(String tag, String msg, Throwable tr, char level) {
if (LOG_SWITCH) {
if ('e' == level && ('e' == LOG_TYPE || 'v' == LOG_TYPE)) { // 输出错误信息
private static void log(String tag, String msg, Throwable tr, char type) {
if (logSwitch) {
if ('e' == type && ('e' == logFilter || 'v' == logFilter)) {
Log.e(tag, msg, tr);
} else if ('w' == level && ('w' == LOG_TYPE || 'v' == LOG_TYPE)) {
} else if ('w' == type && ('w' == logFilter || 'v' == logFilter)) {
Log.w(tag, msg, tr);
} else if ('d' == level && ('d' == LOG_TYPE || 'v' == LOG_TYPE)) {
} else if ('d' == type && ('d' == logFilter || 'v' == logFilter)) {
Log.d(tag, msg, tr);
} else if ('i' == level && ('d' == LOG_TYPE || 'v' == LOG_TYPE)) {
} else if ('i' == type && ('d' == logFilter || 'v' == logFilter)) {
Log.i(tag, msg, tr);
} else {
Log.v(tag, msg, tr);
}
if (LOG_TO_FILE)
log2File(String.valueOf(level), tag, msg + tr == null ? "" : "\n" + Log.getStackTraceString(tr));
if (log2FileSwitch) {
log2File(type, tag, msg + '\n' + Log.getStackTraceString(tr));
}
}
}
/**
* 打开日志文件并写入日志
*
* @return
* @param type 日志类型
* @param tag 标签
* @param content 内容
**/
private synchronized static void log2File(String mylogtype, String tag, String text) {
Date nowtime = new Date();
String date = FILE_SUFFIX.format(nowtime);
String dateLogContent = LOG_FORMAT.format(nowtime) + ":" + mylogtype + ":" + tag + ":" + text; // 日志输出格式
File destDir = new File(LOG_FILE_PATH);
if (!destDir.exists()) {
destDir.mkdirs();
}
File file = new File(LOG_FILE_PATH, LOG_FILE_NAME + date);
private synchronized static void log2File(char type, String tag, String content) {
if (content == null) return;
Date now = new Date();
String date = new SimpleDateFormat("MM-dd", Locale.getDefault()).format(now);
String time = new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(now);
String fullPath = dir + date + ".log";
if (!FileUtils.createOrExistsFile(fullPath)) return;
String dateLogContent = time + ":" + type + ":" + tag + ":" + content + '\n';
BufferedWriter bw = null;
try {
FileWriter filerWriter = new FileWriter(file, true);
BufferedWriter bufWriter = new BufferedWriter(filerWriter);
bufWriter.write(dateLogContent);
bufWriter.newLine();
bufWriter.close();
filerWriter.close();
bw = new BufferedWriter(new FileWriter(fullPath, true));
bw.write(dateLogContent);
} catch (IOException e) {
e.printStackTrace();
} finally {
CloseUtils.closeIO(bw);
}
}
/**
* 删除指定的日志文件
*/
public static void delFile() {// 删除日志文件
String needDelFiel = FILE_SUFFIX.format(getDateBefore());
File file = new File(LOG_FILE_PATH, needDelFiel + LOG_FILE_NAME);
if (file.exists()) {
file.delete();
}
}
/**
* 得到LOG_SAVE_DAYS天前的日期
*
* @return
*/
private static Date getDateBefore() {
Date nowtime = new Date();
Calendar now = Calendar.getInstance();
now.setTime(nowtime);
now.set(Calendar.DATE, now.get(Calendar.DATE) - LOG_SAVE_DAYS);
return now.getTime();
}
}
......@@ -27,7 +27,7 @@ public class NetworkUtils {
private NetworkUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
public static final int NETWORK_WIFI = 1; // wifi network
public static final int NETWORK_4G = 4; // "4G" networks
public static final int NETWORK_3G = 3; // "3G" networks
......@@ -35,14 +35,14 @@ public class NetworkUtils {
public static final int NETWORK_UNKNOWN = 5; // unknown network
public static final int NETWORK_NO = -1; // no network
private static final int NETWORK_TYPE_GSM = 16;
private static final int NETWORK_TYPE_GSM = 16;
private static final int NETWORK_TYPE_TD_SCDMA = 17;
private static final int NETWORK_TYPE_IWLAN = 18;
private static final int NETWORK_TYPE_IWLAN = 18;
private static final String CMCC_ISP = "46000"; //中国移动
private static final String CMCC_ISP = "46000";//中国移动
private static final String CMCC2_ISP = "46002";//中国移动
private static final String CU_ISP = "46001"; //中国联通
private static final String CT_ISP = "46003"; //中国电信
private static final String CU_ISP = "46001";//中国联通
private static final String CT_ISP = "46003";//中国电信
/**
* 打开网络设置界面
......
package com.blankj.utilcode.utils;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
......@@ -53,6 +54,7 @@ public class PhoneUtils {
* @param context 上下文
* @return IMIE码
*/
@SuppressLint("HardwareIds")
public static String getIMEI(Context context) {
return ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
}
......@@ -63,6 +65,7 @@ public class PhoneUtils {
* @param context 上下文
* @return IMSI码
*/
@SuppressLint("HardwareIds")
public static String getIMSI(Context context) {
return ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getSubscriberId();
}
......
......@@ -82,7 +82,7 @@ public class SDCardUtils {
} catch (Exception e) {
e.printStackTrace();
} finally {
FileUtils.closeIO(bufferedReader);
CloseUtils.closeIO(bufferedReader);
}
return Environment.getExternalStorageDirectory().getPath() + File.separator;
}
......
......@@ -15,7 +15,7 @@ import java.util.List;
* author: Blankj
* blog : http://blankj.com
* time : 2016/8/2
* desc : 服务工具类
* desc : 服务相关工具类
* </pre>
*/
public class ServiceUtils {
......@@ -32,17 +32,11 @@ public class ServiceUtils {
* @return {@code true}: 是<br>{@code false}: 否
*/
public static boolean isRunningService(Context context, String className) {
// 进程的管理者,活动的管理者
ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
// 获取正在运行的服务,最多获取1000个
List<RunningServiceInfo> runningServices = activityManager.getRunningServices(1000);
// 遍历集合
for (RunningServiceInfo runningServiceInfo : runningServices) {
ComponentName service = runningServiceInfo.service;
if (className.equals(service.getClassName())) {
return true;
}
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infoList = activityManager.getRunningServices(0x7FFFFFFF);
if (infoList == null || infoList.size() == 0) return false;
for (RunningServiceInfo info : infoList) {
if (className.equals(info.service.getClassName())) return true;
}
return false;
}
......
......@@ -2,7 +2,6 @@ package com.blankj.utilcode.utils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
......@@ -20,19 +19,6 @@ public class ShellUtils {
throw new UnsupportedOperationException("u can't instantiate me...");
}
public static final String COMMAND_SU = "su";
public static final String COMMAND_SH = "sh";
public static final String COMMAND_EXIT = "exit\n";
public static final String COMMAND_LINE_END = "\n";
/**
* 判断设备是否root
* @return {@code true}: root<br>{@code false}: 没root
*/
public static boolean isRoot() {
return execCmd("echo root", true, false).result == 0;
}
/**
* 是否是在root下执行命令
*
......@@ -110,19 +96,18 @@ public class ShellUtils {
StringBuilder errorMsg = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
os.write(command.getBytes());
os.writeBytes(COMMAND_LINE_END);
os.writeBytes("\n");
os.flush();
}
os.writeBytes(COMMAND_EXIT);
os.writeBytes("exit\n");
os.flush();
result = process.waitFor();
if (isNeedResultMsg) {
successMsg = new StringBuilder();
......@@ -140,39 +125,28 @@ public class ShellUtils {
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
CloseUtils.closeIO(os, successResult, errorResult);
if (process != null) {
process.destroy();
}
}
return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
: errorMsg.toString());
return new CommandResult(
result,
successMsg == null ? null : successMsg.toString(),
errorMsg == null ? null : errorMsg.toString()
);
}
/**
* 返回的命令结果
*/
public static class CommandResult {
/**
* 结果码
**/
public int result;
/**
* 成功信息
* 成功信息
**/
public String successMsg;
/**
......@@ -180,10 +154,6 @@ public class ShellUtils {
**/
public String errorMsg;
public CommandResult(int result) {
this.result = result;
}
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
......
......@@ -21,12 +21,18 @@ public class ToastUtils {
private static Toast sToast;
private static Handler sHandler = new Handler(Looper.getMainLooper());
private static boolean sIsCancel;
/**
* <p>当连续弹出吐司时,是要弹出新吐司还是只修改文本内容</p>
* <p>{@code true}: 弹出新吐司<br>{@code false}: 只修改文本内容</p>
* <p>如果为{@code false}的话可用来做显示任意时长的吐司</p>
* 吐司初始化
*
* @param isCancel 当连续弹出吐司时,是要弹出新吐司还是只修改文本内容
* <p>{@code true}: 弹出新吐司<br>{@code false}: 只修改文本内容</p>
* <p>如果为{@code false}的话可用来做显示任意时长的吐司</p>
*/
public static boolean sIsCancel;
public static void init(boolean isCancel) {
sIsCancel = isCancel;
}
/**
* 安全地显示短时吐司
......
package com.blankj.utilcode.utils;
import android.content.Context;
import android.os.Vibrator;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/9/29
* desc :
* desc : 震动相关工具类
* </pre>
*/
public class VibrationUtils {
// private VibrationUtils() {
// throw new UnsupportedOperationException("u can't instantiate me...");
// }
//
// /**
// * 震动
// * <p>需添加权限 {@code <uses-permission android:name="android.permission.VIBRATE"/>}</p>
// *
// * @param context 上下文
// * @param milliseconds 振动时长
// */
// public static void vibrate(Context context, long milliseconds) {
// Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
// vibrator.vibrate(milliseconds);
// }
//
// /**
// * 指定手机以pattern模式振动
// *
// * @param context
// * @param pattern new long[]{400,800,1200,1600},就是指定在400ms、800ms、1200ms、1600ms这些时间点交替启动、关闭手机振动器
// * @param repeat 指定pattern数组的索引,指定pattern数组中从repeat索引开始的振动进行循环。-1表示只振动一次,非-1表示从 pattern的指定下标开始重复振动。
// */
// public static void vibrate(Context context, long[] pattern, int repeat) {
// Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
// vibrator.vibrate(pattern, repeat);
// }
//
// /**
// * 取消振动
// *
// * @param context 上下文
// */
// public static void cancel(Context context) {
// ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).cancel();
// }
}
......@@ -94,7 +94,7 @@ public class ZipUtils {
} finally {
if (zos != null) {
zos.finish();
FileUtils.closeIO(zos);
CloseUtils.closeIO(zos);
}
}
}
......@@ -157,7 +157,7 @@ public class ZipUtils {
return zipFile(resFile, "", zos, comment);
} finally {
if (zos != null) {
FileUtils.closeIO(zos);
CloseUtils.closeIO(zos);
}
}
}
......@@ -203,7 +203,7 @@ public class ZipUtils {
}
zos.closeEntry();
} finally {
FileUtils.closeIO(is);
CloseUtils.closeIO(is);
}
}
return true;
......@@ -317,7 +317,7 @@ public class ZipUtils {
out.write(buffer, 0, len);
}
} finally {
FileUtils.closeIO(in, out);
CloseUtils.closeIO(in, out);
}
}
}
......
......@@ -53,6 +53,16 @@ public class ConvertUtilsTest {
assertThat(byte2FitSize(1024 * 1024 * 3 + 1024 * 100)).isEqualTo("3.098MB");
}
@Test
public void testBytes2Bits() throws Exception {
System.out.println(bytes2Bits(new byte[]{0x7F, (byte) 0xFA}));
}
@Test
public void testBits2Bytes() throws Exception {
System.out.println(bytes2HexString(bits2Bytes("111111111111010")));
}
@Test
public void testInputStream2BytesAndBytes2InputStream() throws Exception {
String string = "this is test string";
......
......@@ -21,7 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
* </pre>
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
@Config(manifest = Config.NONE ,sdk = 23)
public class EncryptUtilsTest {
String blankjMD2 = "15435017570D8A73449E25C4622E17A4";
......@@ -83,6 +83,60 @@ public class EncryptUtilsTest {
assertThat(encryptSHA512("blankj".getBytes())).isEqualTo(hexString2Bytes(blankjSHA512));
}
//use this site to test https://www.freeformatter.com/hmac-generator.html
String blankjHmacMD5 = "2BA3FDABEE222522044BEC0CE5D6B490";
String blankjHmacSHA1 = "88E83EFD915496860C83739BE2CF4752B2AC105F";
String blankjHmacSHA224 = "E392D83D1030323FB2E062E8165A3AD38366E53DF19EA3290961E153";
String blankjHmacSHA256 = "A59675F13FC9A6E06D8DC90D4DC01DB9C991B0B95749D2471E588BF311DA2C67";
String blankjHmacSHA384 =
"9FC2F49C7EDE698EA59645B3BEFBBE67DCC7D6623E03D4D03CDA1324F7B6445BC428AB42F6A962CF79AFAD1302C3223D";
String blankjHmacSHA512 =
"FC55AD54B95F55A8E32EA1BAD7748C157F80679F5561EC95A3EAD975316BA85363CB4AF6462D695F742F469EDC2D577272BE359A7F9E9C7018FDF4C921E1B3CF";
String blankjHmackey = "blankj";
@Test
public void testEncryptHmacMD5() throws Exception {
assertThat(encryptHmacMD5ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacMD5);
assertThat(encryptHmacMD5ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacMD5);
assertThat(encryptHmacMD5("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacMD5));
}
@Test
public void testEncryptHmacSHA1() throws Exception {
assertThat(encryptHmacSHA1ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacSHA1);
assertThat(encryptHmacSHA1ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacSHA1);
assertThat(encryptHmacSHA1("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacSHA1));
}
@Test
public void testEncryptHmacSHA224() throws Exception {
assertThat(encryptHmacSHA224ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacSHA224);
assertThat(encryptHmacSHA224ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacSHA224);
assertThat(encryptHmacSHA224("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacSHA224));
}
@Test
public void testEncryptHmacSHA256() throws Exception {
assertThat(encryptHmacSHA256ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacSHA256);
assertThat(encryptHmacSHA256ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacSHA256);
assertThat(encryptHmacSHA256("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacSHA256));
}
@Test
public void testEncryptHmacSHA384() throws Exception {
assertThat(encryptHmacSHA384ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacSHA384);
assertThat(encryptHmacSHA384ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacSHA384);
assertThat(encryptHmacSHA384("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacSHA384));
}
@Test
public void testEncryptHmacSHA512() throws Exception {
assertThat(encryptHmacSHA512ToString("blankj", blankjHmackey)).isEqualTo(blankjHmacSHA512);
assertThat(encryptHmacSHA512ToString("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(blankjHmacSHA512);
assertThat(encryptHmacSHA512("blankj".getBytes(), blankjHmackey.getBytes())).isEqualTo(hexString2Bytes(blankjHmacSHA512));
}
String dataDES = "0008DB3345AB0223";
String keyDES = "6801020304050607";
String resDES = "1F7962581118F360";
......
package com.blankj.utilcode.utils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/10/9
* desc : LogUtils单元测试
* </pre>
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class LogUtilsTest {
@Before
public void setUp() throws Exception {
ShadowLog.stream = System.out;
LogUtils.getBuilder(TestUtils.getContext()).
setLogSwitch(true).
setLog2FileSwitch(false).
setTag("Blankj").
setLogFilter('e').
create();
}
@Test
public void v() throws Exception {
LogUtils.v("Verbose");
}
@Test
public void d() throws Exception {
LogUtils.d("Debug");
}
@Test
public void i() throws Exception {
LogUtils.i("Info");
}
@Test
public void w() throws Exception {
LogUtils.w("Warn");
}
@Test
public void e() throws Exception {
LogUtils.e("Error");
}
}
\ No newline at end of file
......@@ -9,6 +9,9 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.io.File;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.regex.Pattern;
import static com.blankj.utilcode.utils.TimeUtils.milliseconds2String;
import static com.google.common.truth.Truth.assertThat;
......@@ -36,6 +39,7 @@ public class TestUtils {
@Test
public void test() throws Exception {
byte[] bytes = new byte[0];
System.out.println(bytes.length);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册