mirror of
https://github.com/RfidResearchGroup/ChameleonBLEAPI.git
synced 2026-05-12 11:20:47 -07:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* 一些数组,集合操作的封装类!
|
||||
* */
|
||||
public class ArrayUtils {
|
||||
//将字符串链表或者数列转换为一般字符串数组
|
||||
public static <T> T[] list2Arr(List<T> list) {
|
||||
if (list == null) return null;
|
||||
if (list.size() == 0) return null;
|
||||
return list.toArray((T[]) Array.newInstance(list.get(0).getClass(), list.size()));
|
||||
}
|
||||
|
||||
//obj数组去重
|
||||
public static <T> T[] unrepeat(T[] objs) {
|
||||
if (objs == null) return null;
|
||||
if (objs.length == 0) return null;
|
||||
ArrayList<T> list = new ArrayList<>();
|
||||
for (int i = 0; i < objs.length; ++i) {
|
||||
if (list.indexOf(objs[i]) == -1) {
|
||||
//-1证明没有找到这个元素的存在,添加进去!
|
||||
list.add(objs[i]);
|
||||
}
|
||||
}
|
||||
return list.toArray((T[]) Array.newInstance(objs[0].getClass(), list.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到一个数组中的元素,如果越界则为空!
|
||||
*
|
||||
* @param array 需要被取出元素的数组!
|
||||
* @param index 需要取出的对应数组的元素的索引!
|
||||
* @return 如果不越界,则取出对应的值,否则直接返回null
|
||||
*/
|
||||
public static <T> T getElement(T[] array, int index) {
|
||||
return index >= array.length ? null : array[index];
|
||||
}
|
||||
|
||||
// 得到距离数组开始的有效长度!
|
||||
public static <T> int getLength(T[] array, int offset) {
|
||||
if (offset >= array.length) return -1;
|
||||
return array.length - offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/*
|
||||
* 针对Assets进行操作的类!
|
||||
* */
|
||||
public class AssetsUtil {
|
||||
|
||||
private Context context;
|
||||
|
||||
public AssetsUtil(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
//判断assets文件是否存在!
|
||||
public boolean isFileExists(String fileName) {
|
||||
InputStream is = null;
|
||||
boolean ret = false;
|
||||
try {
|
||||
is = context.getResources().getAssets().open(fileName);
|
||||
ret = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (is != null)
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//得到assets指定目录下的所有文件!
|
||||
public String[] getFiles(String root) {
|
||||
String[] files = new String[0];
|
||||
try {
|
||||
files = context.getAssets().list(root);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (files == null || files.length == 0) return null;
|
||||
return files;
|
||||
}
|
||||
|
||||
//移动assets中的文件到指定目录
|
||||
public boolean moveFile(String asFile, String targetPath) {
|
||||
File file = new File(targetPath);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
try {
|
||||
if (!file.createNewFile()) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean ret = false;
|
||||
//移动默认key文件
|
||||
AssetManager am = context.getResources().getAssets();
|
||||
InputStream is = null;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
is = am.open(asFile);
|
||||
fos = new FileOutputStream(file);
|
||||
int len = is.available();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
fos.write((byte) is.read());
|
||||
}
|
||||
ret = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
if (is != null) is.close();
|
||||
if (fos != null) fos.close();
|
||||
ret = false;
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (is != null) is.close();
|
||||
if (fos != null) fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/*
|
||||
* 倒计时任务!
|
||||
* */
|
||||
public class CountDown extends TimerTask {
|
||||
|
||||
private int timeDelay = 1000;
|
||||
private transient int countdynamic = 0;
|
||||
private Progress mProgress;
|
||||
private Timer timer;
|
||||
|
||||
public CountDown(Progress progress) {
|
||||
timer = new Timer();
|
||||
mProgress = progress;
|
||||
}
|
||||
|
||||
//倒计时回调接口
|
||||
public interface Progress {
|
||||
boolean onProgress(int countdynamic);
|
||||
}
|
||||
|
||||
//设置回调!
|
||||
public void setProgress(Progress progress) {
|
||||
mProgress = progress;
|
||||
}
|
||||
|
||||
//设置每次的延迟
|
||||
public CountDown setTimeDelay(int ms) {
|
||||
timeDelay = ms;
|
||||
return this;
|
||||
}
|
||||
|
||||
//设置需要延迟多少次!
|
||||
public CountDown setCountDown(int count) {
|
||||
countdynamic = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
//开始倒计时!
|
||||
public CountDown startCountDown() {
|
||||
if (countdynamic == 0) return this;
|
||||
timer.schedule(this, 0, timeDelay);
|
||||
return this;
|
||||
}
|
||||
|
||||
//取消倒计时
|
||||
public CountDown cancelCountDown() {
|
||||
cancel();
|
||||
countdynamic = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
//是否处于倒计时状态!
|
||||
public boolean isRunning() {
|
||||
return this.countdynamic != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//判断为零,立刻回调结束
|
||||
if (countdynamic == 0) {
|
||||
mProgress.onProgress(0);
|
||||
cancelCountDown();
|
||||
} else {
|
||||
//回调且判断需不需要继续下次回调!
|
||||
if (!mProgress.onProgress(countdynamic)) {
|
||||
cancelCountDown();
|
||||
return;
|
||||
}
|
||||
--countdynamic;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.proxgrind.chameleon.utils.stream.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author DXL
|
||||
* @Date 2019/4/12
|
||||
*/
|
||||
public class DiskKVUtil {
|
||||
|
||||
private static String LOG_TAG = "DiskKVUtil";
|
||||
|
||||
/**
|
||||
* 封装由设置写到持久化层的实现
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param file 最终写入的文件
|
||||
*/
|
||||
public static void update2Disk(String key, String value, File file) throws IOException {
|
||||
//由键值对到底层持久化的实现
|
||||
byte[] dataBuf = FileUtils.readBytes(file);
|
||||
String[] dats = new String(dataBuf).split("\n");
|
||||
//迭代判断行!
|
||||
for (int i = 0; i < dats.length; i++) {
|
||||
String kvLine = dats[i];
|
||||
//如果是注释则跳过处理
|
||||
if (kvLine.startsWith("#")) continue;
|
||||
//否则判断键值对!
|
||||
if (kvLine.matches(".* : .*")) {
|
||||
if (kvLine.startsWith(key)) {
|
||||
//判断键是否对应行开头,更新具体内容!
|
||||
String newKVLine = warp2KvLine(key, value);
|
||||
dats[i] = newKVLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
String result = StringUtils.arr2Str(dats, "\n", true);
|
||||
//重新写入到磁盘!
|
||||
FileUtils.writeBytes(result.getBytes(), file, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装由设置写到持久化层的实现
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值,数组形式,表示一键多值!
|
||||
* @param file 最终写入的文件
|
||||
*/
|
||||
public static void update2Disk(String key, String[] value, File file) throws IOException {
|
||||
//由键值对到底层持久化的实现
|
||||
byte[] dataBuf = FileUtils.readBytes(file);
|
||||
String[] dats = new String(dataBuf).split("\n");
|
||||
//迭代判断行!
|
||||
for (int i = 0, j = 0; i < dats.length; i++) {
|
||||
String kvLine = dats[i];
|
||||
//如果是注释则跳过处理
|
||||
if (kvLine.startsWith("#")) continue;
|
||||
//否则判断键值对!
|
||||
if (kvLine.matches(".* : .*")) {
|
||||
if (kvLine.startsWith(key)) {
|
||||
if (j >= value.length) {
|
||||
//可能会越界!
|
||||
Log.d(LOG_TAG, "update2Disk 有越界风险!");
|
||||
} else {
|
||||
//判断键是否对应行开头,更新具体内容!
|
||||
String newKVLine = warp2KvLine(key, value[j]);
|
||||
j++;
|
||||
dats[i] = newKVLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String result = StringUtils.arr2Str(dats, "\n", true);
|
||||
//重新写入到磁盘!
|
||||
FileUtils.writeBytes(result.getBytes(), file, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询键值对!
|
||||
*
|
||||
* @param key 键
|
||||
* @param file 欲操作的文件
|
||||
* @return 查询的结果集(值)!
|
||||
* @throws IOException 操作出现的各种问题!
|
||||
*/
|
||||
public static String[] queryKVLine(String key, File file) throws IOException {
|
||||
byte[] dataBuf = FileUtils.readBytes(file);
|
||||
String[] dats = new String(dataBuf).split("\n");
|
||||
ArrayList<String> valueList = new ArrayList<>(16);
|
||||
for (String line : dats) {
|
||||
//如果是注释则跳过处理
|
||||
if (line.startsWith("#")) continue;
|
||||
if (line.startsWith(key)) {
|
||||
valueList.add(getValue(line));
|
||||
}
|
||||
}
|
||||
return valueList.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询键是否存在!
|
||||
*
|
||||
* @param key 键
|
||||
* @param file 查询的文件!
|
||||
* @return 对应的键是否存在于配置文件中!
|
||||
*/
|
||||
public static boolean isKVExists(String key, File file) throws IOException {
|
||||
byte[] dataBuf = FileUtils.readBytes(file);
|
||||
String[] dats = new String(dataBuf).split("\n");
|
||||
for (String line : dats) {
|
||||
//如果是注释则跳过处理
|
||||
if (line.startsWith("#")) continue;
|
||||
if (line.startsWith(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param file 欲操作的文件!
|
||||
*/
|
||||
public static void insertKV(String key, String value, File file) throws IOException {
|
||||
String line = warp2KvLine(key, value) + "\n";
|
||||
FileUtils.writeBytes(line.getBytes(), file, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 凡是匹配到的键信息行,全部略过,然后将区间外的行写回去!
|
||||
*
|
||||
* @param key 键
|
||||
* @param file 操作的文件
|
||||
*/
|
||||
public static void deleteKV(String key, File file) throws IOException {
|
||||
byte[] dataBuf = FileUtils.readBytes(file);
|
||||
String[] dats = new String(dataBuf).split("\n");
|
||||
ArrayList<String> valueList = new ArrayList<>(16);
|
||||
for (String line : dats) {
|
||||
if (!line.startsWith(key)) {
|
||||
valueList.add(getValue(line));
|
||||
}
|
||||
}
|
||||
String ret = StringUtils.arr2Str(valueList.toArray(new String[0]), "\n", true);
|
||||
FileUtils.writeBytes(ret.getBytes(), file, false);
|
||||
}
|
||||
|
||||
public static char toChar(String v, char defaultVar) {
|
||||
try {
|
||||
return v.toCharArray()[0];
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static short toShort(String v, short defaultVar) {
|
||||
try {
|
||||
return Short.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static int toInt(String v, int defaultVar) {
|
||||
try {
|
||||
return Integer.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static long toLong(String v, long defaultVar) {
|
||||
try {
|
||||
return Long.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static float toFloat(String v, float defaultVar) {
|
||||
try {
|
||||
return Float.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static double toDouble(String v, double defaultVar) {
|
||||
try {
|
||||
return Double.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean toBoolean(String v, boolean defaultVar) {
|
||||
try {
|
||||
return Boolean.valueOf(v);
|
||||
} catch (Exception e) {
|
||||
return defaultVar;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue(String line) {
|
||||
//pm3DelayTime :
|
||||
return RegexGroupUtils.matcherGroup(line, ".* : (.*)", 1, 0);
|
||||
}
|
||||
|
||||
private static String warp2KvLine(String key, String value) {
|
||||
return key + " : " + value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.proxgrind.chameleon.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* 一些碎片开发使用上的工具!
|
||||
* */
|
||||
public class FragmentUtils {
|
||||
|
||||
//隐藏所有的碎片!
|
||||
public static void hides(FragmentManager manager, Fragment exclude) {
|
||||
List<Fragment> fragmentList = manager.getFragments();
|
||||
//迭代隐藏所有的碎片!
|
||||
for (Fragment fragment : fragmentList)
|
||||
//排除指定的碎片!
|
||||
if (fragment != exclude)
|
||||
manager.beginTransaction().hide(fragment).commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
public static void showAndAddBackStack(FragmentActivity activity, Fragment fragment) {
|
||||
if (activity == null || fragment == null) return;
|
||||
FragmentManager manager = activity.getSupportFragmentManager();
|
||||
manager.beginTransaction()
|
||||
.add(R.id.mainContainer, fragment)
|
||||
.addToBackStack(fragment.getTag()).commit();
|
||||
}
|
||||
|
||||
public static void runOnUiThread(Activity activity, Runnable runnable) {
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(runnable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.nfc.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 全局的标签缓存!
|
||||
*/
|
||||
public class GlobalTag {
|
||||
private static Tag tag = null;
|
||||
private static List<OnNewTagListener> listeners = new ArrayList<>();
|
||||
|
||||
public static Tag getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static void setTag(Tag tag) {
|
||||
GlobalTag.tag = tag;
|
||||
}
|
||||
|
||||
public interface OnNewTagListener {
|
||||
void onNewTag(Tag tag);
|
||||
}
|
||||
|
||||
public static void addListener(OnNewTagListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public static void removeListener(OnNewTagListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public static void notifyOnNewTag(Tag tag) {
|
||||
//直接通知TAG的变化!
|
||||
for (OnNewTagListener l : listeners) {
|
||||
try {
|
||||
l.onNewTag(tag);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HexUtil {
|
||||
private final static char[] HEX_DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
public static String dumpHexString(byte[] array) {
|
||||
return dumpHexString(array, 0, array.length);
|
||||
}
|
||||
|
||||
public static String dumpHexString(byte[] array, int offset, int length) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
byte[] line = new byte[16];
|
||||
int lineIndex = 0;
|
||||
|
||||
result.append("\n0x");
|
||||
result.append(toHexString(offset));
|
||||
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
if (lineIndex == 16) {
|
||||
result.append(" ");
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (line[j] > ' ' && line[j] < '~') {
|
||||
result.append(new String(line, j, 1));
|
||||
} else {
|
||||
result.append(".");
|
||||
}
|
||||
}
|
||||
|
||||
result.append("\n0x");
|
||||
result.append(toHexString(i));
|
||||
lineIndex = 0;
|
||||
}
|
||||
|
||||
byte b = array[i];
|
||||
result.append(" ");
|
||||
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
|
||||
result.append(HEX_DIGITS[b & 0x0F]);
|
||||
|
||||
line[lineIndex++] = b;
|
||||
}
|
||||
|
||||
if (lineIndex != 16) {
|
||||
int count = (16 - lineIndex) * 3;
|
||||
count++;
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
for (int i = 0; i < lineIndex; i++) {
|
||||
if (line[i] > ' ' && line[i] < '~') {
|
||||
result.append(new String(line, i, 1));
|
||||
} else {
|
||||
result.append(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String toHexString(byte b) {
|
||||
return toHexString(toByteArray(b));
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] array) {
|
||||
if (array == null) return null;
|
||||
return toHexString(array, 0, array.length);
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] array, int offset, int length) {
|
||||
char[] buf = new char[length * 2];
|
||||
|
||||
int bufIndex = 0;
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
byte b = array[i];
|
||||
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
|
||||
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
|
||||
}
|
||||
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public static String toHexString(int i) {
|
||||
return toHexString(toByteArray(i));
|
||||
}
|
||||
|
||||
public static String toHexString(short i) {
|
||||
return toHexString(toByteArray(i));
|
||||
}
|
||||
|
||||
public static String decorateHex(String hexStr) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] charArr = hexStr.toCharArray();
|
||||
for (int i = 0; i < charArr.length; i += 2) {
|
||||
sb.append("0x").append(charArr[i])
|
||||
.append(charArr[i + 1]).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(byte b) {
|
||||
byte[] array = new byte[1];
|
||||
array[0] = b;
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(int i) {
|
||||
byte[] array = new byte[4];
|
||||
|
||||
array[3] = (byte) (i & 0xFF);
|
||||
array[2] = (byte) ((i >> 8) & 0xFF);
|
||||
array[1] = (byte) ((i >> 16) & 0xFF);
|
||||
array[0] = (byte) ((i >> 24) & 0xFF);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(short i) {
|
||||
byte[] array = new byte[2];
|
||||
|
||||
array[1] = (byte) (i & 0xFF);
|
||||
array[0] = (byte) ((i >> 8) & 0xFF);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private static int toByte(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return (c - '0');
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return (c - 'A' + 10);
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return (c - 'a' + 10);
|
||||
Log.d("HexUtil", "The byte char is invalid: " + c);
|
||||
//throw new RuntimeException("Invalid hex char '" + c + "'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int toInt(byte b) {
|
||||
return b & 0xFF;
|
||||
}
|
||||
|
||||
public static int toIntFrom2Byte(byte[] b) {
|
||||
return Integer.parseInt(toHexString(b), 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拆分byte数组
|
||||
*
|
||||
* @param bytes 要拆分的数组
|
||||
* @param size 要按几个组成一份
|
||||
* @return
|
||||
*/
|
||||
public static byte[][] splitBytes(byte[] bytes, int size) {
|
||||
double splitLength = Double.parseDouble(size + "");
|
||||
int arrayLength = (int) Math.ceil(bytes.length / splitLength);
|
||||
byte[][] result = new byte[arrayLength][];
|
||||
int from, to;
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
from = (int) (i * splitLength);
|
||||
to = (int) (from + splitLength);
|
||||
if (to > bytes.length)
|
||||
to = bytes.length;
|
||||
result[i] = Arrays.copyOfRange(bytes, from, to);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] bytesMerge(byte[]... arrs) {
|
||||
byte[] ret = new byte[byteArraysLength(arrs)];
|
||||
int pos = 0;
|
||||
for (byte[] tmp : arrs) {
|
||||
if (tmp != null && tmp.length > 0) {
|
||||
System.arraycopy(tmp, 0, ret, pos, tmp.length);
|
||||
pos += tmp.length;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int byteArraysLength(byte[]... arrs) {
|
||||
int ret = 0;
|
||||
for (byte[] tmp : arrs) {
|
||||
if (tmp != null)
|
||||
ret += tmp.length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int byteArrayToInt(byte[] b) {
|
||||
return (b[3] & 0xFF) |
|
||||
(b[2] & 0xFF) << 8 |
|
||||
(b[1] & 0xFF) << 16 |
|
||||
(b[0] & 0xFF) << 24;
|
||||
}
|
||||
|
||||
public static int byte2Int(byte[] data, int offset) {
|
||||
byte[] bs = new byte[4];
|
||||
for (int i = offset, j = 0; j < bs.length; i++, j++) {
|
||||
bs[j] = data[i];
|
||||
}
|
||||
return HexUtil.byteArrayToInt(bs);
|
||||
}
|
||||
|
||||
public static int hexString2Int(String hexString) {
|
||||
byte[] hexByte = hexStringToByteArray(hexString);
|
||||
return byteArrayToInt(hexByte);
|
||||
}
|
||||
|
||||
public static byte[] intToByteArray(int a) {
|
||||
return new byte[]{
|
||||
(byte) ((a >> 24) & 0xFF),
|
||||
(byte) ((a >> 16) & 0xFF),
|
||||
(byte) ((a >> 8) & 0xFF),
|
||||
(byte) (a & 0xFF)
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] hexStringToByteArray(String hexString) {
|
||||
if (hexString == null) return null;
|
||||
if (hexString.length() == 0) return null;
|
||||
int length = hexString.length();
|
||||
byte[] buffer = new byte[length / 2];
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString
|
||||
.charAt(i + 1)));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] getAsciiBytes(String str) {
|
||||
return str.getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
//判断是否是十六进制格式的字符串
|
||||
public static boolean isHexString(String str) {
|
||||
if (str == null) return false;
|
||||
if (str.matches("[0-9a-fA-F]+")) return true;
|
||||
if (str.matches("0x[0-9a-fA-F]+")) return true;
|
||||
return str.matches("0x[0-9a-fA-F] +");
|
||||
}
|
||||
|
||||
public static boolean sequenceEqual(byte[] a, byte[] b, int len) {
|
||||
if (len > a.length && len > b.length) return false;
|
||||
int minLen = Math.min(a.length, b.length);
|
||||
if (minLen > len) return false;
|
||||
for (int i = 0; i < minLen; ++i) {
|
||||
if (a[i] != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
//MD5加密不可逆
|
||||
public class MD5Utils {
|
||||
/**
|
||||
* 对字节内容进行加密
|
||||
*
|
||||
* @param source 摘要对象!
|
||||
* @return 密文
|
||||
*/
|
||||
public static String digest(byte[] source) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
return HexUtil.toHexString(digest.digest(source));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对字节内容进行摘要检查!
|
||||
*
|
||||
* @param digest 已经确定的摘要信息!
|
||||
* @param source 未知的摘要对象!
|
||||
* @return 摘要信息对比结果!
|
||||
*/
|
||||
public static boolean verify(String digest, byte[] source) {
|
||||
return digest(source).equals(digest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
/*
|
||||
* MifareClassic标签用得到的工具!
|
||||
* */
|
||||
public class MifareUtils {
|
||||
|
||||
public static boolean validateSector(int sector) {
|
||||
// Do not be too strict on upper bounds checking, since some cards
|
||||
// have more addressable memory than they report. For example,
|
||||
// MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in
|
||||
// MIFARE Classic compatibility mode.
|
||||
// Note that issuing a command to an out-of-bounds block is safe - the
|
||||
// tag should report error causing IOException. This validation is a
|
||||
// helper to guard against obvious programming mistakes.
|
||||
|
||||
int NR_TRAILERS_4k = 40;
|
||||
if (sector < 0 || sector >= NR_TRAILERS_4k) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean validateBlock(int block) {
|
||||
// Just looking for obvious out of bounds...
|
||||
int NR_BLOCKS_4k = 0xFF;
|
||||
if (block < 0 || block >= NR_BLOCKS_4k) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean validateValueOperand(int value) {
|
||||
if (value < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int blockToSector(int blockIndex) {
|
||||
if (!validateBlock(blockIndex)) return 0;
|
||||
if (blockIndex < 32 * 4) {
|
||||
return (blockIndex / 4);
|
||||
} else {
|
||||
return (32 + (blockIndex - 32 * 4) / 16);
|
||||
}
|
||||
}
|
||||
|
||||
public static int sectorToBlock(int sectorIndex) {
|
||||
if (!validateSector(sectorIndex)) {
|
||||
return -1;
|
||||
}
|
||||
if (sectorIndex < 32) {
|
||||
return (sectorIndex * 4);
|
||||
} else {
|
||||
return (32 * 4 + (sectorIndex - 32) * 16);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFirstBlock(int uiBlock) {
|
||||
// 测试我们是否处于小扇区或者大扇区?
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock) % 16 == 0);
|
||||
}
|
||||
|
||||
public static boolean isTrailerBlock(int uiBlock) {
|
||||
// 测试我们处于小区块还是大扇区
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock + 1) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock + 1) % 16 == 0);
|
||||
}
|
||||
|
||||
public static int getBlockCountInSector(int sectorIndex) {
|
||||
if (!validateSector(sectorIndex)) return -1;
|
||||
if (sectorIndex < 32) {
|
||||
return 4;
|
||||
} else {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
public static int get_trailer_block(int uiFirstBlock) {
|
||||
// Test if we are in the small or big sectors
|
||||
int trailer_block;
|
||||
if (uiFirstBlock < 128) {
|
||||
trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
|
||||
} else {
|
||||
trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
|
||||
}
|
||||
return trailer_block;
|
||||
}
|
||||
|
||||
public static int getIndexOnSector(int block, int sector) {
|
||||
int index = 0;
|
||||
//得到当前的块在扇区中的具体索引!
|
||||
for (int i = 0; i < getBlockCountInSector(sector); i++) { //得到当前扇区的块总数!
|
||||
if (block == (sectorToBlock(block) + i)) break;
|
||||
++index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class NetworkUtils {
|
||||
/**
|
||||
* 是否使用代理(WiFi状态下的,避免被抓包)
|
||||
*/
|
||||
public static boolean isWifiProxy() {
|
||||
String proxyAddress;
|
||||
int proxyPort;
|
||||
proxyAddress = System.getProperty("http.proxyHost");
|
||||
String portstr = System.getProperty("http.proxyPort");
|
||||
proxyPort = Integer.parseInt((portstr != null ? portstr : "-1"));
|
||||
System.out.println(proxyAddress + "~");
|
||||
System.out.println("port = " + proxyPort);
|
||||
return (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在使用VPN
|
||||
*/
|
||||
public static boolean isVpnUsed() {
|
||||
try {
|
||||
Enumeration niList = NetworkInterface.getNetworkInterfaces();
|
||||
if (niList != null) {
|
||||
for (Object intf : Collections.list(niList)) {
|
||||
NetworkInterface ni = (NetworkInterface) intf;
|
||||
if (!ni.isUp() || ni.getInterfaceAddresses().size() == 0) {
|
||||
continue;
|
||||
}
|
||||
Log.d("-----", "isVpnUsed() NetworkInterface Name: " + ni.getName());
|
||||
if ("tun0".equals(ni.getName()) || "ppp0".equals(ni.getName())) {
|
||||
return true; // The VPN is up
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络是否连接!
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 有网时返回true,没网时返回false
|
||||
*/
|
||||
public static boolean isNetworkConnected(Context context) {
|
||||
if (context != null) {
|
||||
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
|
||||
if (mNetworkInfo != null) {
|
||||
return mNetworkInfo.isAvailable();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* wifi是否连接
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 是WIFI网络返回true,不是WIFI返回false
|
||||
*/
|
||||
public static boolean isWifiConnected(Context context) {
|
||||
if (context != null) {
|
||||
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo mWiFiNetworkInfo = mConnectivityManager
|
||||
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
if (mWiFiNetworkInfo != null) {
|
||||
return mWiFiNetworkInfo.isAvailable();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动网络是否连接
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 是数据流量时返回true,不是返回false
|
||||
*/
|
||||
public static boolean isMobileConnected(Context context) {
|
||||
if (context != null) {
|
||||
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo mMobileNetworkInfo = mConnectivityManager
|
||||
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
|
||||
if (mMobileNetworkInfo != null) {
|
||||
return mMobileNetworkInfo.isAvailable();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前网络连接的类型信息
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 判断结果,
|
||||
*/
|
||||
public static int getConnectedType(Context context) {
|
||||
if (context != null) {
|
||||
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
|
||||
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
|
||||
return mNetworkInfo.getType();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断主机是否存在!
|
||||
*
|
||||
* @param host 主机
|
||||
* @param timeout 超时值!
|
||||
*/
|
||||
public static boolean isHostReachable(String host, int timeout) {
|
||||
try {
|
||||
return InetAddress.getByName(host).isReachable(timeout);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断主机是否可以连接!
|
||||
*
|
||||
* @param host 主机
|
||||
* @param port 端口
|
||||
* @param timeout 超时值
|
||||
*/
|
||||
public static boolean isHostConnectable(String host, int port, int timeout) {
|
||||
Socket socket = new Socket();
|
||||
try {
|
||||
socket.connect(new InetSocketAddress(host, port), timeout);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断主机是否可以连接!
|
||||
*
|
||||
* @param host 主机
|
||||
* @param port 端口
|
||||
*/
|
||||
public static boolean isHostConnectable(String host, int port) {
|
||||
Socket socket = new Socket();
|
||||
try {
|
||||
socket.connect(new InetSocketAddress(host, port));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import com.proxgrind.chameleon.utils.stream.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface Properties {
|
||||
String APP_SDCARD = FileUtils.getAppFilesDir("files").getAbsolutePath();
|
||||
String APP_SETTINH_DIR = "settings";
|
||||
String APP_SETTINGS_NAME = "settings.ky";
|
||||
// APP的配置文件保存目录!
|
||||
String APP_CONF_PATH = APP_SDCARD + File.separator + APP_SETTINH_DIR;
|
||||
// app的通用配置文件!
|
||||
String APP_CONF_FILE = APP_CONF_PATH + File.separator + APP_SETTINGS_NAME;
|
||||
// 设备的自动关闭状态设置key!
|
||||
String APP_AUTO_CLOSE_KEY = "autoClose";
|
||||
// 设备的自动断开时间!
|
||||
String APP_AUTO_CLOSE_TIME_KEY = "autoCloseTime";
|
||||
// 新手模式的标志!
|
||||
String APP_NOVICE_MODE = "noviceMode";
|
||||
// 绑定的mac地址
|
||||
String APP_BIND_MAC = "bindMac";
|
||||
// 是否启用了MAC地址绑定!
|
||||
String APP_BIND_MAC_STATUS = "bindMacStatus";
|
||||
// 设备备注
|
||||
String APP_DEVICE_REMARKS = "device_remarks";
|
||||
// UI模式
|
||||
String APP_UI_MODE = "ui_mode";
|
||||
// DUMP模式
|
||||
String APP_DUMP_MODE = "dump_mode";
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/*
|
||||
* TODO 正则组匹配工具类
|
||||
* 根据给出的组标签反选或者正选内容!
|
||||
* */
|
||||
public class RegexGroupUtils {
|
||||
|
||||
/*public static void main(String args[]) {
|
||||
String c = "UID : 8b 36 8b eb";
|
||||
String s = matcherGroup(c, ".*UID : (.{11}).*", 1, 0);
|
||||
System.out.println("最终测试组匹配截取: " + s);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @param content 被匹配的内容!
|
||||
* @param regex 匹配规则
|
||||
* @return 匹配的组!
|
||||
* @Method 匹配组多个,根据组得到内容结果!
|
||||
*/
|
||||
public static String[] matcherGroups(String content, String regex, int group) {
|
||||
//准备格式匹配对象!
|
||||
Pattern p = Pattern.compile(regex);
|
||||
//准备匹配器对象!
|
||||
Matcher m = p.matcher(content);
|
||||
//结果集!
|
||||
ArrayList<String> ret = new ArrayList<>();
|
||||
//迭代查组
|
||||
while (m.find()) {
|
||||
ret.add(m.group(group));
|
||||
}
|
||||
return ret.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Method 匹配一个组
|
||||
* @Param content 被匹配的内容!
|
||||
* @Param regex 被匹配的正则!
|
||||
* @Param index 组索引,位于字符串中的第一次pos
|
||||
* @Return 返回指定索引的组内容!
|
||||
* */
|
||||
public static String matcherGroup(String content, String regex, int group, int index) {
|
||||
String[] res = matcherGroups(content, regex, group);
|
||||
if (index >= res.length || index < 0) return null;
|
||||
return res[index];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
//字符串数组转字符串,可选择性的添加分隔符!
|
||||
public static String arr2Str(String[] arr, String split, boolean addSplitInEnd) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
//进行迭代添加!
|
||||
for (int i = 0; i < arr.length; ++i) {
|
||||
//判断是否是在尾部
|
||||
if (i == arr.length - 1 && !addSplitInEnd) {
|
||||
//不添加换行符!
|
||||
sb.append(arr[i]);
|
||||
} else {
|
||||
sb.append(arr[i]).append(split);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
//是否是空串
|
||||
public static boolean isEmpty(String str) {
|
||||
return str.isEmpty() || str.equals(" ") || str.matches("\\s*");
|
||||
}
|
||||
|
||||
//是否是十六进制字符串
|
||||
public static boolean isHexStr(String str) {
|
||||
return str.matches("[0-9a-fA-F]+");
|
||||
}
|
||||
|
||||
//是否是数字
|
||||
public static boolean isNumStr(String str) {
|
||||
return str.matches("[0-9]+");
|
||||
}
|
||||
|
||||
//是否是字母
|
||||
public static boolean isLetter(String str) {
|
||||
return str.matches("[A-Fa-f]+");
|
||||
}
|
||||
|
||||
//是否是纯空格
|
||||
public static boolean isSpaces(String str) {
|
||||
return str.matches(" +");
|
||||
}
|
||||
|
||||
//删除所有的空格和转为大写!
|
||||
public static String trimO2Upper(String content) {
|
||||
return content.replaceAll(" ", "").toUpperCase();
|
||||
}
|
||||
|
||||
//删除所有的空格和转为小写!
|
||||
public static String trimO2Lower(String content) {
|
||||
return content.replaceAll(" ", "").toLowerCase();
|
||||
}
|
||||
|
||||
//删除所有的空格和转为大写!
|
||||
public static void trimO2Upper(String[] datas) {
|
||||
for (int i = 0; i < datas.length; i++) {
|
||||
datas[i] = trimO2Upper(datas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//删除所有的空格和转为小写!
|
||||
public static void trimO2Lower(String[] datas) {
|
||||
for (int i = 0; i < datas.length; i++) {
|
||||
datas[i] = trimO2Lower(datas[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
|
||||
/*
|
||||
* 设置文本的样式!
|
||||
* */
|
||||
public class TextStyleUtils {
|
||||
|
||||
/*
|
||||
* 合并多个富文本对象到构造器里!
|
||||
* */
|
||||
public static SpannableStringBuilder merge(SpannableString... text) {
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||
for (SpannableString ss : text) {
|
||||
ssb.append(ss);
|
||||
}
|
||||
return ssb;
|
||||
}
|
||||
|
||||
/*
|
||||
* 设置字体前景色!
|
||||
* */
|
||||
public static SpannableString getColorString(String str, int color) {
|
||||
SpannableString ret = new SpannableString(str);
|
||||
ret.setSpan(new ForegroundColorSpan(color), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 设置背景样式!
|
||||
* */
|
||||
public static SpannableString getStyleString(Context context, String str, int style) {
|
||||
// TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
|
||||
SpannableString ret = new SpannableString(str);
|
||||
ret.setSpan(new TextAppearanceSpan(context, style), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.proxgrind.chameleon.utils.tools;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
public class ViewUtils {
|
||||
//加载layout文件并且返回view引用
|
||||
public static View inflate(Context context, int layID) {
|
||||
View v = LayoutInflater.from(context).inflate(layID, null);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static void measureUnspecified(View view) {
|
||||
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||
}
|
||||
|
||||
// ScrollView自动滑动到底部!
|
||||
public static void fullScroll(ScrollView scrollView) {
|
||||
scrollView.getViewTreeObserver()
|
||||
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
scrollView.post(new Runnable() {
|
||||
public void run() {
|
||||
scrollView.fullScroll(View.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//给编辑器请求焦点和虚拟键盘
|
||||
public static void requestFocusAndShowInputMethod(EditText edt) {
|
||||
if (edt == null) return;
|
||||
edt.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
edt.setFocusable(true);
|
||||
edt.setFocusableInTouchMode(true);
|
||||
edt.requestFocus();
|
||||
InputMethodManager imm = (InputMethodManager) edt.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null)
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_NOT_ALWAYS);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user