├── README.md ├── appmain ├── callback │ ├── Basecallback.java │ └── actioncallback.java ├── defined │ ├── Basctypescallback.java │ ├── ChameleonCMDSet.java │ ├── ChameleonClick.java │ ├── ChameleonRespSet.java │ ├── ChameleonType.java │ ├── DataChangeListener.java │ ├── DecryptCallback.java │ ├── IChameleonExecutor.java │ ├── OnConnectListener.java │ ├── OnDfuRuniingListener.java │ ├── OnTouchListener.java │ ├── RegexCommon.java │ └── ResultCallback.java ├── devices │ ├── BleCMDControl.java │ ├── BleSerialControl.java │ ├── DevCallback.java │ ├── Device.java │ ├── DriverInterface.java │ ├── EmptyDevice.java │ └── UsbSerialControl.java ├── executor │ ├── ChameleonBleExecutor.java │ ├── ChameleonExecutorProxy.java │ ├── ChameleonStdExecutor.java │ └── ChameleonUsbExecutor.java ├── javabean │ ├── DecryptOrder.java │ ├── DetectionLog.java │ ├── DevBean.java │ ├── DeviceInfo.java │ ├── DumpBean.java │ ├── FileBean.java │ ├── ItemCommonBean.java │ ├── ItemTextBean.java │ ├── ItemToggleBean.java │ ├── KeyValueTipsBean.java │ ├── M1KeyBean.java │ ├── MifareBean.java │ ├── SlotAction.java │ ├── SlotBean.java │ └── TitleBean.java ├── posixio │ └── PosixCom.java ├── utils │ ├── device │ │ ├── ble │ │ │ ├── BLERawUtils.java │ │ │ ├── BluetoothUtils.java │ │ │ └── ClsUtils.java │ │ └── screen │ │ │ ├── BadgeHelper.java │ │ │ └── DisplayUtil.java │ ├── mifare │ │ ├── BatchAdapter.java │ │ ├── ChameleonBatchAdapterImpl.java │ │ ├── ChameleonMifareAdapter.java │ │ ├── DumpUtils.java │ │ ├── MfDataUtils.java │ │ ├── MifareAdapter.java │ │ ├── StdMifareImpl.java │ │ └── StdMifareIntent.java │ ├── security │ │ ├── AesUtils.java │ │ ├── CRC16Utils.java │ │ ├── CRC16_14443.java │ │ ├── CRC8Utils.java │ │ └── RSAUtils.java │ ├── status │ │ ├── StatusBarUtil.java │ │ └── SystemBarTintManager.java │ ├── stream │ │ ├── FileListenUtils.java │ │ ├── FileUtils.java │ │ ├── IOUtils.java │ │ ├── LineParseUtils.java │ │ └── ZipUtils.java │ ├── system │ │ ├── AppAssetsUtils.java │ │ ├── AppContextUtils.java │ │ ├── AppListUtils.java │ │ ├── AppResourceUtils.java │ │ ├── AppRestartUtils.java │ │ ├── CrashUtils.java │ │ ├── LanguageUtils.java │ │ ├── LogUtils.java │ │ ├── PermissionUtils.java │ │ ├── RomUtils.java │ │ ├── SystemUtils.java │ │ └── VibratorUtils.java │ └── tools │ │ ├── AccessBitUtil.java │ │ ├── ArrayUtils.java │ │ ├── AssetsUtil.java │ │ ├── Commons.java │ │ ├── CountDown.java │ │ ├── DiskKVUtil.java │ │ ├── FragmentUtils.java │ │ ├── GlobalTag.java │ │ ├── HexUtil.java │ │ ├── MD5Utils.java │ │ ├── MifareUtils.java │ │ ├── NetworkUtils.java │ │ ├── Properties.java │ │ ├── RegexGroupUtils.java │ │ ├── StringUtils.java │ │ ├── TextStyleUtils.java │ │ └── ViewUtils.java └── xmodem │ ├── AbstractXModem.java │ ├── XModem1024.java │ ├── XModem128.java │ └── XModemUtils.java ├── code.rar └── packets ├── .gitignore ├── build.gradle ├── build ├── generated │ └── source │ │ └── buildConfig │ │ ├── debug │ │ └── com │ │ │ └── proxgrind │ │ │ └── chameleon │ │ │ └── packets │ │ │ └── BuildConfig.java │ │ └── release │ │ └── com │ │ └── proxgrind │ │ └── chameleon │ │ └── packets │ │ └── BuildConfig.java ├── intermediates │ ├── aapt_friendly_merged_manifests │ │ ├── debug │ │ │ └── aapt │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── output.json │ │ └── release │ │ │ └── aapt │ │ │ ├── AndroidManifest.xml │ │ │ └── output.json │ ├── annotation_processor_list │ │ ├── debug │ │ │ └── annotationProcessors.json │ │ └── release │ │ │ └── annotationProcessors.json │ ├── compile_library_classes │ │ ├── debug │ │ │ └── classes.jar │ │ └── release │ │ │ └── classes.jar │ ├── compile_only_not_namespaced_r_class_jar │ │ ├── debug │ │ │ └── R.jar │ │ └── release │ │ │ └── R.jar │ ├── compile_symbol_list │ │ ├── debug │ │ │ └── R.txt │ │ └── release │ │ │ └── R.txt │ ├── incremental │ │ ├── debug-mergeNativeLibs │ │ │ └── merge-state │ │ ├── mergeDebugJniLibFolders │ │ │ └── merger.xml │ │ ├── mergeDebugShaders │ │ │ └── merger.xml │ │ ├── mergeReleaseJniLibFolders │ │ │ └── merger.xml │ │ ├── mergeReleaseShaders │ │ │ └── merger.xml │ │ ├── packageDebugAssets │ │ │ └── merger.xml │ │ ├── packageDebugResources │ │ │ ├── compile-file-map.properties │ │ │ └── merger.xml │ │ ├── packageReleaseAssets │ │ │ └── merger.xml │ │ ├── packageReleaseResources │ │ │ ├── compile-file-map.properties │ │ │ └── merger.xml │ │ └── release-mergeNativeLibs │ │ │ └── merge-state │ ├── javac │ │ ├── debug │ │ │ └── classes │ │ │ │ └── com │ │ │ │ └── proxgrind │ │ │ │ └── chameleon │ │ │ │ ├── exceptions │ │ │ │ ├── CMDInvalidException.class │ │ │ │ └── DataInvalidException.class │ │ │ │ └── packets │ │ │ │ ├── BuildConfig.class │ │ │ │ ├── DataBean.class │ │ │ │ ├── DataHead.class │ │ │ │ ├── DataPackets$1.class │ │ │ │ ├── DataPackets$Mode.class │ │ │ │ └── DataPackets.class │ │ └── release │ │ │ └── classes │ │ │ └── com │ │ │ └── proxgrind │ │ │ └── chameleon │ │ │ ├── exceptions │ │ │ ├── CMDInvalidException.class │ │ │ └── DataInvalidException.class │ │ │ └── packets │ │ │ ├── BuildConfig.class │ │ │ ├── DataBean.class │ │ │ ├── DataHead.class │ │ │ ├── DataPackets$1.class │ │ │ ├── DataPackets$Mode.class │ │ │ └── DataPackets.class │ ├── library_java_res │ │ ├── debug │ │ │ └── res.jar │ │ └── release │ │ │ └── res.jar │ ├── library_manifest │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── release │ │ │ └── AndroidManifest.xml │ ├── local_only_symbol_list │ │ ├── debug │ │ │ └── R-def.txt │ │ └── release │ │ │ └── R-def.txt │ ├── manifest_merge_blame_file │ │ ├── debug │ │ │ └── manifest-merger-blame-debug-report.txt │ │ └── release │ │ │ └── manifest-merger-blame-release-report.txt │ ├── merged_manifests │ │ ├── debug │ │ │ └── output.json │ │ └── release │ │ │ └── output.json │ ├── navigation_json │ │ ├── debug │ │ │ └── navigation.json │ │ └── release │ │ │ └── navigation.json │ ├── runtime_library_classes │ │ ├── debug │ │ │ └── classes.jar │ │ └── release │ │ │ └── classes.jar │ └── symbol_list_with_package_name │ │ ├── debug │ │ └── package-aware-r.txt │ │ └── release │ │ └── package-aware-r.txt └── outputs │ └── logs │ ├── manifest-merger-debug-report.txt │ └── manifest-merger-release-report.txt └── src └── main ├── AndroidManifest.xml └── java └── com └── proxgrind └── chameleon ├── exceptions ├── CMDInvalidException.java └── DataInvalidException.java └── packets ├── DataBean.java ├── DataHead.java └── DataPackets.java /README.md: -------------------------------------------------------------------------------- 1 | # Chameleon BLE API 2 | BLE API 3 | 4 | Please download [code.rar](https://github.com/RfidResearchGroup/ChameleonBLEAPI/blob/master/code.rar) for BLE API 5 | -------------------------------------------------------------------------------- /appmain/callback/Basecallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.callback; 2 | 3 | public interface BaseCallback { 4 | 5 | interface ErrorCallback { 6 | void onError(T e); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /appmain/callback/actioncallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.callback; 2 | 3 | public interface ActionCallback { 4 | void onSuccess(S s); 5 | 6 | void onFail(F f); 7 | } 8 | -------------------------------------------------------------------------------- /appmain/defined/Basctypescallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface BasicTypesCallback { 4 | //布尔型 5 | interface BoolType { 6 | void onBool(boolean b); 7 | 8 | void onBools(boolean[] bs); 9 | } 10 | 11 | class BoolTypeEntry implements BoolType { 12 | @Override 13 | public void onBool(boolean b) { 14 | 15 | } 16 | 17 | @Override 18 | public void onBools(boolean[] bs) { 19 | 20 | } 21 | } 22 | 23 | //字符型 24 | interface CharType { 25 | void onChar(char c); 26 | 27 | void onChars(char[] cs); 28 | } 29 | 30 | class CharTypeEntry implements CharType { 31 | @Override 32 | public void onChar(char c) { 33 | 34 | } 35 | 36 | @Override 37 | public void onChars(char[] cs) { 38 | 39 | } 40 | } 41 | 42 | //字节型 43 | interface ByteType { 44 | void onByte(byte b); 45 | 46 | void onBytes(byte[] bs); 47 | } 48 | 49 | class ByteTypeEntry implements ByteType { 50 | @Override 51 | public void onByte(byte b) { 52 | 53 | } 54 | 55 | @Override 56 | public void onBytes(byte[] bs) { 57 | 58 | } 59 | } 60 | 61 | //短整型 62 | interface ShortType { 63 | void onShort(short s); 64 | 65 | void onShorts(short[] ss); 66 | } 67 | 68 | class ShortTypeEntry implements ShortType { 69 | @Override 70 | public void onShort(short s) { 71 | 72 | } 73 | 74 | @Override 75 | public void onShorts(short[] ss) { 76 | 77 | } 78 | } 79 | 80 | //整形 81 | interface IntegerType { 82 | void onInt(int i); 83 | 84 | void onInts(int[] is); 85 | } 86 | 87 | class IntegerTypeEntry implements IntegerType { 88 | @Override 89 | public void onInt(int i) { 90 | 91 | } 92 | 93 | @Override 94 | public void onInts(int[] is) { 95 | 96 | } 97 | } 98 | 99 | //长整型 100 | interface LongType { 101 | void onLong(long l); 102 | 103 | void onLongs(long[] ls); 104 | } 105 | 106 | class LongTypeEntry implements LongType { 107 | @Override 108 | public void onLong(long l) { 109 | 110 | } 111 | 112 | @Override 113 | public void onLongs(long[] ls) { 114 | 115 | } 116 | } 117 | 118 | //单精度浮点 119 | interface FloatType { 120 | void onFloat(float f); 121 | 122 | void onFloats(float[] fs); 123 | } 124 | 125 | class FloatTypeEntry implements FloatType { 126 | @Override 127 | public void onFloat(float f) { 128 | 129 | } 130 | 131 | @Override 132 | public void onFloats(float[] fs) { 133 | 134 | } 135 | } 136 | 137 | //双精度浮点 138 | interface DoubleType { 139 | void onDouble(double d); 140 | 141 | void onDoubles(double[] ds); 142 | } 143 | 144 | class DoubleTypeEntry implements DoubleType { 145 | 146 | @Override 147 | public void onDouble(double d) { 148 | 149 | } 150 | 151 | @Override 152 | public void onDoubles(double[] ds) { 153 | 154 | } 155 | } 156 | 157 | //字符串型! 158 | interface StringType { 159 | void onString(String str); 160 | 161 | void onStrings(String[] str); 162 | } 163 | 164 | class StringTypeEntry implements StringType { 165 | 166 | @Override 167 | public void onString(String str) { 168 | 169 | } 170 | 171 | @Override 172 | public void onStrings(String[] str) { 173 | 174 | } 175 | } 176 | 177 | //对象类型! 178 | interface ObjectType { 179 | void onObject(Object obj); 180 | 181 | void onObjects(Object[] obj); 182 | } 183 | 184 | class ObjectTypeEntry implements ObjectType { 185 | @Override 186 | public void onObject(Object obj) { 187 | 188 | } 189 | 190 | @Override 191 | public void onObjects(Object[] obj) { 192 | 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /appmain/defined/ChameleonCMDSet.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public enum ChameleonCMDSet { 4 | HELP, 5 | GET_VERSION, 6 | RESET_DEVICE, 7 | 8 | GET_MEMORY_SIZE, 9 | GET_UID_SIZE, 10 | 11 | SET_CONFIG, 12 | QUERY_CONFIG, 13 | CONFIG_HELP, 14 | 15 | QUERY_UID, 16 | SET_UID, 17 | 18 | QUERY_READONLY, 19 | SET_READONLY, 20 | 21 | UPLOAD_XMODEM, 22 | DOWNLOAD_XMODEM, 23 | 24 | GET_ACTIVE_SLOT, 25 | SET_ACTIVE_SLOT, 26 | CLEAR_ACTIVE_SLOT, 27 | 28 | GET_RIGHT_BUTTON_CLICK, 29 | SET_RIGHT_BUTTON_CLICK, 30 | BUTTON_RIGHT_CLICK_HELP, 31 | 32 | GET_LEFT_BUTTON_CLICK, 33 | SET_LEFT_BUTTON_CLICK, 34 | BUTTON_LEFT_CLICK_HELP, 35 | 36 | GET_RIGHT_BUTTON_LONG_CLICK, 37 | SET_RIGHT_BUTTON_LONG_CLICK, 38 | BUTTON_RIGHT_CLICK_LONG_HELP, 39 | 40 | GET_LEFT_BUTTON_LONG_CLICK, 41 | SET_LEFT_BUTTON_LONG_CLICK, 42 | BUTTON_LEFT_CLICK_LONG_HELP, 43 | 44 | GET_RSSI_VOLTAGE, 45 | UPLOAD_ENCRYPTED, 46 | DETECTION, 47 | DETECTION_CLEAR, 48 | 49 | GET_SAKMODE, 50 | SET_SAKMODE, 51 | GET_SAKMODE_HELP, 52 | 53 | GET_UIDMODE, 54 | SET_UIDMODE, 55 | GET_UIDMODE_HELP, 56 | 57 | GET_TIMEOUT, 58 | SET_TIMEOUT, 59 | GET_TIMEOUT_HELP, 60 | 61 | GETUID_READER, 62 | KEYAUTH, 63 | SETKEY, 64 | GENKEY, 65 | 66 | CLONE, 67 | } 68 | -------------------------------------------------------------------------------- /appmain/defined/ChameleonClick.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface ChameleonClick { 4 | String CLICK_CLOSED = "CLOSED"; 5 | String CLICK_RANDOM_UID = "RANDOM_UID"; 6 | String CLICK_UID_LEFT_INCREMENT = "UID_LEFT_INCREMENT"; 7 | String CLICK_UID_RIGHT_INCREMENT = "UID_RIGHT_INCREMENT"; 8 | String CLICK_UID_LEFT_DECREMENT = "UID_LEFT_DECREMENT"; 9 | String CLICK_UID_RIGHT_DECREMENT = "UID_RIGHT_DECREMENT"; 10 | String CLICK_SWITCHCARD = "SWITCHCARD"; 11 | } 12 | -------------------------------------------------------------------------------- /appmain/defined/ChameleonRespSet.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | 7 | /** 8 | *

Serial Response Code

9 | * The class SerialRespCode contains extended enum definitions of the possible response 10 | * codes returned by the devices. Also provides helper methods. 11 | */ 12 | public enum ChameleonRespSet { 13 | 14 | /** 15 | * List of the status codes and their corresponding text descriptions 16 | * (taken almost verbatim from the ChameleonMini source code). 17 | */ 18 | OK(100), 19 | OK_WITH_TEXT(101), 20 | WAITING_FOR_MODEM(110), 21 | TRUE(121), 22 | FALSE(120), 23 | UNKNOWN_COMMAND(200), 24 | INVALID_COMMAND_USAGE(201), 25 | INVALID_PARAMETER(202), 26 | TIMEOUT(203); 27 | 28 | /** 29 | * Integer value associated with each enum value. 30 | */ 31 | private int responseCode; 32 | 33 | /** 34 | * Constructor 35 | * 36 | * @param rcode 37 | */ 38 | ChameleonRespSet(int rcode) { 39 | responseCode = rcode; 40 | } 41 | 42 | /** 43 | * Stores a maps of integer-valued response codes to their corresponding enum value. 44 | */ 45 | private static final Map RESP_CODE_MAP = new HashMap<>(); 46 | 47 | static { 48 | for (ChameleonRespSet respCode : values()) { 49 | RESP_CODE_MAP.put(respCode.toInteger(), respCode); 50 | } 51 | } 52 | 53 | /** 54 | * Lookup table of String response codes prefixing command return data sent by the devices. 55 | * 56 | * @ref ChameleonIO.isCommandResponse 57 | */ 58 | public static final Map RESP_CODE_TEXT_MAP = new HashMap<>(); 59 | public static final Map RESP_CODE_TEXT_MAP2 = new HashMap<>(); 60 | 61 | /* 62 | * init response code mapping 63 | * */ 64 | static { 65 | for (ChameleonRespSet respCode : values()) { 66 | String rcode = String.valueOf(respCode.toInteger()); 67 | String rcodeText = respCode.name().replace("_", " "); 68 | RESP_CODE_TEXT_MAP.put(rcode + ":" + rcodeText, respCode); 69 | RESP_CODE_TEXT_MAP2.put(rcode, respCode); 70 | } 71 | } 72 | 73 | /** 74 | * Retrieve the integer-valued response code associated with the enum value. 75 | * 76 | * @return int response code 77 | */ 78 | public int toInteger() { 79 | return responseCode; 80 | } 81 | 82 | /** 83 | * Lookup the enum value by its associated integer response code value. 84 | * 85 | * @param rcode 86 | * @return SerialRespCode enum value associated with the integer code 87 | */ 88 | public static ChameleonRespSet lookupByResponseCode(int rcode) { 89 | return RESP_CODE_MAP.get(rcode); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /appmain/defined/ChameleonType.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public enum ChameleonType { 4 | /* 5 | * 变色龙有版本的区别,分别,G 和 V版本! 6 | * 版本不同命令也不同! 7 | * */ 8 | REVE, 9 | REVG 10 | } 11 | -------------------------------------------------------------------------------- /appmain/defined/DataChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | /** 4 | * 在数据有变动时通知某个对象! 5 | */ 6 | public interface DataChangeListener { 7 | void onChange(T y); 8 | } -------------------------------------------------------------------------------- /appmain/defined/DecryptCallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | import com.proxgrind.chameleon.detection.ResultBean; 4 | 5 | public interface DecryptCallback { 6 | void onMsg(String msg); 7 | 8 | void onKey(ResultBean result); 9 | } -------------------------------------------------------------------------------- /appmain/defined/IChameleonExecutor.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | import java.io.IOException; 4 | 5 | import com.proxgrind.devices.DriverInterface; 6 | 7 | /** 8 | * 接口,定义变色龙的执行器的功能! 9 | * 10 | * @author DXL 11 | */ 12 | public interface IChameleonExecutor { 13 | boolean initExecutor(DriverInterface com); 14 | 15 | byte[] requestChameleon(String at, int timeout, boolean xmodemMode); 16 | 17 | byte[] requestChameleon(int timeout, int length); 18 | 19 | int requestChameleon(String at, int timeout) throws IOException; 20 | 21 | DriverInterface getDriver(); 22 | 23 | int clear(int timeout); 24 | 25 | void close(); 26 | 27 | String getVersion(); 28 | 29 | boolean isConnected(); 30 | } 31 | -------------------------------------------------------------------------------- /appmain/defined/OnConnectListener.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface OnConnectListener { 4 | void onConnectStart(); 5 | 6 | void onConnectEnd(); 7 | } 8 | -------------------------------------------------------------------------------- /appmain/defined/OnDfuRuniingListener.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface OnDfuRuniingListener { 4 | void onRun(String address); 5 | } 6 | -------------------------------------------------------------------------------- /appmain/defined/OnTouchListener.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | import android.view.MotionEvent; 4 | 5 | /* 6 | * 在触发时的回调! 7 | * */ 8 | public interface OnTouchListener { 9 | boolean onTouch(MotionEvent event); 10 | } -------------------------------------------------------------------------------- /appmain/defined/RegexCommon.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface RegexCommon { 4 | 5 | //邮箱匹配规则! 6 | String email = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?"; 7 | } 8 | -------------------------------------------------------------------------------- /appmain/defined/ResultCallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.defined; 2 | 3 | public interface ResultCallback { 4 | void onSuccess(S s); 5 | 6 | void onFaild(F f); 7 | } 8 | -------------------------------------------------------------------------------- /appmain/devices/BleCMDControl.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.devices; 2 | 3 | import com.proxgrind.chameleon.javabean.DeviceInfo; 4 | import com.proxgrind.chameleon.packets.DataPackets; 5 | import com.proxgrind.chameleon.utils.system.LogUtils; 6 | import com.proxgrind.chameleon.utils.tools.HexUtil; 7 | 8 | import java.io.IOException; 9 | import java.util.Arrays; 10 | 11 | /* 12 | * 同步任务! 13 | * 将会给对象上锁! 14 | * */ 15 | public class BleCMDControl { 16 | /** 17 | * 命令定义区域,我们需要进行命令包标志的定义! 18 | */ 19 | private static final int BLE_INFO = 0X69; 20 | 21 | private static final BleSerialControl control = BleSerialControl.get(); 22 | private static final int BLE_INFO_PACKET_SIZE_MAX_MINI = 77; 23 | private static final int BLE_INFO_PACKET_SIZE_MAX_TINY = 25; 24 | private static final int TRANSFER_TIMEOUT = 2000; 25 | private static final int REVEICE_TIMEOUT = TRANSFER_TIMEOUT; 26 | 27 | public static DeviceInfo getBLEInfo() { 28 | DeviceInfo info = new DeviceInfo(); 29 | // 谨记上锁! 30 | synchronized (control) { 31 | if (control.isDeviceConnected()) { 32 | try { 33 | if (isChameleonMini()) { 34 | getInfoFromMini(info); 35 | } else { 36 | getInfoFromTiny(info); 37 | } 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | } else { 42 | LogUtils.d("设备未连接,可能通讯是USB"); 43 | } 44 | return info; 45 | } 46 | } 47 | 48 | public static boolean isChameleonMini() { 49 | return !control.isCtrlCharacteristicExists(); 50 | } 51 | 52 | private static void getInfoFromMini(DeviceInfo info) throws IOException { 53 | control.setPushDataToBuffer(false); 54 | // 打包一个命令! 55 | byte[] infoCMD = DataPackets.getData(BLE_INFO); 56 | control.write(infoCMD, 0, infoCMD.length, TRANSFER_TIMEOUT); 57 | byte[] recvs = new byte[BLE_INFO_PACKET_SIZE_MAX_MINI]; 58 | if (control.read(recvs, 0, 0, REVEICE_TIMEOUT) >= BLE_INFO_PACKET_SIZE_MAX_MINI) { 59 | // 主版本号 60 | info.setMainVersion(recvs[0]); 61 | // 次版本号 62 | info.setMinorVersion(recvs[1]); 63 | // 版本特性 64 | info.setVersionFlag(HexUtil.byteArrayToInt(new byte[]{recvs[5], recvs[4], recvs[3], recvs[2]})); 65 | // 版本字符串(BLE) 66 | info.setBleVersion(new String(Arrays.copyOfRange(recvs, 6, 37))); 67 | // BLE电池电压! 68 | info.setBatteryVoltage(HexUtil.byteArrayToInt(new byte[]{recvs[41], recvs[40], recvs[39], recvs[38]})); 69 | // BLE电池百分比! 70 | info.setBatteryPercent(recvs[42]); 71 | // AVR相关参数! 72 | info.setAvrMainVersion(recvs[43]); 73 | info.setAvrMinorVersion(recvs[44]); 74 | info.setAvrVersion(new String(Arrays.copyOfRange(recvs, 44, 74))); 75 | } else { 76 | LogUtils.d("接收到的长度字节不够!"); 77 | } 78 | control.setPushDataToBuffer(true); 79 | } 80 | 81 | private static void getInfoFromTiny(DeviceInfo info) throws IOException { 82 | LogUtils.d("请求Tiny的信息"); 83 | control.setPushDataToBuffer(false); 84 | byte[] infoCMD = new byte[]{(byte) 0XA5, 0X69, 0X00, 0X00}; 85 | // Tiny分离出来了一个控制点特征单独用来进行UART之外的操作! 86 | // 因此我们需要往Tiny的控制特征写,而不是往标准的UART写接口写。 87 | control.write(infoCMD, 0, infoCMD.length, TRANSFER_TIMEOUT, BleSerialControl.CTRL_CHARACT_UUID); 88 | byte[] recvs = new byte[1024]; 89 | if (control.read(recvs, 0, 0, REVEICE_TIMEOUT) >= BLE_INFO_PACKET_SIZE_MAX_TINY) { 90 | // BLE电池电压! 91 | info.setBatteryVoltage(HexUtil.toIntFrom2Byte(new byte[]{recvs[1], recvs[0]})); 92 | // BLE电池百分比! 93 | info.setBatteryPercent(recvs[2]); 94 | // BLE版本号 95 | info.setBleVersion(new String(Arrays.copyOfRange(recvs, 3, 18))); 96 | } else { 97 | LogUtils.d("接收到的长度字节不够!"); 98 | } 99 | control.setPushDataToBuffer(true); 100 | } 101 | 102 | public static void openAirplaneMode() { 103 | new Thread(new Runnable() { 104 | @Override 105 | public void run() { 106 | byte[] infoCMD = new byte[]{(byte) 0XA5, 0X6B, 0X00, 0X00}; 107 | try { 108 | control.write(infoCMD, 0, infoCMD.length, TRANSFER_TIMEOUT, BleSerialControl.CTRL_CHARACT_UUID); 109 | } catch (IOException e) { 110 | e.printStackTrace(); 111 | } 112 | } 113 | }).start(); 114 | } 115 | 116 | /** 117 | * 进行数据的传输与应答帧的接收 118 | */ 119 | public static byte[] tranRecv(int cmd, byte[] data, int timeout) { 120 | BleSerialControl control = BleSerialControl.get(); 121 | if (!control.isDeviceConnected()) return null; 122 | // 关闭缓冲区转发 123 | control.setPushDataToBuffer(false); 124 | // 拼包并且发送数据! 125 | byte[] sendPack = new DataPackets(cmd, data).getData(); 126 | byte[] ret = new byte[BleSerialControl.MTU]; 127 | try { 128 | control.write(sendPack, 0, sendPack.length, timeout); 129 | int status = control.read(ret, 0, 0, timeout); 130 | if (status == -1) { 131 | //超时了,我们返回空的字节组表示超时 132 | return new byte[0]; 133 | } 134 | } catch (IOException e) { 135 | e.printStackTrace(); 136 | return null; 137 | } 138 | // 回复缓冲区转发 139 | control.setPushDataToBuffer(true); 140 | return ret; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /appmain/devices/DevCallback.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.devices; 2 | 3 | import java.io.Serializable; 4 | 5 | public interface DevCallback extends Serializable { 6 | // 是否符合设备预期 7 | boolean isDev(T dev); 8 | 9 | //新设备发现回调 10 | void onAttach(T dev); 11 | 12 | //设备移除回调 13 | void onDetach(T dev); 14 | } 15 | -------------------------------------------------------------------------------- /appmain/devices/Device.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.devices; 2 | 3 | import java.io.IOException; 4 | import java.io.Serializable; 5 | 6 | public interface Device extends Serializable { 7 | //设备测试连通性! 8 | boolean working() throws IOException; 9 | 10 | //设备关闭! 11 | boolean close() throws IOException; 12 | } 13 | -------------------------------------------------------------------------------- /appmain/devices/DriverInterface.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.devices; 2 | 3 | import android.app.Application; 4 | 5 | import com.proxgrind.chameleon.posixio.PosixCom; 6 | import com.proxgrind.chameleon.utils.system.AppContextUtils; 7 | import com.proxgrind.chameleon.callback.ConnectCallback; 8 | 9 | /* 10 | * 驱动程序类 11 | * 泛型1 -> 设备实体类 12 | * 泛型2 -> 适配器类 13 | */ 14 | public interface DriverInterface extends PosixCom { 15 | Application context = AppContextUtils.app; 16 | 17 | //注册广播之类的事件 18 | void register(DevCallback callback); 19 | 20 | //链接到设备 21 | void connect(Device t, ConnectCallback callback); 22 | 23 | // 设备是否连接! 24 | boolean isDeviceConnected(); 25 | 26 | //得到当前的驱动程序适配器类 27 | Adapter getAdapter(); 28 | 29 | //得到当前的驱动程序的设备类 30 | Device getDevice(); 31 | 32 | //断开与设备的链接(在某些设备上不一定是立刻生效的) 33 | void disconnect(); 34 | 35 | //获得驱动的ID! 36 | int getUniqueId(); 37 | 38 | //解注册广播之类的 39 | void unregister(); 40 | } -------------------------------------------------------------------------------- /appmain/devices/EmptyDevice.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.devices; 2 | 3 | import java.io.IOException; 4 | 5 | public class EmptyDevice implements Device { 6 | @Override 7 | public boolean working() throws IOException { 8 | return true; 9 | } 10 | 11 | @Override 12 | public boolean close() throws IOException { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /appmain/executor/ChameleonBleExecutor.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.executor; 2 | 3 | import com.proxgrind.chameleon.utils.tools.HexUtil; 4 | import com.proxgrind.chameleon.utils.system.LogUtils; 5 | import com.proxgrind.chameleon.utils.system.SystemUtils; 6 | import com.proxgrind.chameleon.defined.IChameleonExecutor; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | 11 | /** 12 | * @author DXL 13 | * BLE执行器实现类,具体封装了执行和获得返回值的函数! 14 | * 由于BLE的通讯原因,我们必须实现封包和解包! 15 | */ 16 | public class ChameleonBleExecutor extends ChameleonStdExecutor { 17 | 18 | private static ChameleonBleExecutor executor = new ChameleonBleExecutor(); 19 | 20 | /** 21 | * @return 单例 22 | */ 23 | public static IChameleonExecutor get() { 24 | return executor; 25 | } 26 | 27 | /** 28 | * @param at 指令,ascii编码集,需要在后缀附带\r换行! 29 | * @param timeout 超时,多久之后接收不到完整的数据帧自动返回? 30 | * @return 设备的返回信息,可能超时(无返回值),如果超时则返回null,否则返回对应命令的应答! 31 | */ 32 | @Override 33 | public byte[] requestChameleon(String at, int timeout, boolean xmodemMode) { 34 | LogUtils.d("发送的指令: " + at); 35 | //初始化必须的变量 36 | ByteArrayOutputStream bos = new ByteArrayOutputStream(512); 37 | try { 38 | mCom.flush(); 39 | //请求并且判断结果! 40 | if (requestChameleon(at, timeout) == -1) return null; 41 | long currentTime = System.currentTimeMillis(); 42 | //LogUtils.d("当前线程ID: " + Thread.currentThread().getId()); 43 | do { 44 | if (SystemUtils.isTimeout(currentTime, timeout)) return null; 45 | //开始接收,每次接收一个字节! 46 | byte tmpByte = read(0); 47 | if (tmpByte != -1) { 48 | //接收完毕,有有效的字节!!! 49 | bos.write(tmpByte); 50 | //Log.d(LOG_TAG, "打印接收到的字节: " + HexUtil.toHexString(tmpByte)); 51 | //有有效数据,进行超时拖延! 52 | currentTime = System.currentTimeMillis(); 53 | //判断到换行,则可能是一帧的结束! 54 | // FIXME: 2019/4/21 谨记,上传或下载将会打开xmodem通道,此时应当进行判断,断定下一步的操作! 55 | if (tmpByte == 0x0A) { 56 | //Log.d(LOG_TAG, "有换行,下一步判断是否需要继续接收!"); 57 | if (!xmodemMode) { 58 | //延迟判断新行,延迟最大限度提升成功率!!! 59 | tmpByte = read(5); 60 | if (tmpByte != -1) { 61 | //Log.d(LOG_TAG, "需要"); 62 | bos.write(tmpByte); 63 | currentTime = System.currentTimeMillis(); 64 | } else { 65 | //Log.d(LOG_TAG, "不需要"); 66 | //接收完毕,直接返回! 67 | //Log.d(LOG_TAG, "锁释放完成: " + Thread.currentThread().getId()); 68 | return bos.toByteArray(); 69 | } 70 | } else { 71 | LogUtils.d("XModem模式,终止接收!"); 72 | return bos.toByteArray(); 73 | } 74 | } 75 | } 76 | } while (true); //超时中处理! 77 | } catch (IOException e) { 78 | e.printStackTrace(); 79 | return null; 80 | } 81 | } 82 | 83 | /** 84 | * 在指定的时间内接收指定的长度的值, 85 | * 86 | * @param timeout 超时值 87 | * @param length 欲接收的长度! 88 | * @return 接收结果! 89 | */ 90 | @Override 91 | public byte[] requestChameleon(int timeout, int length) { 92 | byte[] ret = new byte[length]; 93 | int pos = 0; 94 | long currentTime = System.currentTimeMillis(); 95 | //Log.d(LOG_TAG, "得到锁成功,当前线程ID: " + Thread.currentThread().getId()); 96 | do { 97 | //开始接收,每次接收一个字节! 98 | byte tmpByte = read(timeout); 99 | if (tmpByte != -1) { 100 | ret[pos] = tmpByte; 101 | if (++pos == length) break; 102 | } 103 | } while (SystemUtils.isTimeout(currentTime, timeout)); //超时中处理! 104 | return ret; 105 | } 106 | 107 | /** 108 | * @param at 指令,ascii编码集,需要在后缀附带\r换行! 109 | * @param timeout 超时,多久之后接收不到完整的数据帧自动返回? 110 | * @return 发送成功的字节数,如果发送失败则返回 -1 111 | */ 112 | @Override 113 | public int requestChameleon(String at, int timeout) throws IOException { 114 | if (at == null) return -1; 115 | //Log.d(LOG_TAG, "尝试得到锁,当前线程ID: " + Thread.currentThread().getId()); 116 | //发送命令必须回应,否则系命令错误! 117 | // TODO 不用自己加回车! 118 | //Log.d(LOG_TAG, "发送的命令: " + at); 119 | //at = checkAT(at); 120 | byte[] sendBuf = HexUtil.getAsciiBytes(at); 121 | // BLE进行了封包,我们此处需要封包! TODO 在外部,给对象进行注入封包! 122 | //sendBuf = DataPackage.dopack(sendBuf, DataPackage.TEXT_HEX); 123 | return mCom.write(sendBuf, 0, sendBuf.length, timeout); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /appmain/executor/ChameleonExecutorProxy.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.executor; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | 6 | import com.proxgrind.chameleon.defined.BasicTypesCallback; 7 | import com.proxgrind.chameleon.posixio.PosixCom; 8 | import com.proxgrind.chameleon.defined.IChameleonExecutor; 9 | import com.proxgrind.chameleon.utils.system.SystemUtils; 10 | import com.proxgrind.devices.DriverInterface; 11 | 12 | /** 13 | * 这个类实际是个代理类,留了一个接口来初始化其中引用的实际(执行器)的实现! 14 | * 抽出这个类主要是为了实现将具体的类隐匿。 15 | * 因此我们需要将初始化的必要接口留下来,此类也必须是单例! 16 | * 17 | * @author DXL 18 | */ 19 | public class ChameleonExecutorProxy implements IChameleonExecutor { 20 | 21 | private static IChameleonExecutor mExecutor; 22 | private static ChameleonExecutorProxy mImpl; 23 | private ArrayList entrys = new ArrayList<>(); 24 | 25 | public static void setExecutor(IChameleonExecutor executor) throws RuntimeException { 26 | mExecutor = executor; 27 | } 28 | 29 | public static ChameleonExecutorProxy getInstance() { 30 | synchronized (ChameleonExecutorProxy.class) { 31 | if (mImpl == null) mImpl = new ChameleonExecutorProxy(); 32 | } 33 | return mImpl; 34 | } 35 | 36 | @Override 37 | public boolean initExecutor(DriverInterface com) { 38 | if (mExecutor != null) 39 | return mExecutor.initExecutor(com); 40 | return false; 41 | } 42 | 43 | @Override 44 | public byte[] requestChameleon(String at, int timeout, boolean xmodemMode) { 45 | if (mExecutor != null) 46 | return callback(mExecutor.requestChameleon(at, timeout, xmodemMode)); 47 | else return "Device Disconnected".getBytes(); 48 | } 49 | 50 | @Override 51 | public byte[] requestChameleon(int timeout, int length) { 52 | if (mExecutor != null) 53 | return callback(mExecutor.requestChameleon(timeout, length)); 54 | else return "Device Disconnected".getBytes(); 55 | } 56 | 57 | @Override 58 | public int requestChameleon(String at, int timeout) throws IOException { 59 | if (mExecutor != null) 60 | return mExecutor.requestChameleon(at, timeout); 61 | else 62 | return -1; 63 | } 64 | 65 | @Override 66 | public DriverInterface getDriver() { 67 | if (mExecutor == null) return null; 68 | return mExecutor.getDriver(); 69 | } 70 | 71 | @Override 72 | public int clear(int timeout) { 73 | if (mExecutor != null) 74 | return mExecutor.clear(timeout); 75 | else return -1; 76 | } 77 | 78 | @Override 79 | public void close() { 80 | try { 81 | DriverInterface driverInterface = getDriver(); 82 | if (driverInterface != null) { 83 | driverInterface.disconnect(); 84 | driverInterface.close(); 85 | } 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | 91 | @Override 92 | public String getVersion() { 93 | if (mExecutor != null) 94 | return mExecutor.getVersion(); 95 | else 96 | return "Device Disconnected"; 97 | } 98 | 99 | @Override 100 | public boolean isConnected() { 101 | if (mExecutor != null) 102 | return mExecutor.isConnected(); 103 | return false; 104 | } 105 | 106 | public void addEntry(BasicTypesCallback.ByteType entry) { 107 | this.entrys.add(entry); 108 | } 109 | 110 | public void removeEntry(BasicTypesCallback.ByteType entry) { 111 | this.entrys.remove(entry); 112 | } 113 | 114 | public byte[] callback(byte[] in) { 115 | if (entrys.size() > 0) 116 | for (BasicTypesCallback.ByteType type : entrys) { 117 | type.onBytes(in); 118 | } 119 | return in; 120 | } 121 | 122 | public IChameleonExecutor getExecutorInternalImpl() { 123 | return mExecutor; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /appmain/executor/ChameleonUsbExecutor.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.executor; 2 | 3 | import com.proxgrind.chameleon.defined.IChameleonExecutor; 4 | 5 | /** 6 | * @author DXL 7 | * USB执行器实现类,具体封装了执行和获得返回值的函数! 8 | */ 9 | public class ChameleonUsbExecutor extends ChameleonStdExecutor implements IChameleonExecutor { 10 | 11 | private static final ChameleonUsbExecutor executor = new ChameleonUsbExecutor(); 12 | 13 | /** 14 | * @return 单例 15 | */ 16 | public static IChameleonExecutor get() { 17 | return executor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /appmain/javabean/DecryptOrder.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class DecryptOrder { 4 | private String uid; 5 | private String[] keys; 6 | 7 | public DecryptOrder() { 8 | } 9 | 10 | public DecryptOrder(String uid, String[] keys) { 11 | this.uid = uid; 12 | this.keys = keys; 13 | } 14 | 15 | public String getUid() { 16 | return uid; 17 | } 18 | 19 | public void setUid(String uid) { 20 | this.uid = uid; 21 | } 22 | 23 | public String[] getKeys() { 24 | return keys; 25 | } 26 | 27 | public void setKeys(String[] keys) { 28 | this.keys = keys; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /appmain/javabean/DetectionLog.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class DetectionLog { 4 | // 类型 5 | private int type; 6 | // 数据 7 | private byte[] data; 8 | // 时间戳 9 | private int timestamp; 10 | 11 | public int getType() { 12 | return type; 13 | } 14 | 15 | public void setType(int type) { 16 | this.type = type; 17 | } 18 | 19 | public byte[] getData() { 20 | return data; 21 | } 22 | 23 | public void setData(byte[] data) { 24 | this.data = data; 25 | } 26 | 27 | public int getTimestamp() { 28 | return timestamp; 29 | } 30 | 31 | public void setTimestamp(int timestamp) { 32 | this.timestamp = timestamp; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /appmain/javabean/DevBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Created by DXL on 2017/11/14. 9 | */ 10 | public class DevBean implements Serializable { 11 | 12 | private String devName = ""; 13 | private String macAddress = ""; 14 | private Object object; 15 | 16 | public DevBean(String name, String addr) { 17 | if (name != null) 18 | this.devName = name; 19 | if (addr != null) 20 | this.macAddress = addr; 21 | } 22 | 23 | public DevBean(String devName, String macAddress, Object object) { 24 | this.devName = devName; 25 | this.macAddress = macAddress; 26 | this.object = object; 27 | } 28 | 29 | public String getDevName() { 30 | return devName; 31 | } 32 | 33 | public String getMacAddress() { 34 | return macAddress; 35 | } 36 | 37 | public Object getObject() { 38 | return object; 39 | } 40 | 41 | public void setObject(Object object) { 42 | this.object = object; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "DevBean{" + 48 | "devName='" + devName + '\'' + 49 | ", macAddress='" + macAddress + '\'' + 50 | ", object=" + object + 51 | '}'; 52 | } 53 | 54 | @Override 55 | public boolean equals(@Nullable Object obj) { 56 | if (obj == this) return true; 57 | if (obj instanceof DevBean) { 58 | return (((DevBean) obj).getMacAddress() 59 | .equals(getMacAddress())); 60 | } 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /appmain/javabean/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class DeviceInfo { 4 | private int mainVersion; 5 | private int minorVersion; 6 | private int versionFlag; 7 | private String bleVersion; 8 | private int batteryVoltage; 9 | private int batteryPercent; 10 | private int avrMainVersion; 11 | private int avrMinorVersion; 12 | private String avrVersion; 13 | 14 | public int getMainVersion() { 15 | return mainVersion; 16 | } 17 | 18 | public void setMainVersion(int mainVersion) { 19 | this.mainVersion = mainVersion; 20 | } 21 | 22 | public int getMinorVersion() { 23 | return minorVersion; 24 | } 25 | 26 | public void setMinorVersion(int minorVersion) { 27 | this.minorVersion = minorVersion; 28 | } 29 | 30 | public int getVersionFlag() { 31 | return versionFlag; 32 | } 33 | 34 | public void setVersionFlag(int versionFlag) { 35 | this.versionFlag = versionFlag; 36 | } 37 | 38 | public int getBatteryVoltage() { 39 | return batteryVoltage; 40 | } 41 | 42 | public void setBatteryVoltage(int batteryVoltage) { 43 | this.batteryVoltage = batteryVoltage; 44 | } 45 | 46 | public int getBatteryPercent() { 47 | return batteryPercent; 48 | } 49 | 50 | public void setBatteryPercent(int batteryPercent) { 51 | this.batteryPercent = batteryPercent; 52 | } 53 | 54 | public int getAvrMainVersion() { 55 | return avrMainVersion; 56 | } 57 | 58 | public void setAvrMainVersion(int avrMainVersion) { 59 | this.avrMainVersion = avrMainVersion; 60 | } 61 | 62 | public int getAvrMinorVersion() { 63 | return avrMinorVersion; 64 | } 65 | 66 | public void setAvrMinorVersion(int avrMinorVersion) { 67 | this.avrMinorVersion = avrMinorVersion; 68 | } 69 | 70 | public String getAvrVersion() { 71 | return avrVersion; 72 | } 73 | 74 | public void setAvrVersion(String avrVersion) { 75 | this.avrVersion = avrVersion; 76 | } 77 | 78 | public String getBleVersion() { 79 | return bleVersion; 80 | } 81 | 82 | public void setBleVersion(String bleVersion) { 83 | this.bleVersion = bleVersion; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /appmain/javabean/DumpBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public class DumpBean { 6 | private String time; 7 | private String uid; 8 | private int position; 9 | @NonNull 10 | private String name = ""; 11 | 12 | private DumpBean() { 13 | } 14 | 15 | public DumpBean(@NonNull String name) { 16 | this.name = name; 17 | } 18 | 19 | public String getTime() { 20 | return time; 21 | } 22 | 23 | public void setTime(String time) { 24 | this.time = time; 25 | } 26 | 27 | public String getUid() { 28 | return uid; 29 | } 30 | 31 | public void setUid(String uid) { 32 | this.uid = uid; 33 | } 34 | 35 | public int getPosition() { 36 | return position; 37 | } 38 | 39 | public void setPosition(int position) { 40 | this.position = position; 41 | } 42 | 43 | @NonNull 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(@NonNull String name) { 49 | this.name = name; 50 | } 51 | 52 | @NonNull 53 | @Override 54 | public String toString() { 55 | return "DumpBean{" + 56 | "time='" + time + '\'' + 57 | ", uid='" + uid + '\'' + 58 | ", position=" + position + 59 | ", name='" + name + '\'' + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /appmain/javabean/FileBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class FileBean { 4 | private boolean isFile; 5 | private String name; 6 | private String info; 7 | private String path; 8 | 9 | public FileBean() { 10 | } 11 | 12 | public FileBean(boolean isFile, String name, String path, String info) { 13 | this.isFile = isFile; 14 | this.name = name; 15 | this.info = info; 16 | this.path = path; 17 | } 18 | 19 | public boolean isFile() { 20 | return isFile; 21 | } 22 | 23 | public void setFile(boolean file) { 24 | isFile = file; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public String getInfo() { 36 | return info; 37 | } 38 | 39 | public void setInfo(String info) { 40 | this.info = info; 41 | } 42 | 43 | public String getPath() { 44 | return path; 45 | } 46 | 47 | public void setPath(String path) { 48 | this.path = path; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "FileBean{" + 54 | "isFile=" + isFile + 55 | ", name='" + name + '\'' + 56 | ", info='" + info + '\'' + 57 | ", path='" + path + '\'' + 58 | '}'; 59 | } 60 | 61 | // 回调! 62 | public void onClick() { 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /appmain/javabean/ItemCommonBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import android.view.View; 4 | 5 | public class ItemCommonBean extends TitleBean { 6 | private String subTitle = ""; 7 | private int iconResID; 8 | 9 | public ItemCommonBean(String title) { 10 | super(title); 11 | } 12 | 13 | public String getSubTitle() { 14 | return subTitle; 15 | } 16 | 17 | public void setSubTitle(String subTitle) { 18 | this.subTitle = subTitle; 19 | } 20 | 21 | public int getIconResID() { 22 | return iconResID; 23 | } 24 | 25 | public void setIconResID(int iconResID) { 26 | this.iconResID = iconResID; 27 | } 28 | 29 | public void onClick(View view, int pos) { 30 | } 31 | 32 | public void onChange(View view, int pos, boolean checked) { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /appmain/javabean/ItemTextBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class ItemTextBean extends ItemCommonBean { 4 | private String message; 5 | 6 | public ItemTextBean(String title) { 7 | super(title); 8 | } 9 | 10 | public String getMessage() { 11 | return message; 12 | } 13 | 14 | public void setMessage(String message) { 15 | this.message = message; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /appmain/javabean/ItemToggleBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class ItemToggleBean extends ItemCommonBean { 4 | private boolean checked; 5 | 6 | public ItemToggleBean(String title) { 7 | super(title); 8 | } 9 | 10 | public boolean isChecked() { 11 | return checked; 12 | } 13 | 14 | public void setChecked(boolean checked) { 15 | this.checked = checked; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /appmain/javabean/KeyValueTipsBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import android.view.View; 4 | 5 | public class KeyValueTipsBean implements View.OnClickListener { 6 | private int iconId; 7 | private String key; 8 | private String value; 9 | 10 | public KeyValueTipsBean(int iconId, String key, String value) { 11 | this.iconId = iconId; 12 | this.key = key; 13 | this.value = value; 14 | } 15 | 16 | public KeyValueTipsBean() { 17 | } 18 | 19 | public int getIconId() { 20 | return iconId; 21 | } 22 | 23 | public void setIconId(int iconId) { 24 | this.iconId = iconId; 25 | } 26 | 27 | public String getKey() { 28 | return key; 29 | } 30 | 31 | public void setKey(String key) { 32 | this.key = key; 33 | } 34 | 35 | public String getValue() { 36 | return value; 37 | } 38 | 39 | public void setValue(String value) { 40 | this.value = value; 41 | } 42 | 43 | @Override 44 | public void onClick(View v) { 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /appmain/javabean/M1KeyBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | /* 6 | * 这个bean是用来存放验证完成后的key 7 | */ 8 | public class M1KeyBean { 9 | //扇区号 10 | private int sector; 11 | 12 | //ab密钥 13 | private String keyA; 14 | private String keyB; 15 | 16 | public int getSector() { 17 | return sector; 18 | } 19 | 20 | public void setSector(int sector) { 21 | this.sector = sector; 22 | } 23 | 24 | public String getKeyA() { 25 | return keyA; 26 | } 27 | 28 | public void setKeyA(String keyA) { 29 | this.keyA = keyA; 30 | } 31 | 32 | public String getKeyB() { 33 | return keyB; 34 | } 35 | 36 | public void setKeyB(String keyB) { 37 | this.keyB = keyB; 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public String toString() { 43 | return "M1KeyBean{" + 44 | "sector=" + sector + 45 | ", keyA='" + keyA + '\'' + 46 | ", keyB='" + keyB + '\'' + 47 | '}'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /appmain/javabean/MifareBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import java.io.Serializable; 4 | import java.util.Arrays; 5 | 6 | public class MifareBean implements Serializable { 7 | 8 | //扇区号 9 | private int sector; 10 | //数据块的数据 11 | private String[] datas; 12 | 13 | public MifareBean() { 14 | } 15 | 16 | public MifareBean(int sector) { 17 | this.sector = sector; 18 | } 19 | 20 | public MifareBean(int sector, String[] datas) { 21 | this.sector = sector; 22 | this.datas = datas; 23 | } 24 | 25 | public int getSector() { 26 | return sector; 27 | } 28 | 29 | public void setSector(int sector) { 30 | this.sector = sector; 31 | } 32 | 33 | public String[] getDatas() { 34 | return datas; 35 | } 36 | 37 | public void setDatas(String[] datas) { 38 | this.datas = datas; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "M1Bean{" + 44 | "sector=" + sector + 45 | ", datas=" + Arrays.toString(datas) + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /appmain/javabean/SlotAction.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import com.proxgrind.chameleon.utils.chameleon.ChameleonUtils; 4 | 5 | public class SlotAction { 6 | private String leftClick = ChameleonUtils.DEFAULT_BTN_DEFAULT[6]; 7 | private String rightClick = ChameleonUtils.DEFAULT_BTN_DEFAULT[6]; 8 | private String leftLongClick = ChameleonUtils.DEFAULT_BTN_DEFAULT[6]; 9 | private String rightLongClick = ChameleonUtils.DEFAULT_BTN_DEFAULT[6]; 10 | private boolean isUidMode; 11 | 12 | public String getRightClick() { 13 | return rightClick; 14 | } 15 | 16 | public void setRightClick(String rightClick) { 17 | this.rightClick = rightClick; 18 | } 19 | 20 | public String getLeftClick() { 21 | return leftClick; 22 | } 23 | 24 | public void setLeftClick(String leftClick) { 25 | this.leftClick = leftClick; 26 | } 27 | 28 | public String getLeftLongClick() { 29 | return leftLongClick; 30 | } 31 | 32 | public void setLeftLongClick(String leftLongClick) { 33 | this.leftLongClick = leftLongClick; 34 | } 35 | 36 | public String getRightLongClick() { 37 | return rightLongClick; 38 | } 39 | 40 | public void setRightLongClick(String rightLongClick) { 41 | this.rightLongClick = rightLongClick; 42 | } 43 | 44 | public boolean isUidMode() { 45 | return isUidMode; 46 | } 47 | 48 | public void setUidMode(boolean uidMode) { 49 | isUidMode = uidMode; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /appmain/javabean/SlotBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.proxgrind.chameleon.R; 6 | import com.proxgrind.chameleon.utils.system.AppContextUtils; 7 | 8 | public class SlotBean { 9 | private int position; 10 | private String uid = "00000000"; 11 | private String mode = "NONE"; 12 | private boolean isValid = true; 13 | private boolean isOffline = true; 14 | private int size; 15 | private boolean isSakMode = false; 16 | 17 | public SlotBean(int position) { 18 | this.position = position; 19 | } 20 | 21 | public boolean isOffline() { 22 | return isOffline; 23 | } 24 | 25 | public void setOffline(boolean offline) { 26 | isOffline = offline; 27 | } 28 | 29 | public int getSize() { 30 | return size; 31 | } 32 | 33 | public void setSize(int size) { 34 | this.size = size; 35 | } 36 | 37 | public boolean isValid() { 38 | return isValid; 39 | } 40 | 41 | public void setValid(boolean valid) { 42 | isValid = valid; 43 | } 44 | 45 | public String getUid() { 46 | return uid; 47 | } 48 | 49 | public void setUid(String uid) { 50 | this.uid = uid; 51 | } 52 | 53 | public String getMode() { 54 | return mode; 55 | } 56 | 57 | public void setMode(String mode) { 58 | this.mode = mode; 59 | } 60 | 61 | public int getPosition() { 62 | return position; 63 | } 64 | 65 | public void setPosition(int position) { 66 | this.position = position; 67 | } 68 | 69 | public boolean isSakMode() { 70 | return isSakMode; 71 | } 72 | 73 | public void setSakMode(boolean sakMode) { 74 | isSakMode = sakMode; 75 | } 76 | 77 | @NonNull 78 | @Override 79 | public String toString() { 80 | return "SlotBean{" + 81 | "position=" + position + 82 | ", uid='" + uid + '\'' + 83 | ", mode='" + mode + '\'' + 84 | ", isValid=" + isValid + 85 | ", isOffline=" + isOffline + 86 | ", size=" + size + 87 | ", isSakMode=" + isSakMode + 88 | '}'; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /appmain/javabean/TitleBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.javabean; 2 | 3 | public class TitleBean { 4 | private String title = ""; 5 | 6 | public TitleBean(String title) { 7 | this.title = title; 8 | } 9 | 10 | public String getTitle() { 11 | return title; 12 | } 13 | 14 | public void setTitle(String title) { 15 | this.title = title; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "TitleBean{" + 21 | "title='" + title + '\'' + 22 | '}'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /appmain/posixio/PosixCom.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.posixio; 2 | 3 | import java.io.Closeable; 4 | import java.io.Flushable; 5 | import java.io.IOException; 6 | import java.io.Serializable; 7 | 8 | /* 9 | * author DXL 10 | * 通信接口,实现了必要的元素传递以及通信实现规定,可以用来桥接通讯! 11 | * Communication interface, All communication bridger! 12 | */ 13 | public interface PosixCom extends Serializable, Closeable, Flushable { 14 | 15 | //实现了发送消息 16 | int write(byte[] sendMsg, int offset, int length, int timeout) throws IOException; 17 | 18 | //实现了接收消息 19 | int read(byte[] recvMsg, int offset, int length, int timeout) throws IOException; 20 | 21 | //实现了刷新消息 22 | @Override 23 | void flush() throws IOException; 24 | 25 | //实现了通信关闭 26 | @Override 27 | void close() throws IOException; 28 | } 29 | -------------------------------------------------------------------------------- /appmain/utils/device/ble/BLERawUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.device.ble; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.proxgrind.chameleon.utils.system.LogUtils; 6 | import com.proxgrind.chameleon.utils.tools.ArrayUtils; 7 | import com.proxgrind.chameleon.utils.tools.HexUtil; 8 | 9 | import java.util.ArrayList; 10 | 11 | public class BLERawUtils { 12 | // 解析! 13 | public static Details[] parse(byte[] raw) { 14 | ArrayList
details = new ArrayList<>(3); 15 | // 02 01 02 16 | // 02 0A 04 17 | // 03 02 F0 FF 18 | // 0C FF 5A 69 63 6F 78 DC 0D 30 02 74 CC 19 | // 06 09 58 54 34 32 33 20 | // 0000000000000000000000000000000000000000000000000000000000000000 21 | for (int i = 0; i < raw.length; ) { 22 | // 分三段取长度字节! 23 | int len = raw[i]; 24 | // 必定超过一个字节! 25 | if (len > 1) { 26 | // 足够一帧数据! 27 | if (len < raw.length + i) { 28 | // 建立存储对象! 29 | Details tmp = new Details(); 30 | tmp.setLength(len); 31 | tmp.setType(raw[i + 1]); 32 | // 建立一个存放值字节的数组,长度减去类型可以得到有效的值长度! 33 | byte[] bytes = new byte[len - 1]; 34 | // 进行值拷贝! 35 | try { 36 | System.arraycopy(raw, i + 2, bytes, 0, bytes.length); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | // 存放进对象中! 41 | tmp.setValue(bytes); 42 | // 添加到结果集! 43 | details.add(tmp); 44 | i += (len + 1); 45 | } else { 46 | break; 47 | } 48 | } else { 49 | break; 50 | } 51 | } 52 | return ArrayUtils.list2Arr(details); 53 | } 54 | 55 | // 按照某个类型搜索值 56 | public static Details find(int typeByte, Details[] details) { 57 | if (details != null) { 58 | for (Details tmp : details) { 59 | /*LogUtils.d("len: " 60 | + HexUtil.toHexString(tmp.getLength()) + ", " 61 | + "type: " + HexUtil.toHexString(tmp.getType()) + ", " 62 | + "value: " + HexUtil.toHexString(tmp.getValue()) + ", " 63 | + "str: " + new String(tmp.getValue()) 64 | );*/ 65 | if (tmp.getType() == typeByte) { 66 | return tmp; 67 | } 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | // 直接获得某个类型的值! 74 | public static Details find(int typeByte, byte[] raw) { 75 | // 进行raw分包查询! 76 | BLERawUtils.Details[] details = BLERawUtils.parse(raw); 77 | return BLERawUtils.find(typeByte, details); 78 | } 79 | 80 | // 存放详细信息的类! 81 | public static class Details { 82 | public int getLength() { 83 | return length; 84 | } 85 | 86 | private void setLength(int length) { 87 | this.length = length; 88 | } 89 | 90 | public int getType() { 91 | return type; 92 | } 93 | 94 | private void setType(int type) { 95 | this.type = type; 96 | } 97 | 98 | public byte[] getValue() { 99 | return value; 100 | } 101 | 102 | private void setValue(byte[] value) { 103 | this.value = value; 104 | } 105 | 106 | int length; 107 | int type; 108 | byte[] value; 109 | 110 | @NonNull 111 | @Override 112 | public String toString() { 113 | return "[Type=" + type + "]" + "[Value=]" + HexUtil.toHexString(value) + "]" + "[Length=" + length + "]"; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /appmain/utils/device/ble/BluetoothUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.device.ble; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.bluetooth.BluetoothAdapter; 5 | import android.bluetooth.BluetoothManager; 6 | import android.content.BroadcastReceiver; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.IntentFilter; 10 | 11 | import com.proxgrind.devices.BleSerialControl; 12 | 13 | import java.lang.reflect.Field; 14 | import java.lang.reflect.InvocationTargetException; 15 | import java.lang.reflect.Method; 16 | 17 | import static android.bluetooth.BluetoothDevice.ACTION_BOND_STATE_CHANGED; 18 | 19 | /** 20 | * 蓝牙状态监听! 21 | */ 22 | public class BluetoothUtils { 23 | public static BroadcastReceiver startStatusReceicer(Context context, OnStatusChange callback) { 24 | if (callback != null) { 25 | if (!check(context, callback)) return null; 26 | // 创建广播! 27 | BroadcastReceiver blueToothValueReceiver = new BroadcastReceiver() { 28 | public int DEFAULT_VALUE_BULUETOOTH = 1000; 29 | 30 | @Override 31 | public void onReceive(Context context, Intent intent) { 32 | String action = intent.getAction(); 33 | if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { 34 | int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, DEFAULT_VALUE_BULUETOOTH); 35 | switch (state) { 36 | case BluetoothAdapter.STATE_OFF: 37 | callback.onStateOff(context); 38 | break; 39 | case BluetoothAdapter.STATE_ON: 40 | callback.onStateOn(context); 41 | break; 42 | case BluetoothAdapter.STATE_TURNING_ON: 43 | callback.onStateTurningOn(context); 44 | break; 45 | case BluetoothAdapter.STATE_TURNING_OFF: 46 | callback.onStateTurningOff(context); 47 | break; 48 | case BluetoothAdapter.STATE_CONNECTING: 49 | callback.onConnecting(context); 50 | break; 51 | case BluetoothAdapter.STATE_CONNECTED: 52 | callback.onConnected(context); 53 | break; 54 | case BluetoothAdapter.STATE_DISCONNECTING: 55 | callback.onDisconnecting(context); 56 | break; 57 | case BluetoothAdapter.STATE_DISCONNECTED: 58 | callback.onDisconnected(context); 59 | break; 60 | default: 61 | break; 62 | } 63 | } 64 | } 65 | }; 66 | //注册广播,蓝牙状态监听 67 | IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 68 | context.registerReceiver(blueToothValueReceiver, filter); 69 | return blueToothValueReceiver; 70 | } 71 | return null; 72 | } 73 | 74 | public static BroadcastReceiver startActionReceiver(Context context, OnActionChange callback) { 75 | if (callback != null) { 76 | if (!check(context, callback)) return null; 77 | // 创建广播! 78 | BroadcastReceiver blueToothValueReceiver = new BroadcastReceiver() { 79 | @Override 80 | public void onReceive(Context context, Intent intent) { 81 | if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) { 82 | callback.onScanStarted(context); 83 | } 84 | if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) { 85 | callback.onScanFinished(context); 86 | } 87 | } 88 | }; 89 | //注册广播,蓝牙状态监听 90 | IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 91 | filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 92 | filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 93 | context.registerReceiver(blueToothValueReceiver, filter); 94 | return blueToothValueReceiver; 95 | } 96 | return null; 97 | } 98 | 99 | private static boolean check(Context context, OnBlueNoSupport callback) { 100 | BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); 101 | if (manager == null || manager.getAdapter() == null) { 102 | callback.onBlueNoSupported(context); 103 | return false; 104 | } 105 | return true; 106 | } 107 | 108 | public static void stop(BroadcastReceiver receiver, Context context) { 109 | try { 110 | context.unregisterReceiver(receiver); 111 | } catch (Exception ignored) { 112 | } 113 | } 114 | 115 | private static class OnBlueNoSupport { 116 | public void onBlueNoSupported(Context context) { 117 | } 118 | } 119 | 120 | public static class OnStatusChange extends OnBlueNoSupport { 121 | public void onStateOff(Context context) { 122 | } 123 | 124 | public void onStateOn(Context context) { 125 | } 126 | 127 | public void onStateTurningOn(Context context) { 128 | } 129 | 130 | public void onStateTurningOff(Context context) { 131 | } 132 | 133 | public void onConnecting(Context context) { 134 | } 135 | 136 | public void onConnected(Context context) { 137 | } 138 | 139 | public void onDisconnecting(Context context) { 140 | } 141 | 142 | public void onDisconnected(Context context) { 143 | } 144 | } 145 | 146 | public static class OnActionChange extends OnBlueNoSupport { 147 | public void onScanStarted(Context context) { 148 | } 149 | 150 | public void onScanFinished(Context context) { 151 | } 152 | } 153 | 154 | public static boolean isBlueOpen(Context context) { 155 | return BleSerialControl.get().getAdapter().isEnabled(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /appmain/utils/device/ble/ClsUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.device.ble; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.bluetooth.BluetoothDevice; 6 | import android.bluetooth.BluetoothGatt; 7 | import android.os.Build; 8 | import android.util.Log; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | 13 | public class ClsUtils { 14 | /** 15 | * 与设备配对 参考源码:platform/packages/apps/Settings.git 16 | * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java 17 | */ 18 | @SuppressLint("ObsoleteSdkInt") 19 | static public boolean createBond(Class btClass, BluetoothDevice btDevice) { 20 | if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) return false; 21 | try { 22 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 23 | Method createBondMethod = btClass.getMethod("createBond"); 24 | Object obj = createBondMethod.invoke(btDevice); 25 | return obj instanceof Boolean ? (Boolean) obj : false; 26 | } else { 27 | return btDevice.createBond(); 28 | } 29 | } catch (Exception e) { 30 | return false; 31 | } 32 | } 33 | 34 | /** 35 | * 与设备解除配对 参考源码:platform/packages/apps/Settings.git 36 | * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java 37 | */ 38 | static public boolean removeBond(Class btClass, BluetoothDevice btDevice) { 39 | try { 40 | Method removeBondMethod = btClass.getMethod("removeBond"); 41 | Object obj = removeBondMethod.invoke(btDevice); 42 | return obj instanceof Boolean ? (Boolean) obj : false; 43 | } catch (Exception e) { 44 | return false; 45 | } 46 | } 47 | 48 | static public boolean setPin(Class btClass, BluetoothDevice btDevice, String str) throws Exception { 49 | byte[] key = str != null ? str.getBytes() : null; 50 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 51 | try { 52 | Method removeBondMethod = btClass.getDeclaredMethod("setPin", byte[].class); 53 | Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[]{key}); 54 | Log.d("returnValue", "" + returnValue); 55 | } catch (SecurityException e) { 56 | // throw new RuntimeException(e.getMessage()); 57 | e.printStackTrace(); 58 | } catch (IllegalArgumentException e) { 59 | // throw new RuntimeException(e.getMessage()); 60 | e.printStackTrace(); 61 | } catch (Exception e) { 62 | // TODO Auto-generated catch block 63 | e.printStackTrace(); 64 | } 65 | return true; 66 | } else { 67 | return btDevice.setPin(key); 68 | } 69 | } 70 | 71 | // 取消用户输入 72 | static public boolean cancelPairingUserInput(Class btClass, BluetoothDevice device) throws Exception { 73 | Method createBondMethod = btClass.getMethod("cancelPairingUserInput"); 74 | // cancelBondProcess(btClass, device); 75 | Boolean returnValue = (Boolean) createBondMethod.invoke(device); 76 | return returnValue.booleanValue(); 77 | } 78 | 79 | // 取消配对 80 | static public boolean cancelBondProcess(Class btClass, BluetoothDevice device) throws Exception { 81 | Method createBondMethod = btClass.getMethod("cancelBondProcess"); 82 | Boolean returnValue = (Boolean) createBondMethod.invoke(device); 83 | return returnValue.booleanValue(); 84 | } 85 | 86 | //确认配对 87 | static public void setPairingConfirmation(Class btClass, BluetoothDevice device, boolean isConfirm) throws Exception { 88 | Method setPairingConfirmation = btClass.getDeclaredMethod("setPairingConfirmation", boolean.class); 89 | setPairingConfirmation.invoke(device, isConfirm); 90 | } 91 | 92 | /** 93 | * @param clsShow 94 | */ 95 | static public void printAllInform(Class clsShow) { 96 | try { 97 | // 取得所有方法 98 | Method[] hideMethod = clsShow.getMethods(); 99 | int i = 0; 100 | for (; i < hideMethod.length; i++) { 101 | Log.e("method name", hideMethod[i].getName() + ";and the i is:" 102 | + i); 103 | } 104 | // 取得所有常量 105 | Field[] allFields = clsShow.getFields(); 106 | for (i = 0; i < allFields.length; i++) { 107 | Log.e("Field name", allFields[i].getName()); 108 | } 109 | } catch (SecurityException e) { 110 | // throw new RuntimeException(e.getMessage()); 111 | e.printStackTrace(); 112 | } catch (IllegalArgumentException e) { 113 | // throw new RuntimeException(e.getMessage()); 114 | e.printStackTrace(); 115 | } catch (Exception e) { 116 | // TODO Auto-generated catch block 117 | e.printStackTrace(); 118 | } 119 | } 120 | 121 | /** 122 | * 刷新设备的缓存! 123 | */ 124 | static public void refreshDeviceCache(BluetoothGatt gatt) { 125 | if (gatt == null) return; 126 | /* 127 | * If the device is bonded this is up to the Service Changed characteristic to notify Android that the services has changed. 128 | * There is no need for this trick in that case. 129 | * If not bonded, the Android should not keep the services cached when the Service Changed characteristic is present in the target device database. 130 | * However, due to the Android bug (still exists in Android 5.0.1), it is keeping them anyway and the only way to clear services is by using this hidden refresh method. 131 | */ 132 | if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) { 133 | /* 134 | * There is a refresh() method in BluetoothGatt class but for now it's hidden. We will call it using reflections. 135 | */ 136 | try { 137 | //noinspection JavaReflectionMemberAccess 138 | final Method refresh = gatt.getClass().getMethod("refresh"); 139 | refresh.invoke(gatt); 140 | } catch (Exception ignored) { 141 | } 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /appmain/utils/device/screen/DisplayUtil.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.device.screen; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.content.res.Configuration; 7 | import android.content.res.Resources; 8 | import android.graphics.RectF; 9 | import android.os.Build; 10 | import android.view.View; 11 | import android.view.animation.Animation; 12 | import android.view.animation.CycleInterpolator; 13 | import android.view.animation.TranslateAnimation; 14 | 15 | import com.proxgrind.chameleon.utils.system.LogUtils; 16 | 17 | import java.lang.reflect.Method; 18 | 19 | /** 20 | * 屏幕显示工具类 21 | * 22 | * @author DXL 23 | */ 24 | public class DisplayUtil { 25 | /** 26 | * 获取屏幕高度! 27 | */ 28 | public static int getWindowHeight(Context context) { 29 | return context.getResources().getDisplayMetrics().heightPixels; 30 | } 31 | 32 | /** 33 | * 获取屏幕宽度! 34 | */ 35 | public static int getWindowWidth(Context context) { 36 | return context.getResources().getDisplayMetrics().widthPixels; 37 | } 38 | 39 | /** 40 | * 测量底部导航栏的高度 41 | * 42 | * @param mActivity:上下文环境 43 | * @return:返回测量出的底部导航栏高度 44 | */ 45 | public static int getNavigationBarHeight(Activity mActivity) { 46 | Resources resources = mActivity.getResources(); 47 | int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); 48 | int height = resources.getDimensionPixelSize(resourceId); 49 | return height; 50 | } 51 | 52 | /* 53 | * navigation 是否存在! 54 | * */ 55 | private boolean checkDeviceHasNavigationBar(Context context) { 56 | 57 | boolean hasNavigationBar = false; 58 | Resources rs = context.getResources(); 59 | int id = rs.getIdentifier("config_showNavigationBar", "bool", "android"); 60 | if (id > 0) { 61 | hasNavigationBar = rs.getBoolean(id); 62 | } 63 | try { 64 | Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); 65 | Method m = systemPropertiesClass.getMethod("get", String.class); 66 | String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys"); 67 | if ("1".equals(navBarOverride)) { 68 | hasNavigationBar = false; 69 | } else if ("0".equals(navBarOverride)) { 70 | hasNavigationBar = true; 71 | } 72 | } catch (Exception e) { 73 | LogUtils.e(e.toString()); 74 | } 75 | return hasNavigationBar; 76 | } 77 | 78 | /** 79 | * 将px值转换为dip或dp值,保证尺寸大小不变 80 | * 81 | * @param pxValue 像素值 82 | * @return dip值 83 | */ 84 | public static int px2dip(Context context, float pxValue) { 85 | final float scale = context.getResources().getDisplayMetrics().density; 86 | return (int) (pxValue / scale + 0.5f); 87 | } 88 | 89 | /** 90 | * 将dip或dp值转换为px值,保证尺寸大小不变 91 | * 92 | * @param dipValue 93 | * @return 94 | */ 95 | public static int dip2px(Context context, float dipValue) { 96 | final float scale = context.getResources().getDisplayMetrics().density; 97 | return (int) (dipValue * scale + 0.5f); 98 | } 99 | 100 | /** 101 | * 将px值转换为sp值,保证文字大小不变 102 | * 103 | * @param pxValue 104 | * @return 105 | */ 106 | public static int px2sp(Context context, float pxValue) { 107 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 108 | return (int) (pxValue / fontScale + 0.5f); 109 | } 110 | 111 | /** 112 | * 将sp值转换为px值,保证文字大小不变 113 | * 114 | * @param spValue 115 | * @return 116 | */ 117 | public static int sp2px(Context context, float spValue) { 118 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 119 | return (int) (spValue * fontScale + 0.5f); 120 | } 121 | 122 | /** 123 | * 显示状态栏和导航栏! 124 | */ 125 | public static void showStatusAndNavigationBar(Activity activity) { 126 | View decorView = activity.getWindow().getDecorView(); 127 | decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); 128 | } 129 | 130 | /** 131 | * 隐藏状态栏和导航栏! 132 | */ 133 | @SuppressLint("ObsoleteSdkInt") 134 | public static void dismissStatusAndNavigationBar(Activity activity) { 135 | //隐藏虚拟按键,并且全屏 136 | if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api 137 | View v = activity.getWindow().getDecorView(); 138 | v.setSystemUiVisibility(View.GONE); 139 | } else if (Build.VERSION.SDK_INT >= 19) { 140 | //for new api versions. 141 | View decorView = activity.getWindow().getDecorView(); 142 | int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 143 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN; 144 | decorView.setSystemUiVisibility(uiOptions); 145 | } 146 | } 147 | 148 | /** 149 | * 判断某个xy坐标是否在某个view内 150 | * 151 | * @return 判断结果! 152 | */ 153 | public static boolean isXyInView(float x, float y, View v) { 154 | if (v == null) return false; 155 | int[] location = new int[2]; 156 | // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值 157 | v.getLocationOnScreen(location); 158 | RectF rect = new RectF(location[0], location[1], 159 | location[0] + v.getWidth(), location[1] + v.getHeight()); 160 | return rect.contains(x, y); 161 | } 162 | 163 | /** 164 | * 设置晃动动画 165 | */ 166 | public static void setShakeAnimation(View v) { 167 | v.startAnimation(shakeAnimation(5)); 168 | } 169 | 170 | /** 171 | * 晃动动画 172 | * 173 | * @param counts 1秒钟晃动多少下 174 | * @return 175 | */ 176 | public static Animation shakeAnimation(int counts) { 177 | Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0); 178 | translateAnimation.setInterpolator(new CycleInterpolator(counts)); 179 | translateAnimation.setDuration(1000); 180 | return translateAnimation; 181 | } 182 | 183 | //检查当前系统是否已开启暗黑模式 184 | public static boolean isDarkModeStatus(Context context) { 185 | int mode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; 186 | return mode == Configuration.UI_MODE_NIGHT_YES; 187 | } 188 | } -------------------------------------------------------------------------------- /appmain/utils/mifare/BatchAdapter.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.mifare; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * MifareClassic S50 & S70 batch verity and RW! 7 | * 8 | * @author DXL 9 | * @version 1.0 10 | */ 11 | public interface BatchAdapter { 12 | /** 13 | * 读取标签 14 | * 15 | * @param block 读取的起始块 16 | * 如果all为true,则将会读取该扇区所有块,此时参数一就是扇区的起始块, 17 | * 如果all为false,则将会只读单个块,此时参数一就是块! 18 | * @return 读取结果, 可能为null 19 | */ 20 | byte[][] read(int block, boolean isKeyA, byte[] key, boolean isReadSector) throws IOException; 21 | 22 | /** 23 | * 写入标签 24 | * 25 | * @param sector 写入的扇区, 26 | * @param data 将被写入的数据,单项必须是16字节长度的Hex字符串 27 | * @return 写入结果! 28 | */ 29 | boolean write(int sector, boolean isKeyA, byte[] key, byte[] data) throws IOException; 30 | 31 | /** 32 | * 验证标签,使用一定长度的秘钥组 33 | * 34 | * @param sector 需要验证的扇区号! 35 | * @param keysGroup 被用来验证的秘钥组! 36 | * @param isKeyA 是否是验证秘钥A的 37 | * @return 验证成功的秘钥! 38 | */ 39 | byte[] verity(int sector, byte[][] keysGroup, boolean isKeyA) throws IOException; 40 | 41 | /** 42 | * 获取批量操作的超时! 43 | */ 44 | int getTimeout(); 45 | 46 | /** 47 | * 设置批量操作的超时! 48 | */ 49 | void setTimeout(int timeout); 50 | } 51 | -------------------------------------------------------------------------------- /appmain/utils/mifare/ChameleonBatchAdapterImpl.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.mifare; 2 | 3 | import com.proxgrind.chameleon.packets.DataPackets; 4 | import com.proxgrind.chameleon.utils.system.LogUtils; 5 | import com.proxgrind.chameleon.utils.tools.HexUtil; 6 | import com.proxgrind.devices.BleSerialControl; 7 | 8 | import java.io.IOException; 9 | import java.util.Arrays; 10 | 11 | public class ChameleonBatchAdapterImpl implements BatchAdapter { 12 | // 持有一个原生通讯的句柄! 13 | private BleSerialControl control = BleSerialControl.get(); 14 | // 一个空的数组! 15 | public static final byte[] EMPTY_DATA_ONE = new byte[]{0x00}; 16 | 17 | /** 18 | * 读取函数,变色龙的读取实现,依赖起始块 19 | * 20 | * @param startBlock 起始块,如果当前的模式是读取单块模式,则此参数是需要读取的块 21 | * @param isKeyA 当前是否是用keyA来验证并且读取的 22 | * @param key 当前被用来读取的秘钥 23 | * @param isReadSector 当前是否是读取全部扇区模式,注意,如果是读取扇区模式, 24 | * 遇到4K的大扇区的情况下,需要进行每次4个块的读取,也就是 25 | * 从startBlock开始表示读取第一个大块 26 | * 从startBlock + 4 开始表示读取第二个大块 27 | * 从startBlock + 8 开始表示读取第三个大块 28 | * 从startBlock + 12 开始表示读取第四个大块 29 | */ 30 | @Override 31 | public byte[][] read(int startBlock, boolean isKeyA, byte[] key, boolean isReadSector) throws IOException { 32 | // 组包! 33 | byte[] dataOfParam = HexUtil.bytesMerge( 34 | getType(isReadSector ? 2 : 1), // 置入类型,如果当前是读取扇区,则设置操作标志为2,否则设置为1 35 | EMPTY_DATA_ONE, // 置入状态码! 36 | new byte[]{(byte) startBlock}, // 置入起始块! 37 | isKeyA(isKeyA), // 置入当前验证的秘钥类型! 38 | key, // 置入秘钥! 39 | isReadSector ? new byte[16 * 4] : new byte[16] // 置入空字节 40 | ); 41 | byte[] dataOfFinal = new DataPackets(0x72, dataOfParam).getData(); 42 | LogUtils.d("发送的数据长度: " + dataOfParam.length); 43 | // 发送数据! 44 | byte[] respDatas = sendAndReadResponse(dataOfFinal, dataOfFinal.length, dataOfParam.length); 45 | if (respDatas != null && respDatas.length == dataOfParam.length) { 46 | // 得到最终的秘钥索引,并且进行下标 -1 的内容返回! 47 | byte status = respDatas[1]; 48 | checkTagStatus(status); 49 | if (status == 0) { 50 | LogUtils.d("读取失败"); 51 | return null; 52 | } 53 | if (status == 1) { 54 | return HexUtil.splitBytes( 55 | Arrays.copyOfRange(respDatas, 10, respDatas.length), 56 | 16 57 | ); 58 | } 59 | } 60 | return null; 61 | } 62 | 63 | @Override 64 | public boolean write(int sector, boolean isKeyA, byte[] key, byte[] dataGroup) throws IOException { 65 | // 组包! 66 | byte[] dataOfParam = HexUtil.bytesMerge( 67 | getType(3), // 置入类型! 68 | EMPTY_DATA_ONE, // 置入状态码! 69 | new byte[]{(byte) sector}, // 置入扇区! 70 | isKeyA(isKeyA), // 置入当前验证的秘钥类型! 71 | key, // 置入秘钥! 72 | dataGroup // 置入数据! 73 | ); 74 | byte[] dataOfFinal = new DataPackets(0x72, dataOfParam).getData(); 75 | // 发送数据! 76 | byte[] respDatas = sendAndReadResponse(dataOfFinal, dataOfFinal.length, dataOfParam.length); 77 | if (respDatas != null && respDatas.length == dataOfParam.length) { 78 | // 得到最终的秘钥索引,并且进行下标 -1 的内容返回! 79 | byte status = respDatas[1]; 80 | checkTagStatus(status); 81 | if (status == 0) { 82 | LogUtils.d("写入失败"); 83 | return false; 84 | } 85 | return status == 1; 86 | } 87 | return false; 88 | } 89 | 90 | /** 91 | * 经过测试,以35个秘钥为一组进行验证比较好! 92 | */ 93 | @Override 94 | public byte[] verity(int sector, byte[][] keysGroup, boolean isKeyA) throws IOException { 95 | // 组包! 96 | byte[] dataOfParam = HexUtil.bytesMerge( 97 | getType(0x04), // 置入类型! 04 98 | EMPTY_DATA_ONE, // 置入状态码! 00 99 | getBlock(sector), // 置入扇区! ~3F 100 | isKeyA(isKeyA), // 置入当前验证的秘钥类型! 00 101 | getKeyCount(keysGroup), // 获得当前的秘钥总数! 102 | HexUtil.bytesMerge(keysGroup) // 合并秘钥! 103 | ); 104 | byte[] dataOfFinal = new DataPackets(0x72, dataOfParam).getData(); 105 | byte[] respDatas = sendAndReadResponse(dataOfFinal, dataOfFinal.length, 11); 106 | if (respDatas != null && respDatas.length == 11) { 107 | // 得到最终的秘钥索引,并且进行下标 -1 的内容返回! 108 | byte index = respDatas[1]; 109 | checkTagStatus(index); 110 | // 只有当索引大于1的时候,才是真正的有应答,当应答FF的时候,则是卡片失联了 111 | if (index > 0 && index <= keysGroup.length) { 112 | return keysGroup[index - 1]; 113 | } 114 | } 115 | return null; 116 | } 117 | 118 | public void checkTagStatus(int statusCode) throws IOException { 119 | if (statusCode == 0xFF || statusCode == -1) { 120 | throw new IOException("Tag lost."); 121 | } 122 | } 123 | 124 | public byte[] sendAndReadResponse(byte[] data, int dataLength, int acceptRespLength) throws IOException { 125 | // 发送数据! 126 | int timeout = getTimeout(); 127 | // 刷新缓冲区且发送 128 | control.flush(); 129 | int maxLen = BleSerialControl.MTU; 130 | if (control.write(data, 0, dataLength, timeout) == dataLength) { 131 | // 读取应答数据 132 | byte[] responseBuffer = new byte[acceptRespLength <= 0 ? maxLen : acceptRespLength]; 133 | // 直接读取 134 | control.read( 135 | responseBuffer, 136 | 0, 137 | Math.max(acceptRespLength, 0), 138 | timeout 139 | ); 140 | return responseBuffer; 141 | } 142 | return null; 143 | } 144 | 145 | /** 146 | * 获取byte数组型的类型,分别可能是 147 | * 0 读取 148 | * 1 写入 149 | * 2 验证 150 | */ 151 | public byte[] getType(int type) { 152 | return new byte[]{(byte) type}; 153 | } 154 | 155 | /** 156 | * 将单个字节的sector转为数组! 157 | */ 158 | public byte[] getBlock(int sector) { 159 | return new byte[]{(byte) MfDataUtils.get_trailer_block(MfDataUtils.sectorToBlock(sector))}; 160 | } 161 | 162 | public byte[] isKeyA(boolean isKeyA) { 163 | return new byte[]{(byte) (isKeyA ? 0 : 1)}; 164 | } 165 | 166 | public byte[] getKeyCount(byte[][] keys) { 167 | return new byte[]{(byte) keys.length}; 168 | } 169 | 170 | @Override 171 | public int getTimeout() { 172 | return 2333; 173 | } 174 | 175 | @Override 176 | public void setTimeout(int timeout) { 177 | 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /appmain/utils/mifare/MfDataUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.mifare; 2 | 3 | /* 4 | * MifareClassic标签用得到的工具! 5 | * */ 6 | public class MfDataUtils { 7 | 8 | public static boolean validateSector(int sector) { 9 | // Do not be too strict on upper bounds checking, since some cards 10 | // have more addressable memory than they report. For example, 11 | // MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in 12 | // MIFARE Classic compatibility mode. 13 | // Note that issuing a command to an out-of-bounds block is safe - the 14 | // tag should report error causing IOException. This validation is a 15 | // helper to guard against obvious programming mistakes. 16 | 17 | int NR_TRAILERS_4k = 40; 18 | if (sector < 0 || sector >= NR_TRAILERS_4k) { 19 | return false; 20 | } 21 | return true; 22 | } 23 | 24 | public static boolean validateBlock(int block) { 25 | // Just looking for obvious out of bounds... 26 | int NR_BLOCKS_4k = 0xFF; 27 | if (block < 0 || block >= NR_BLOCKS_4k) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | public static boolean validateValueOperand(int value) { 34 | if (value < 0) { 35 | return false; 36 | } 37 | return true; 38 | } 39 | 40 | public static int blockToSector(int blockIndex) { 41 | if (!validateBlock(blockIndex)) return 0; 42 | if (blockIndex < 32 * 4) { 43 | return (blockIndex / 4); 44 | } else { 45 | return (32 + (blockIndex - 32 * 4) / 16); 46 | } 47 | } 48 | 49 | public static int sectorToBlock(int sectorIndex) { 50 | if (!validateSector(sectorIndex)) { 51 | return -1; 52 | } 53 | if (sectorIndex < 32) { 54 | return (sectorIndex * 4); 55 | } else { 56 | return (32 * 4 + (sectorIndex - 32) * 16); 57 | } 58 | } 59 | 60 | public static boolean isFirstBlock(int uiBlock) { 61 | // 测试我们是否处于小扇区或者大扇区? 62 | if (uiBlock < 128) 63 | return ((uiBlock) % 4 == 0); 64 | else 65 | return ((uiBlock) % 16 == 0); 66 | } 67 | 68 | public static boolean isTrailerBlock(int uiBlock) { 69 | // 测试我们处于小区块还是大扇区 70 | if (uiBlock < 128) 71 | return ((uiBlock + 1) % 4 == 0); 72 | else 73 | return ((uiBlock + 1) % 16 == 0); 74 | } 75 | 76 | public static int getBlockCountInSector(int sectorIndex) { 77 | if (!validateSector(sectorIndex)) return -1; 78 | if (sectorIndex < 32) { 79 | return 4; 80 | } else { 81 | return 16; 82 | } 83 | } 84 | 85 | public static int get_trailer_block(int uiFirstBlock) { 86 | // Test if we are in the small or big sectors 87 | int trailer_block; 88 | if (uiFirstBlock < 128) { 89 | trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4)); 90 | } else { 91 | trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16)); 92 | } 93 | return trailer_block; 94 | } 95 | 96 | public static int getIndexOnSector(int block, int sector) { 97 | int index = 0; 98 | //得到当前的块在扇区中的具体索引! 99 | for (int i = 0; i < getBlockCountInSector(sector); i++) { //得到当前扇区的块总数! 100 | if (block == (sectorToBlock(block) + i)) break; 101 | ++index; 102 | } 103 | return index; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /appmain/utils/mifare/MifareAdapter.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.mifare; 2 | 3 | import java.io.IOException; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * MifareClassic定义 8 | */ 9 | public interface MifareAdapter extends Serializable { 10 | 11 | /* 12 | * 一个标准的MifareClassic 13 | * 是可以被链接,被验证,被读取,被写入,被增值,被减值,被重置的! 14 | * */ 15 | 16 | /** 17 | * 重新查找获取标签! 18 | * 19 | * @return 查找结果! 20 | */ 21 | boolean rescantag() throws IOException; 22 | 23 | /** 24 | * 链接标签 25 | * 26 | * @return 链接结果! 27 | */ 28 | boolean connect() throws IOException; 29 | 30 | /** 31 | * 断开标签 32 | */ 33 | void close() throws IOException; 34 | 35 | /** 36 | * 读取标签 37 | * 38 | * @param block 读取的块 39 | * @return 读取结果, 可能为null 40 | */ 41 | byte[] read(int block) throws IOException; 42 | 43 | /** 44 | * 写入标签 45 | * 46 | * @param blockIndex 写入的块, 47 | * @param data 将被写入的数据,必须是16字节长度的Hex字符串! 48 | * @return 写入结果! 49 | */ 50 | boolean write(int blockIndex, byte[] data) throws IOException; 51 | 52 | /** 53 | * 验证密钥A 54 | * 55 | * @param sectorIndex 被验证的块 56 | * @param key 用来验证的密钥 57 | * @return 验证结果! 58 | */ 59 | boolean authA(int sectorIndex, byte[] key) throws IOException; 60 | 61 | /** 62 | * 验证密钥B 63 | * 64 | * @param sectorIndex 被验证的块 65 | * @param key 用来验证的密钥 66 | * @return 验证结果! 67 | */ 68 | boolean authB(int sectorIndex, byte[] key) throws IOException; 69 | 70 | /** 71 | * 增值 72 | * 73 | * @param blockIndex 被增值的块 74 | * @param value 非负递增的值 75 | */ 76 | void increment(int blockIndex, int value) throws IOException; 77 | 78 | /** 79 | * 增值 80 | * 81 | * @param blockIndex 被增值的块 82 | * @param value 非负递减的值 83 | */ 84 | void decrement(int blockIndex, int value) throws IOException; 85 | 86 | /** 87 | * 恢复增值减值操作 88 | * 89 | * @param blockIndex 被恢复的块 90 | */ 91 | void restore(int blockIndex) throws IOException; 92 | 93 | /** 94 | * 转移值数据到块 95 | * 96 | * @param blockIndex 被转移的块 97 | */ 98 | void transfer(int blockIndex) throws IOException; 99 | 100 | /** 101 | * 获得UID 102 | * 103 | * @return UID字节数组 104 | */ 105 | byte[] getUid(); 106 | 107 | byte[] getAts(); 108 | 109 | byte[] getAtqa(); 110 | 111 | byte[] getSak(); 112 | 113 | /** 114 | * 获得类型 115 | * 116 | * @return 1024 or 2048 or 4096 117 | */ 118 | int getType(); 119 | 120 | /** 121 | * 获得扇区数量 122 | * 123 | * @return 卡片支持的扇区容量 124 | */ 125 | int getSectorCount(); 126 | 127 | /** 128 | * 获得块数量 129 | * 130 | * @return 卡片支持的块容量 131 | */ 132 | int getBlockCount(); 133 | 134 | /** 135 | * 设置操作超时 136 | * 137 | * @param ms 被设置的超时 138 | */ 139 | void setTimeout(int ms); 140 | 141 | /** 142 | * 获取操作超时 143 | * 144 | * @return 超时参数 145 | */ 146 | int getTimeout(); 147 | 148 | /** 149 | * 获取批量操作的实现! 150 | * 如果返回null,则不支持批量! 151 | */ 152 | BatchAdapter getBatchImpl(); 153 | 154 | /** 155 | * 是否是链接状态! 156 | * 157 | * @return 如果卡片已经链接(在部分实现机制上) 158 | * 否则你可以获取结果为true的返回值,否则为false 159 | */ 160 | boolean isConnected(); 161 | 162 | /** 163 | * 是否是仿真卡 164 | * 165 | * @return true为仿真 166 | */ 167 | boolean isEmulated(); 168 | 169 | /** 170 | * 是否是后门卡! 171 | * 172 | * @return 是否是后门卡 173 | */ 174 | boolean isSpecialTag(); 175 | 176 | /** 177 | * 是否是支持测试! 178 | */ 179 | boolean isTestSupported(); 180 | } 181 | -------------------------------------------------------------------------------- /appmain/utils/mifare/StdMifareIntent.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.mifare; 2 | 3 | import android.app.Activity; 4 | import android.app.PendingIntent; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.nfc.NfcAdapter; 8 | import android.nfc.NfcManager; 9 | import android.nfc.tech.MifareClassic; 10 | 11 | public class StdMifareIntent { 12 | 13 | private NfcAdapter mAdapter = null; 14 | 15 | public StdMifareIntent(Context context) { 16 | NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 17 | //判断设备是否支持NFC! 18 | if (manager == null) return; 19 | mAdapter = manager.getDefaultAdapter(); 20 | } 21 | 22 | /* 23 | * 获取当前操作的适配器! 24 | * */ 25 | public NfcAdapter getAdapter() { 26 | return mAdapter; 27 | } 28 | 29 | /* 30 | * 注册前台 31 | * */ 32 | public void enableForegroundDispatch(Activity targetAct) { 33 | if (mAdapter == null) return; 34 | try { 35 | //进行前台广播拦截! 36 | Intent intent = new Intent(targetAct, 37 | targetAct.getClass()).addFlags( 38 | Intent.FLAG_ACTIVITY_SINGLE_TOP); 39 | PendingIntent pendingIntent = PendingIntent.getActivity( 40 | targetAct, 0, intent, 0); 41 | mAdapter.enableForegroundDispatch(targetAct, pendingIntent, null, new String[][]{ 42 | new String[]{MifareClassic.class.getName()}}); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | /* 49 | * 解注册前台 50 | * */ 51 | public void disableForegroundDispatch(Activity activity) { 52 | if (mAdapter == null) return; 53 | try { 54 | //解注册前台拦截 55 | mAdapter.disableForegroundDispatch(activity); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /appmain/utils/security/AesUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.security; 2 | 3 | import javax.crypto.*; 4 | import javax.crypto.spec.SecretKeySpec; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | import java.nio.charset.Charset; 8 | import java.security.InvalidAlgorithmParameterException; 9 | import java.security.InvalidKeyException; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.security.SecureRandom; 12 | 13 | /** 14 | * AES 加密方法,是对称的密码算法(加密与解密的密钥一致),这里使用最大的 256 位的密钥 15 | */ 16 | public class AesUtils { 17 | 18 | private static final int size = 128; 19 | 20 | /** 21 | * 获得一个 密钥长度为 256 位的 AES 密钥, 22 | * 23 | * @return 返回经 BASE64 处理之后的密钥字符串 24 | */ 25 | public static byte[] getStrKeyAES() throws NoSuchAlgorithmException, UnsupportedEncodingException { 26 | KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 27 | SecureRandom secureRandom = new SecureRandom(String.valueOf(System.currentTimeMillis()).getBytes(Charset.forName("UTF-8"))); 28 | keyGen.init(size, secureRandom); // 这里可以是 128、192、256、越大越安全 29 | SecretKey secretKey = keyGen.generateKey(); 30 | return secretKey.getEncoded(); 31 | } 32 | 33 | /** 34 | * 将使用 原生的类型byte的数组 secretKey 转为 SecretKey 35 | * 36 | * @param keyBytes raw key byte. 37 | * @return SecretKey 38 | */ 39 | public static SecretKey strKey2SecretKey(byte[] keyBytes) { 40 | return new SecretKeySpec(keyBytes, "AES"); 41 | } 42 | 43 | /** 44 | * 将使用 byte 类型的 secretKey 转为 SecretKey 45 | * 46 | * @param bytesKey 47 | * @return SecretKey 48 | */ 49 | public static SecretKey bytesKey2SecretKey(byte[] bytesKey) { 50 | return new SecretKeySpec(bytesKey, "AES"); 51 | } 52 | 53 | /** 54 | * 加密 55 | * 56 | * @param content 待加密内容 57 | * @param secretKey 加密使用的 AES 密钥 58 | * @return 加密后的密文 byte[] 59 | */ 60 | public static byte[] encryptAES(byte[] content, SecretKey secretKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, 61 | BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { 62 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 63 | cipher.init(Cipher.ENCRYPT_MODE, secretKey); 64 | return cipher.doFinal(content); 65 | } 66 | 67 | /** 68 | * 解密 69 | * 70 | * @param content 待解密内容 71 | * @param secretKey 解密使用的 AES 密钥 72 | * @return 解密后的明文 byte[] 73 | */ 74 | public static byte[] decryptAES(byte[] content, SecretKey secretKey) 75 | throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, 76 | BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { 77 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 78 | cipher.init(Cipher.DECRYPT_MODE, secretKey); 79 | return cipher.doFinal(content); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /appmain/utils/security/CRC16Utils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.security; 2 | 3 | /** 4 | * crc16多项式算法 5 | * 6 | * @author eguid 7 | */ 8 | public class CRC16Utils { 9 | 10 | /** 11 | * CRC16Utils-XMODEM算法(四字节) 12 | * 13 | * @param bytes 14 | * @return 15 | */ 16 | public static int crc16_ccitt_xmodem(byte[] bytes) { 17 | return crc16_ccitt_xmodem(bytes, 0, bytes.length); 18 | } 19 | 20 | /** 21 | * CRC16Utils-XMODEM算法(四字节) 22 | * 23 | * @param bytes 24 | * @param offset 25 | * @param count 26 | * @return 27 | */ 28 | public static int crc16_ccitt_xmodem(byte[] bytes, int offset, int count) { 29 | int crc = 0x0000; // initial value 30 | int polynomial = 0x1021; // poly value 31 | for (int index = offset; index < count; index++) { 32 | byte b = bytes[index]; 33 | for (int i = 0; i < 8; i++) { 34 | boolean bit = ((b >> (7 - i) & 1) == 1); 35 | boolean c15 = ((crc >> 15 & 1) == 1); 36 | crc <<= 1; 37 | if (c15 ^ bit) 38 | crc ^= polynomial; 39 | } 40 | } 41 | crc &= 0xffff; 42 | return crc; 43 | } 44 | 45 | /** 46 | * CRC16Utils-XMODEM算法(两字节) 47 | * 48 | * @param bytes 49 | * @param offset 50 | * @param count 51 | * @return 52 | */ 53 | public static short crc16_ccitt_xmodem_short(byte[] bytes, int offset, int count) { 54 | return (short) crc16_ccitt_xmodem(bytes, offset, count); 55 | } 56 | 57 | /** 58 | * CRC16Utils-XMODEM算法(两字节) 59 | * 60 | * @param bytes 61 | */ 62 | public static short crc16_ccitt_xmodem_short(byte[] bytes) { 63 | return crc16_ccitt_xmodem_short(bytes, 0, bytes.length); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /appmain/utils/security/CRC16_14443.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.security; 2 | 3 | public class CRC16_14443 { 4 | 5 | //private static String LOG = CRC16_14443.class.getSimpleName(); 6 | 7 | public static final int CRC16_14443_A = 0x6363; 8 | public static final int CRC16_14443_B = 0xFFFF; 9 | 10 | public static class Out { 11 | byte first; 12 | byte second; 13 | } 14 | 15 | private static int updateCrc14443(byte b, int crc) { 16 | byte ch = (byte) (b ^ (byte) (crc & 0x00ff)); 17 | ch = (byte) (ch ^ (ch << 4)); 18 | return ((crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4)); 19 | } 20 | 21 | public static void computeCrc14443(int crc_type, byte[] bytes, int len, Out out) { 22 | out.first = 0; 23 | out.second = 0; 24 | if (len < 2) return; 25 | byte b; 26 | int res = crc_type; 27 | for (int i = 0; i < len; i++) { 28 | b = bytes[i]; 29 | res = updateCrc14443(b, res); 30 | } 31 | /* ISO/IEC 13239 (formerly ISO/IEC 3309) */ 32 | if (crc_type == CRC16_14443_B) res = ~res; 33 | out.first = (byte) (res & 0xFF); 34 | out.second = (byte) ((res >> 8) & 0xFF); 35 | } 36 | 37 | public static boolean checkCrc14443(int crc_type, byte[] bytes, int len) { 38 | if (len < 3) return false; 39 | Out out = new Out(); 40 | computeCrc14443(crc_type, bytes, len - 2, out); 41 | byte crc1 = bytes[len - 2]; 42 | byte crc2 = bytes[len - 1]; 43 | /*Log.d(LOG, "计算的值1: " + HexUtil.toHexString(out.first)); 44 | Log.d(LOG, "计算的值2: " + HexUtil.toHexString(out.second)); 45 | Log.d(LOG, "传入的值1: " + HexUtil.toHexString(crc1)); 46 | Log.d(LOG, "传入的值2: " + HexUtil.toHexString(crc2));*/ 47 | return out.first == crc1 && out.second == crc2; 48 | } 49 | } -------------------------------------------------------------------------------- /appmain/utils/security/RSAUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.security; 2 | 3 | import javax.crypto.Cipher; 4 | 5 | import java.security.*; 6 | import java.security.interfaces.RSAPrivateKey; 7 | import java.security.interfaces.RSAPublicKey; 8 | import java.security.spec.PKCS8EncodedKeySpec; 9 | import java.security.spec.X509EncodedKeySpec; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | 14 | /** 15 | * 非对称加密算法RSA算法组件 16 | * 非对称算法一般是用来传送对称加密算法的密钥来使用的,相对于DH算法,RSA算法只需要一方构造密钥,不需要 17 | * 大费周章的构造各自本地的密钥对了。DH算法只能算法非对称算法的底层实现。而RSA算法算法实现起来较为简单 18 | * 19 | * @author kongqz 20 | */ 21 | public class RSAUtils { 22 | 23 | //非对称密钥算法 24 | public static final String KEY_ALGORITHM = "RSA"; 25 | /** 26 | * 密钥长度,DH算法的默认密钥长度是1024 27 | * 密钥长度必须是64的倍数,在512到65536位之间 28 | */ 29 | private static final int KEY_SIZE = 1024; 30 | //公钥 31 | private static final String PUBLIC_KEY = "RSAPublicKey"; 32 | //私钥 33 | private static final String PRIVATE_KEY = "RSAPrivateKey"; 34 | 35 | /** 36 | * 初始化密钥对 37 | * 38 | * @return Map 甲方密钥的Map 39 | */ 40 | public static Map initKey() throws Exception { 41 | //实例化密钥生成器 42 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); 43 | //初始化密钥生成器 44 | keyPairGenerator.initialize(KEY_SIZE); 45 | //生成密钥对 46 | KeyPair keyPair = keyPairGenerator.generateKeyPair(); 47 | //甲方公钥 48 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 49 | //甲方私钥 50 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 51 | //将密钥存储在map中 52 | Map keyMap = new HashMap<>(); 53 | keyMap.put(PUBLIC_KEY, publicKey); 54 | keyMap.put(PRIVATE_KEY, privateKey); 55 | return keyMap; 56 | } 57 | 58 | /** 59 | * 私钥加密 60 | * 61 | * @param data 待加密数据 62 | * @param key 密钥 63 | * @return byte[] 加密数据 64 | */ 65 | public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception { 66 | 67 | //取得私钥 68 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); 69 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 70 | //生成私钥 71 | PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); 72 | //数据加密 73 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 74 | cipher.init(Cipher.ENCRYPT_MODE, privateKey); 75 | return cipher.doFinal(data); 76 | } 77 | 78 | /** 79 | * 公钥加密 80 | * 81 | * @param data 待加密数据 82 | * @param key 密钥 83 | * @return byte[] 加密数据 84 | */ 85 | public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception { 86 | 87 | //实例化密钥工厂 88 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 89 | //初始化公钥 90 | //密钥材料转换 91 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); 92 | //产生公钥 93 | PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); 94 | //数据加密 95 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 96 | cipher.init(Cipher.ENCRYPT_MODE, pubKey); 97 | return cipher.doFinal(data); 98 | } 99 | 100 | /** 101 | * 私钥解密 102 | * 103 | * @param data 待解密数据 104 | * @param key 密钥 105 | * @return byte[] 解密数据 106 | */ 107 | public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception { 108 | //取得私钥 109 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); 110 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 111 | //生成私钥 112 | PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); 113 | //数据解密 114 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 115 | cipher.init(Cipher.DECRYPT_MODE, privateKey); 116 | return cipher.doFinal(data); 117 | } 118 | 119 | /** 120 | * 公钥解密 121 | * 122 | * @param data 待解密数据 123 | * @param key 密钥 124 | * @return byte[] 解密数据 125 | */ 126 | public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception { 127 | //实例化密钥工厂 128 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 129 | //初始化公钥 130 | //密钥材料转换 131 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); 132 | //产生公钥 133 | PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); 134 | //数据解密 135 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 136 | cipher.init(Cipher.DECRYPT_MODE, pubKey); 137 | return cipher.doFinal(data); 138 | } 139 | 140 | /** 141 | * 取得私钥 142 | * 143 | * @param keyMap 密钥map 144 | * @return byte[] 私钥 145 | */ 146 | public static byte[] getPrivateKey(Map keyMap) { 147 | Key key = (Key) keyMap.get(PRIVATE_KEY); 148 | return key.getEncoded(); 149 | } 150 | 151 | /** 152 | * 取得公钥 153 | * 154 | * @param keyMap 密钥map 155 | * @return byte[] 公钥 156 | */ 157 | public static byte[] getPublicKey(Map keyMap) throws Exception { 158 | Key key = (Key) keyMap.get(PUBLIC_KEY); 159 | return key.getEncoded(); 160 | } 161 | 162 | } -------------------------------------------------------------------------------- /appmain/utils/stream/FileListenUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.stream; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | 10 | /* 11 | * 用于监听文件更新并且回调各项操作! 12 | * */ 13 | public class FileListenUtils { 14 | 15 | private static String LOG_TAG = FileListenUtils.class.getSimpleName(); 16 | private OnPrintLisenter mPrintLisenter = null; 17 | private volatile boolean isWorking = false; 18 | private volatile boolean isPause = false; 19 | private FileInputStream fis = null; 20 | private File mTarget; 21 | 22 | public FileListenUtils(File target) { 23 | mTarget = target; 24 | } 25 | 26 | /* 27 | * 接口,监听到文件新行会回调! 28 | * */ 29 | public interface OnPrintLisenter { 30 | void onPrint(String out); 31 | } 32 | 33 | /* 34 | * 监听标准输出的线程! 35 | * */ 36 | private class PrintThread extends Thread { 37 | 38 | @Override 39 | public void run() { 40 | if (mTarget == null) return; 41 | Log.d(LOG_TAG, "控制台打印线程被执行!"); 42 | try { 43 | fis = new FileInputStream(mTarget); 44 | } catch (FileNotFoundException e) { 45 | e.printStackTrace(); 46 | } 47 | while (isWorking) { 48 | //暂停,也就是跳过! 49 | if (isPause) continue; 50 | //开始执行监听! 51 | if (fis != null) { 52 | //Log.d(LOG_TAG, "控制台打印线程正在运行!"); 53 | try { 54 | //处理行数据,进行回调! 55 | int byteCount = fis.available(); 56 | if (byteCount > 0) { 57 | byte[] bytes = new byte[byteCount]; 58 | int len = fis.read(bytes); 59 | if (len != byteCount) Log.d(LOG_TAG, "接收到的字节长度和欲接收的字节长度不一样!"); 60 | String str = new String(bytes, "UTF-8"); 61 | mPrintLisenter.onPrint(str); 62 | //Log.d(LOG_TAG, "控制台打印线程: " + str); 63 | } 64 | } catch (IOException ioe) { 65 | ioe.printStackTrace(); 66 | } 67 | } 68 | } 69 | isWorking = false; 70 | //在停止线程后应当释放资源! 71 | try { 72 | if (fis != null) 73 | fis.close(); 74 | } catch (IOException e) { 75 | e.printStackTrace(); 76 | } 77 | Log.d(LOG_TAG, "控制台打印线程被结束!"); 78 | } 79 | } 80 | 81 | public void setPrintLisenter(OnPrintLisenter lisenter) { 82 | this.mPrintLisenter = lisenter; 83 | } 84 | 85 | //开始打印线程,从文件种读取被重定向到文件的标准输出! 86 | public void start() { 87 | if (mPrintLisenter != null) { 88 | //检查标准输出重定向的文件! 89 | if (!mTarget.exists() || !mTarget.isFile()) { 90 | mPrintLisenter.onPrint("中转文件不存在或非文件,请检查文件读写权限!\n"); 91 | mPrintLisenter.onPrint("标准输出重定向执行失败,无法获得运行时消息!\n"); 92 | mPrintLisenter.onPrint("尝试打印重定向文件信息:" + mTarget.getAbsolutePath() + "\n"); 93 | return; 94 | } 95 | //不在运行状态则开始新的线程! 96 | if (!isWorking) { 97 | //标志位改变,开始执行监听线程! 98 | isWorking = true; 99 | new PrintThread().start(); 100 | } else { 101 | //当前已有在执行的线程! 102 | Log.d(LOG_TAG, "当前已有在执行的控制台转发监听线程!"); 103 | if (isPause) { 104 | Log.d(LOG_TAG, "当前已在执行的控制台转发监听线程被暂停,将会重新启动!"); 105 | isPause = false; 106 | } 107 | } 108 | } else { 109 | Log.w(LOG_TAG, "mPrintLisenter是空引用,请检查逻辑!"); 110 | } 111 | } 112 | 113 | //停止打印线程! 114 | public void stop() { 115 | isWorking = false; 116 | } 117 | 118 | //暂停打印线程! 119 | public void pause() { 120 | isPause = true; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /appmain/utils/stream/IOUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.stream; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import java.io.Closeable; 6 | import java.io.Flushable; 7 | import java.io.IOException; 8 | 9 | public class IOUtils { 10 | public static boolean close(@Nullable Closeable closeable) { 11 | if (closeable == null) return false; 12 | try { 13 | closeable.close(); 14 | return true; 15 | } catch (IOException e) { 16 | e.printStackTrace(); 17 | } 18 | return false; 19 | } 20 | 21 | public static boolean flush(@Nullable Flushable flushable) { 22 | if (flushable == null) return false; 23 | try { 24 | flushable.flush(); 25 | return true; 26 | } catch (IOException e) { 27 | e.printStackTrace(); 28 | return false; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /appmain/utils/stream/LineParseUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.stream; 2 | 3 | import java.util.Queue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | 6 | public class LineParseUtils extends Thread { 7 | 8 | private String LOG_TAG = this.getClass().getSimpleName(); 9 | 10 | /* 11 | * 回调接口,当有完整的一行出现时回调! 12 | * */ 13 | public interface OnNewLineLisenter { 14 | void onNewLine(String str); 15 | } 16 | 17 | //队列,生产消费! 18 | private Queue mConsoleQueue = new LinkedBlockingQueue<>(); 19 | //回调接口! 20 | private OnNewLineLisenter mLisenter; 21 | //标志,是否暂停! 22 | private volatile boolean mPauseLabel = false; 23 | //标志,是否结束! 24 | private volatile boolean mCancelLabel = false; 25 | 26 | public LineParseUtils(OnNewLineLisenter lisenter) { 27 | mLisenter = lisenter; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | //迭代队列 33 | StringBuilder sb = new StringBuilder(256); 34 | while (!mCancelLabel) { 35 | if (mPauseLabel) { 36 | //Log.d(LOG_TAG, "DynamicLineParseThread is pause!"); 37 | continue; 38 | } 39 | if (mConsoleQueue.size() == 0) continue; 40 | if (mLisenter != null) { 41 | Character c; 42 | while ((c = mConsoleQueue.poll()) != null) { 43 | //遇到的是换行符,则需要处理换行符! 44 | if (c == '\n') { 45 | //回调之前的结果! 46 | String s = sb.toString(); 47 | //Log.d("****", "DLPU新行: " + s); 48 | //开始回调! 49 | mLisenter.onNewLine(s); 50 | //清除缓存,重新建立对象! 51 | sb = new StringBuilder(256); 52 | //尝试通知GC 53 | System.gc(); 54 | //直接跳过下一步的换行符添加! 55 | break; 56 | } 57 | //否则一直追加进缓冲区 58 | sb.append((char) c); 59 | //Log.d("****", "DLPU: " + sb.toString()); 60 | } 61 | } 62 | } 63 | } 64 | 65 | @Override 66 | public synchronized void start() { 67 | //处理启动相关的实现! 68 | mPauseLabel = false; 69 | if (!isAlive()) { 70 | super.start(); 71 | } 72 | } 73 | 74 | public synchronized void appendText(Character txt) { 75 | mConsoleQueue.add(txt); 76 | } 77 | 78 | public synchronized void pause() { 79 | mPauseLabel = true; 80 | } 81 | 82 | public synchronized void cancel() { 83 | mCancelLabel = true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /appmain/utils/system/AppAssetsUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /* 12 | * 针对Assets进行操作的类! 13 | * */ 14 | public class AppAssetsUtils { 15 | 16 | private Context context; 17 | 18 | public AppAssetsUtils(Context context) { 19 | this.context = context; 20 | } 21 | 22 | //判断assets文件是否存在! 23 | public boolean isFileExists(String fileName) { 24 | InputStream is = null; 25 | boolean ret = false; 26 | try { 27 | is = context.getResources().getAssets().open(fileName); 28 | ret = true; 29 | } catch (IOException e) { 30 | e.printStackTrace(); 31 | } finally { 32 | try { 33 | if (is != null) 34 | is.close(); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | return ret; 40 | } 41 | 42 | //得到assets指定目录下的所有文件! 43 | public String[] getFiles(String root) { 44 | String[] files = new String[0]; 45 | try { 46 | files = context.getAssets().list(root); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | if (files == null || files.length == 0) return null; 51 | return files; 52 | } 53 | 54 | //移动assets中的文件到指定目录 55 | public boolean moveFile(String asFile, String targetPath) { 56 | File file = new File(targetPath); 57 | if (!file.exists() || !file.isFile()) { 58 | try { 59 | if (!file.createNewFile()) { 60 | return false; 61 | } 62 | } catch (IOException e) { 63 | e.printStackTrace(); 64 | return false; 65 | } 66 | } 67 | boolean ret = false; 68 | //移动默认key文件 69 | AssetManager am = context.getResources().getAssets(); 70 | InputStream is = null; 71 | FileOutputStream fos = null; 72 | try { 73 | is = am.open(asFile); 74 | fos = new FileOutputStream(file); 75 | int len = is.available(); 76 | for (int i = 0; i < len; ++i) { 77 | fos.write((byte) is.read()); 78 | } 79 | ret = true; 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | try { 83 | if (is != null) is.close(); 84 | if (fos != null) fos.close(); 85 | ret = false; 86 | } catch (IOException e1) { 87 | e1.printStackTrace(); 88 | } 89 | } finally { 90 | try { 91 | if (is != null) is.close(); 92 | if (fos != null) fos.close(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | return ret; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /appmain/utils/system/AppContextUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | 6 | public class AppContextUtils { 7 | private static AppContextUtils thiz = null; 8 | public static Application app; 9 | 10 | private AppContextUtils() { 11 | } 12 | 13 | public static AppContextUtils getInstance() { 14 | if (thiz == null) { 15 | thiz = new AppContextUtils(); 16 | } 17 | return thiz; 18 | } 19 | 20 | public static void register(Application app) { 21 | AppContextUtils.app = app; 22 | } 23 | 24 | public void finishAll() { 25 | for (Activity activity : CrashUtils.activities) { 26 | activity.finish(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /appmain/utils/system/AppListUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.ApplicationInfo; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.content.pm.ResolveInfo; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class AppListUtils { 14 | 15 | //获取用户安装的APP 16 | public static List getInstalledApplication(Context context, boolean needSysAPP) { 17 | PackageManager packageManager = context.getPackageManager(); 18 | Intent intent = new Intent(Intent.ACTION_MAIN); 19 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 20 | List resolveInfos = packageManager.queryIntentActivities(intent, 0); 21 | if (!needSysAPP) { 22 | List resolveInfosWithoutSystem = new ArrayList<>(); 23 | for (int i = 0; i < resolveInfos.size(); i++) { 24 | ResolveInfo resolveInfo = resolveInfos.get(i); 25 | try { 26 | if (!isSysApp(context, resolveInfo.activityInfo.packageName)) { 27 | resolveInfosWithoutSystem.add(resolveInfo); 28 | } 29 | } catch (PackageManager.NameNotFoundException e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | return resolveInfosWithoutSystem; 34 | } 35 | return resolveInfos; 36 | } 37 | 38 | //判断是否系统应用 39 | public static boolean isSysApp(Context context, String packageName) throws PackageManager.NameNotFoundException { 40 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); 41 | return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /appmain/utils/system/AppResourceUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.app.Application; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Build; 9 | import android.os.Handler; 10 | import android.os.Looper; 11 | 12 | import com.proxgrind.chameleon.utils.system.AppContextUtils; 13 | 14 | public class AppResourceUtils { 15 | 16 | private static Application context = AppContextUtils.app; 17 | 18 | //根据colorId得到颜色 19 | public static int getColor(int colorId) { 20 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 21 | return context.getColor(colorId); 22 | } 23 | return context.getResources().getColor(colorId); 24 | } 25 | 26 | //根据drawableId得到drawable对象 27 | public static Drawable getDrawable(int drawableId) { 28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 29 | return context.getDrawable(drawableId); 30 | } 31 | return context.getResources().getDrawable(drawableId); 32 | } 33 | 34 | //复制文本到剪贴板 35 | public static void copyStr2Clipborad(String label, String content) { 36 | new Handler(Looper.getMainLooper()).post(new Runnable() { 37 | @Override 38 | public void run() { 39 | ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 40 | if (clipboardManager == null) return; 41 | //创建ClipData对象 42 | ClipData clipData = ClipData.newPlainText(label, content); 43 | //添加ClipData对象到剪切板中 44 | clipboardManager.setPrimaryClip(clipData); 45 | } 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /appmain/utils/system/AppRestartUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import com.proxgrind.chameleon.services.RestartService; 7 | 8 | public class AppRestartUtils { 9 | 10 | public interface OnExitAction { 11 | /* 12 | * 如果返回true,则使用System.exit终结,否则使用他自几实现自带的。 13 | * */ 14 | boolean usingSystemExit(); 15 | } 16 | 17 | /** 18 | * 此工具类用来重启APP,只是单纯的重启,不做任何处理。 19 | * Created by 13itch on 2016/8/5. 20 | */ 21 | 22 | /** 23 | * 重启整个APP 24 | * 25 | * @param context 上下文 26 | * @param Delayed 延迟多少毫秒 27 | * @param action 在退出时的回调,如果回调返回true,则杀死当前的进程! 28 | */ 29 | public static void restartAPP(Context context, long Delayed, OnExitAction action) { 30 | /**开启一个新的服务,用来重启本APP*/ 31 | Intent intent1 = new Intent(context, RestartService.class); 32 | intent1.putExtra("PackageName", context.getApplicationContext().getPackageName()); 33 | intent1.putExtra("Delayed", Delayed); 34 | context.startService(intent1); 35 | if (action != null && action.usingSystemExit()) { 36 | /**杀死整个进程**/ 37 | android.os.Process.killProcess(android.os.Process.myPid()); 38 | System.exit(0); 39 | } 40 | } 41 | 42 | /** 43 | * 重启整个APP 44 | * 45 | * @param context 上下文 46 | * @param Delayed 延迟多少毫秒 47 | */ 48 | public static void restartAPP(Context context, long Delayed) { 49 | Intent intent1 = new Intent(context, RestartService.class); 50 | intent1.putExtra("PackageName", context.getApplicationContext().getPackageName()); 51 | intent1.putExtra("Delayed", Delayed); 52 | context.startService(intent1); 53 | } 54 | 55 | /***重启整个APP*/ 56 | public static void restartAPP(Context context) { 57 | restartAPP(context, 2000, new OnExitAction() { 58 | @Override 59 | public boolean usingSystemExit() { 60 | return true; 61 | } 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /appmain/utils/system/CrashUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | 11 | import com.proxgrind.chameleon.activities.CrashActivity; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | public class CrashUtils { 17 | private static final Thread.UncaughtExceptionHandler DEFAULT_UNCAUGHT = Thread.getDefaultUncaughtExceptionHandler(); 18 | public static final List activities = new ArrayList<>(); 19 | 20 | /* 21 | * callback for activity! 22 | * */ 23 | private static final 24 | Application.ActivityLifecycleCallbacks callbacks4Act = new Application.ActivityLifecycleCallbacks() { 25 | @Override 26 | public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { 27 | //must add activity to list! 28 | activities.add(activity); 29 | } 30 | 31 | @Override 32 | public void onActivityStarted(@NonNull Activity activity) { 33 | 34 | } 35 | 36 | @Override 37 | public void onActivityResumed(@NonNull Activity activity) { 38 | 39 | } 40 | 41 | @Override 42 | public void onActivityPaused(@NonNull Activity activity) { 43 | 44 | } 45 | 46 | @Override 47 | public void onActivityStopped(@NonNull Activity activity) { 48 | 49 | } 50 | 51 | @Override 52 | public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { 53 | 54 | } 55 | 56 | @Override 57 | public void onActivityDestroyed(@NonNull Activity activity) { 58 | //must remove activity from list! 59 | activities.remove(activity); 60 | } 61 | }; 62 | 63 | public static void register(final Application application) { 64 | //register callback! 65 | application.registerActivityLifecycleCallbacks(callbacks4Act); 66 | Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 67 | @Override 68 | public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) { 69 | //跳转到奔溃信息处理界面 70 | Intent intent = new Intent(application, CrashActivity.class); 71 | intent.putExtra("crash", e); 72 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 73 | //destroy all activity 74 | for (Activity act : activities) { 75 | act.finish(); 76 | } 77 | application.startActivity(intent); 78 | //调用默认的异常处理 79 | if (DEFAULT_UNCAUGHT != null) { 80 | DEFAULT_UNCAUGHT.uncaughtException(t, e); 81 | } 82 | } 83 | }); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /appmain/utils/system/LanguageUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.content.Context; 4 | import android.content.res.Configuration; 5 | import android.os.Build; 6 | import android.os.LocaleList; 7 | 8 | import java.util.Locale; 9 | 10 | public class LanguageUtils { 11 | 12 | /* 13 | * 获得语言列表! 14 | * */ 15 | public static LocaleList getLocaleList(Context context) { 16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 17 | return context.getResources().getConfiguration().getLocales(); 18 | } else { 19 | return new LocaleList(context.getResources().getConfiguration().locale); 20 | } 21 | } 22 | 23 | /* 24 | * 获得当前系统默认的语言! 25 | * */ 26 | public static Locale getDefaultLocale(Context context) { 27 | return Locale.getDefault(); 28 | } 29 | 30 | /* 31 | * 设置当前的语言! 32 | * */ 33 | public static Context setAppLanguage(Context context, String language) { 34 | Configuration configuration = context.getResources().getConfiguration(); 35 | configuration.setLocale(new Locale(language)); 36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { 37 | return context.createConfigurationContext(configuration); 38 | } else { 39 | context.getResources().updateConfiguration(configuration, context.getResources().getDisplayMetrics()); 40 | return context; 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /appmain/utils/system/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.util.Log; 4 | 5 | import com.proxgrind.chameleon.BuildConfig; 6 | 7 | public class LogUtils { 8 | private static String TAG = "LogUtils"; 9 | private static boolean log_open; 10 | 11 | static { 12 | // 是否需要打开DEBUG模式! 13 | log_open = BuildConfig.DEBUG; 14 | } 15 | 16 | public static void setEnable(boolean enable) { 17 | log_open = enable; 18 | } 19 | 20 | public static void setTAG(String tag) { 21 | TAG = tag; 22 | } 23 | 24 | public static String getTag() { 25 | return TAG; 26 | } 27 | 28 | public static void v(String msg) { 29 | if (log_open) 30 | Log.v(TAG, msg); 31 | } 32 | 33 | public static void v(String msg, Throwable throwable) { 34 | if (log_open) 35 | Log.v(TAG, msg, throwable); 36 | } 37 | 38 | public static void d(String msg) { 39 | if (log_open) 40 | Log.d(TAG, msg); 41 | } 42 | 43 | public static void d(String msg, Throwable throwable) { 44 | if (log_open) 45 | Log.d(TAG, msg, throwable); 46 | } 47 | 48 | public static void i(String msg) { 49 | if (log_open) 50 | Log.i(TAG, msg); 51 | } 52 | 53 | public static void i(String msg, Throwable throwable) { 54 | if (log_open) 55 | Log.i(TAG, msg, throwable); 56 | } 57 | 58 | public static void w(String msg) { 59 | if (log_open) 60 | Log.w(TAG, msg); 61 | } 62 | 63 | public static void w(String msg, Throwable throwable) { 64 | if (log_open) 65 | Log.w(TAG, msg, throwable); 66 | } 67 | 68 | public static void e(String msg) { 69 | if (log_open) 70 | Log.e(TAG, msg); 71 | } 72 | 73 | public static void e(String msg, Throwable throwable) { 74 | if (log_open) 75 | Log.e(TAG, msg, throwable); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /appmain/utils/system/RomUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.os.Build; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | 11 | /** 12 | * Created by HaiyuKing 13 | * Used 判断手机ROM,检测ROM是MIUI、EMUI还是Flyme 14 | * 参考资料:https://www.jianshu.com/p/ba9347a5a05a 15 | */ 16 | public class RomUtils { 17 | private static final String TAG = "Rom"; 18 | 19 | public static final String ROM_MIUI = "MIUI"; 20 | public static final String ROM_EMUI = "EMUI"; 21 | public static final String ROM_FLYME = "FLYME"; 22 | public static final String ROM_OPPO = "OPPO"; 23 | public static final String ROM_SMARTISAN = "SMARTISAN"; 24 | public static final String ROM_VIVO = "VIVO"; 25 | public static final String ROM_QIKU = "QIKU"; 26 | 27 | private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name"; 28 | private static final String KEY_VERSION_EMUI = "ro.build.version.emui"; 29 | private static final String KEY_VERSION_OPPO = "ro.build.version.opporom"; 30 | private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version"; 31 | private static final String KEY_VERSION_VIVO = "ro.vivo.os.version"; 32 | 33 | private static String sName; 34 | private static String sVersion; 35 | 36 | //华为 37 | public static boolean isEmui() { 38 | return check(ROM_EMUI); 39 | } 40 | 41 | //小米 42 | public static boolean isMiui() { 43 | return check(ROM_MIUI); 44 | } 45 | 46 | //vivo 47 | public static boolean isVivo() { 48 | return check(ROM_VIVO); 49 | } 50 | 51 | //oppo 52 | public static boolean isOppo() { 53 | return check(ROM_OPPO); 54 | } 55 | 56 | //魅族 57 | public static boolean isFlyme() { 58 | return check(ROM_FLYME); 59 | } 60 | 61 | //360手机 62 | public static boolean is360() { 63 | return check(ROM_QIKU) || check("360"); 64 | } 65 | 66 | //坚果手机 67 | public static boolean isSmartisan() { 68 | return check(ROM_SMARTISAN); 69 | } 70 | 71 | public static String getName() { 72 | if (sName == null) { 73 | check(""); 74 | } 75 | return sName; 76 | } 77 | 78 | public static String getVersion() { 79 | if (sVersion == null) { 80 | check(""); 81 | } 82 | return sVersion; 83 | } 84 | 85 | public static boolean check(String rom) { 86 | if (sName != null) { 87 | return sName.equals(rom); 88 | } 89 | 90 | if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) { 91 | sName = ROM_MIUI; 92 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) { 93 | sName = ROM_EMUI; 94 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) { 95 | sName = ROM_OPPO; 96 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) { 97 | sName = ROM_VIVO; 98 | } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) { 99 | sName = ROM_SMARTISAN; 100 | } else { 101 | sVersion = Build.DISPLAY; 102 | if (sVersion.toUpperCase().contains(ROM_FLYME)) { 103 | sName = ROM_FLYME; 104 | } else { 105 | sVersion = Build.UNKNOWN; 106 | sName = Build.MANUFACTURER.toUpperCase(); 107 | } 108 | } 109 | return sName.equals(rom); 110 | } 111 | 112 | public static String getProp(String name) { 113 | String line; 114 | BufferedReader input = null; 115 | try { 116 | Process p = java.lang.Runtime.getRuntime().exec("getprop " + name); 117 | input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); 118 | line = input.readLine(); 119 | input.close(); 120 | } catch (IOException ex) { 121 | Log.e(TAG, "Unable to read prop " + name, ex); 122 | return null; 123 | } finally { 124 | if (input != null) { 125 | try { 126 | input.close(); 127 | } catch (IOException e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | } 132 | return line; 133 | } 134 | } -------------------------------------------------------------------------------- /appmain/utils/system/SystemUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | /** 4 | * @author DXL 5 | */ 6 | public class SystemUtils { 7 | 8 | /** 9 | * 判断当前是否超时 10 | * 11 | * @param startTimeStamp 开始时间(时间戳形式) 12 | * @param timeoutms 超时值,当最新的时间超过了这个值时将会被判断为超时! 13 | * @return true 超时, 14 | */ 15 | public static boolean isTimeout(long startTimeStamp, long timeoutms) { 16 | return System.currentTimeMillis() - startTimeStamp >= timeoutms; 17 | } 18 | 19 | // 简化休眠 20 | public static void sleep(long ms) { 21 | try { 22 | Thread.sleep(ms); 23 | } catch (InterruptedException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | /** 29 | * Calculates the checksum of the passed byte buffer. 30 | * 31 | * @param buffer 32 | * @return byte checksum value 33 | */ 34 | public static byte calcChecksum(byte[] buffer, boolean sub) { 35 | if (buffer == null) return 0; 36 | byte checksum = 0; 37 | int bufPos = 0; 38 | int byteCount = buffer.length; 39 | while (byteCount-- != 0) { 40 | byte b = buffer[bufPos++]; 41 | if (!sub) 42 | checksum += b; 43 | else 44 | checksum -= b; 45 | } 46 | return checksum; 47 | } 48 | 49 | /** 50 | * Calculates the checksum of the passed byte buffer. 51 | * 52 | * @param buffer 53 | * @return byte checksum value 54 | */ 55 | public static byte calcChecksub(byte checkSum, byte[] buffer, boolean sub) { 56 | if (buffer == null) return 0; 57 | byte checksum = checkSum; 58 | int bufPos = 0; 59 | int byteCount = buffer.length; 60 | while (byteCount-- != 0) { 61 | byte b = buffer[bufPos++]; 62 | if (!sub) 63 | checksum += b; 64 | else 65 | checksum -= b; 66 | //System.out.println("value: " + HexUtil.toHexString(tmp) + "," + HexUtil.toHexString(b) + " checksum: " + HexUtil.toHexString(checksum)); 67 | } 68 | return checksum; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /appmain/utils/system/VibratorUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.system; 2 | 3 | import android.content.Context; 4 | import android.os.VibrationEffect; 5 | import android.os.Vibrator; 6 | 7 | /** 8 | * 震动工具! 9 | * 10 | * @author DXL 11 | */ 12 | public class VibratorUtils { 13 | 14 | //进行抖动! 15 | public static void runOneAsDelay(Context context, int delay) { 16 | Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 17 | if (vibrator != null) 18 | if (vibrator.hasVibrator()) { //有振动器 19 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 20 | VibrationEffect vibrationEffect = VibrationEffect.createOneShot(delay, VibrationEffect.DEFAULT_AMPLITUDE); 21 | vibrator.vibrate(vibrationEffect); 22 | } else { 23 | vibrator.vibrate(delay); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /appmain/utils/tools/ArrayUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /* 8 | * 一些数组,集合操作的封装类! 9 | * */ 10 | public class ArrayUtils { 11 | //将字符串链表或者数列转换为一般字符串数组 12 | public static T[] list2Arr(List list) { 13 | if (list == null) return null; 14 | if (list.size() == 0) return null; 15 | return list.toArray((T[]) Array.newInstance(list.get(0).getClass(), list.size())); 16 | } 17 | 18 | //obj数组去重 19 | public static T[] unrepeat(T[] objs) { 20 | if (objs == null) return null; 21 | if (objs.length == 0) return null; 22 | ArrayList list = new ArrayList<>(); 23 | for (int i = 0; i < objs.length; ++i) { 24 | if (list.indexOf(objs[i]) == -1) { 25 | //-1证明没有找到这个元素的存在,添加进去! 26 | list.add(objs[i]); 27 | } 28 | } 29 | return list.toArray((T[]) Array.newInstance(objs[0].getClass(), list.size())); 30 | } 31 | 32 | /** 33 | * 得到一个数组中的元素,如果越界则为空! 34 | * 35 | * @param array 需要被取出元素的数组! 36 | * @param index 需要取出的对应数组的元素的索引! 37 | * @return 如果不越界,则取出对应的值,否则直接返回null 38 | */ 39 | public static T getElement(T[] array, int index) { 40 | return index >= array.length ? null : array[index]; 41 | } 42 | 43 | // 得到距离数组开始的有效长度! 44 | public static int getLength(T[] array, int offset) { 45 | if (offset >= array.length) return -1; 46 | return array.length - offset; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /appmain/utils/tools/AssetsUtil.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /* 12 | * 针对Assets进行操作的类! 13 | * */ 14 | public class AssetsUtil { 15 | 16 | private Context context; 17 | 18 | public AssetsUtil(Context context) { 19 | this.context = context; 20 | } 21 | 22 | //判断assets文件是否存在! 23 | public boolean isFileExists(String fileName) { 24 | InputStream is = null; 25 | boolean ret = false; 26 | try { 27 | is = context.getResources().getAssets().open(fileName); 28 | ret = true; 29 | } catch (IOException e) { 30 | e.printStackTrace(); 31 | } finally { 32 | try { 33 | if (is != null) 34 | is.close(); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | return ret; 40 | } 41 | 42 | //得到assets指定目录下的所有文件! 43 | public String[] getFiles(String root) { 44 | String[] files = new String[0]; 45 | try { 46 | files = context.getAssets().list(root); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | if (files == null || files.length == 0) return null; 51 | return files; 52 | } 53 | 54 | //移动assets中的文件到指定目录 55 | public boolean moveFile(String asFile, String targetPath) { 56 | File file = new File(targetPath); 57 | if (!file.exists() || !file.isFile()) { 58 | try { 59 | if (!file.createNewFile()) { 60 | return false; 61 | } 62 | } catch (IOException e) { 63 | e.printStackTrace(); 64 | return false; 65 | } 66 | } 67 | boolean ret = false; 68 | //移动默认key文件 69 | AssetManager am = context.getResources().getAssets(); 70 | InputStream is = null; 71 | FileOutputStream fos = null; 72 | try { 73 | is = am.open(asFile); 74 | fos = new FileOutputStream(file); 75 | int len = is.available(); 76 | for (int i = 0; i < len; ++i) { 77 | fos.write((byte) is.read()); 78 | } 79 | ret = true; 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | try { 83 | if (is != null) is.close(); 84 | if (fos != null) fos.close(); 85 | ret = false; 86 | } catch (IOException e1) { 87 | e1.printStackTrace(); 88 | } 89 | } finally { 90 | try { 91 | if (is != null) is.close(); 92 | if (fos != null) fos.close(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | return ret; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /appmain/utils/tools/CountDown.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | 6 | /* 7 | * 倒计时任务! 8 | * */ 9 | public class CountDown extends TimerTask { 10 | 11 | private int timeDelay = 1000; 12 | private transient int countdynamic = 0; 13 | private Progress mProgress; 14 | private Timer timer; 15 | 16 | public CountDown(Progress progress) { 17 | timer = new Timer(); 18 | mProgress = progress; 19 | } 20 | 21 | //倒计时回调接口 22 | public interface Progress { 23 | boolean onProgress(int countdynamic); 24 | } 25 | 26 | //设置回调! 27 | public void setProgress(Progress progress) { 28 | mProgress = progress; 29 | } 30 | 31 | //设置每次的延迟 32 | public CountDown setTimeDelay(int ms) { 33 | timeDelay = ms; 34 | return this; 35 | } 36 | 37 | //设置需要延迟多少次! 38 | public CountDown setCountDown(int count) { 39 | countdynamic = count; 40 | return this; 41 | } 42 | 43 | //开始倒计时! 44 | public CountDown startCountDown() { 45 | if (countdynamic == 0) return this; 46 | timer.schedule(this, 0, timeDelay); 47 | return this; 48 | } 49 | 50 | //取消倒计时 51 | public CountDown cancelCountDown() { 52 | cancel(); 53 | countdynamic = 0; 54 | return this; 55 | } 56 | 57 | //是否处于倒计时状态! 58 | public boolean isRunning() { 59 | return this.countdynamic != 0; 60 | } 61 | 62 | @Override 63 | public void run() { 64 | //判断为零,立刻回调结束 65 | if (countdynamic == 0) { 66 | mProgress.onProgress(0); 67 | cancelCountDown(); 68 | } else { 69 | //回调且判断需不需要继续下次回调! 70 | if (!mProgress.onProgress(countdynamic)) { 71 | cancelCountDown(); 72 | return; 73 | } 74 | --countdynamic; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /appmain/utils/tools/FragmentUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.app.Activity; 4 | 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.fragment.app.Fragment; 7 | import androidx.fragment.app.FragmentActivity; 8 | import androidx.fragment.app.FragmentManager; 9 | 10 | import com.proxgrind.chameleon.R; 11 | 12 | import java.util.List; 13 | 14 | /* 15 | * 一些碎片开发使用上的工具! 16 | * */ 17 | public class FragmentUtils { 18 | 19 | //隐藏所有的碎片! 20 | public static void hides(FragmentManager manager, Fragment exclude) { 21 | List fragmentList = manager.getFragments(); 22 | //迭代隐藏所有的碎片! 23 | for (Fragment fragment : fragmentList) 24 | //排除指定的碎片! 25 | if (fragment != exclude) 26 | manager.beginTransaction().hide(fragment).commitAllowingStateLoss(); 27 | } 28 | 29 | public static void showAndAddBackStack(FragmentActivity activity, Fragment fragment) { 30 | if (activity == null || fragment == null) return; 31 | FragmentManager manager = activity.getSupportFragmentManager(); 32 | manager.beginTransaction() 33 | .add(R.id.mainContainer, fragment) 34 | .addToBackStack(fragment.getTag()).commit(); 35 | } 36 | 37 | public static void runOnUiThread(Activity activity, Runnable runnable) { 38 | if (activity != null) 39 | activity.runOnUiThread(runnable); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /appmain/utils/tools/GlobalTag.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.nfc.Tag; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 全局的标签缓存! 10 | */ 11 | public class GlobalTag { 12 | private static Tag tag = null; 13 | private static List listeners = new ArrayList<>(); 14 | 15 | public static Tag getTag() { 16 | return tag; 17 | } 18 | 19 | public static void setTag(Tag tag) { 20 | GlobalTag.tag = tag; 21 | } 22 | 23 | public interface OnNewTagListener { 24 | void onNewTag(Tag tag); 25 | } 26 | 27 | public static void addListener(OnNewTagListener listener) { 28 | listeners.add(listener); 29 | } 30 | 31 | public static void removeListener(OnNewTagListener listener) { 32 | listeners.remove(listener); 33 | } 34 | 35 | public static void notifyOnNewTag(Tag tag) { 36 | //直接通知TAG的变化! 37 | for (OnNewTagListener l : listeners) { 38 | try { 39 | l.onNewTag(tag); 40 | } catch (Exception ignored) { 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /appmain/utils/tools/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import java.security.MessageDigest; 4 | 5 | //MD5加密不可逆 6 | public class MD5Utils { 7 | /** 8 | * 对字节内容进行加密 9 | * 10 | * @param source 摘要对象! 11 | * @return 密文 12 | */ 13 | public static String digest(byte[] source) { 14 | try { 15 | MessageDigest digest = MessageDigest.getInstance("MD5"); 16 | return HexUtil.toHexString(digest.digest(source)); 17 | } catch (Exception ex) { 18 | ex.printStackTrace(); 19 | return ""; 20 | } 21 | } 22 | 23 | /** 24 | * 对字节内容进行摘要检查! 25 | * 26 | * @param digest 已经确定的摘要信息! 27 | * @param source 未知的摘要对象! 28 | * @return 摘要信息对比结果! 29 | */ 30 | public static boolean verify(String digest, byte[] source) { 31 | return digest(source).equals(digest); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /appmain/utils/tools/MifareUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | /* 4 | * MifareClassic标签用得到的工具! 5 | * */ 6 | public class MifareUtils { 7 | 8 | public static boolean validateSector(int sector) { 9 | // Do not be too strict on upper bounds checking, since some cards 10 | // have more addressable memory than they report. For example, 11 | // MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in 12 | // MIFARE Classic compatibility mode. 13 | // Note that issuing a command to an out-of-bounds block is safe - the 14 | // tag should report error causing IOException. This validation is a 15 | // helper to guard against obvious programming mistakes. 16 | 17 | int NR_TRAILERS_4k = 40; 18 | if (sector < 0 || sector >= NR_TRAILERS_4k) { 19 | return false; 20 | } 21 | return true; 22 | } 23 | 24 | public static boolean validateBlock(int block) { 25 | // Just looking for obvious out of bounds... 26 | int NR_BLOCKS_4k = 0xFF; 27 | if (block < 0 || block >= NR_BLOCKS_4k) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | public static boolean validateValueOperand(int value) { 34 | if (value < 0) { 35 | return false; 36 | } 37 | return true; 38 | } 39 | 40 | public static int blockToSector(int blockIndex) { 41 | if (!validateBlock(blockIndex)) return 0; 42 | if (blockIndex < 32 * 4) { 43 | return (blockIndex / 4); 44 | } else { 45 | return (32 + (blockIndex - 32 * 4) / 16); 46 | } 47 | } 48 | 49 | public static int sectorToBlock(int sectorIndex) { 50 | if (!validateSector(sectorIndex)) { 51 | return -1; 52 | } 53 | if (sectorIndex < 32) { 54 | return (sectorIndex * 4); 55 | } else { 56 | return (32 * 4 + (sectorIndex - 32) * 16); 57 | } 58 | } 59 | 60 | public static boolean isFirstBlock(int uiBlock) { 61 | // 测试我们是否处于小扇区或者大扇区? 62 | if (uiBlock < 128) 63 | return ((uiBlock) % 4 == 0); 64 | else 65 | return ((uiBlock) % 16 == 0); 66 | } 67 | 68 | public static boolean isTrailerBlock(int uiBlock) { 69 | // 测试我们处于小区块还是大扇区 70 | if (uiBlock < 128) 71 | return ((uiBlock + 1) % 4 == 0); 72 | else 73 | return ((uiBlock + 1) % 16 == 0); 74 | } 75 | 76 | public static int getBlockCountInSector(int sectorIndex) { 77 | if (!validateSector(sectorIndex)) return -1; 78 | if (sectorIndex < 32) { 79 | return 4; 80 | } else { 81 | return 16; 82 | } 83 | } 84 | 85 | public static int get_trailer_block(int uiFirstBlock) { 86 | // Test if we are in the small or big sectors 87 | int trailer_block; 88 | if (uiFirstBlock < 128) { 89 | trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4)); 90 | } else { 91 | trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16)); 92 | } 93 | return trailer_block; 94 | } 95 | 96 | public static int getIndexOnSector(int block, int sector) { 97 | int index = 0; 98 | //得到当前的块在扇区中的具体索引! 99 | for (int i = 0; i < getBlockCountInSector(sector); i++) { //得到当前扇区的块总数! 100 | if (block == (sectorToBlock(block) + i)) break; 101 | ++index; 102 | } 103 | return index; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /appmain/utils/tools/NetworkUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | 9 | import java.io.IOException; 10 | import java.net.InetAddress; 11 | import java.net.InetSocketAddress; 12 | import java.net.NetworkInterface; 13 | import java.net.Socket; 14 | import java.net.UnknownHostException; 15 | import java.util.Collections; 16 | import java.util.Enumeration; 17 | 18 | public class NetworkUtils { 19 | /** 20 | * 是否使用代理(WiFi状态下的,避免被抓包) 21 | */ 22 | public static boolean isWifiProxy() { 23 | String proxyAddress; 24 | int proxyPort; 25 | proxyAddress = System.getProperty("http.proxyHost"); 26 | String portstr = System.getProperty("http.proxyPort"); 27 | proxyPort = Integer.parseInt((portstr != null ? portstr : "-1")); 28 | System.out.println(proxyAddress + "~"); 29 | System.out.println("port = " + proxyPort); 30 | return (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1); 31 | } 32 | 33 | /** 34 | * 是否正在使用VPN 35 | */ 36 | public static boolean isVpnUsed() { 37 | try { 38 | Enumeration niList = NetworkInterface.getNetworkInterfaces(); 39 | if (niList != null) { 40 | for (Object intf : Collections.list(niList)) { 41 | NetworkInterface ni = (NetworkInterface) intf; 42 | if (!ni.isUp() || ni.getInterfaceAddresses().size() == 0) { 43 | continue; 44 | } 45 | Log.d("-----", "isVpnUsed() NetworkInterface Name: " + ni.getName()); 46 | if ("tun0".equals(ni.getName()) || "ppp0".equals(ni.getName())) { 47 | return true; // The VPN is up 48 | } 49 | } 50 | } 51 | } catch (Throwable e) { 52 | e.printStackTrace(); 53 | } 54 | return false; 55 | } 56 | 57 | /** 58 | * 网络是否连接! 59 | * 60 | * @param context 上下文 61 | * @return 有网时返回true,没网时返回false 62 | */ 63 | public static boolean isNetworkConnected(Context context) { 64 | if (context != null) { 65 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 66 | .getSystemService(Context.CONNECTIVITY_SERVICE); 67 | NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); 68 | if (mNetworkInfo != null) { 69 | return mNetworkInfo.isAvailable(); 70 | } 71 | } 72 | return false; 73 | } 74 | 75 | /** 76 | * wifi是否连接 77 | * 78 | * @param context 上下文 79 | * @return 是WIFI网络返回true,不是WIFI返回false 80 | */ 81 | public static boolean isWifiConnected(Context context) { 82 | if (context != null) { 83 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 84 | .getSystemService(Context.CONNECTIVITY_SERVICE); 85 | NetworkInfo mWiFiNetworkInfo = mConnectivityManager 86 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI); 87 | if (mWiFiNetworkInfo != null) { 88 | return mWiFiNetworkInfo.isAvailable(); 89 | } 90 | } 91 | return false; 92 | } 93 | 94 | /** 95 | * 移动网络是否连接 96 | * 97 | * @param context 上下文 98 | * @return 是数据流量时返回true,不是返回false 99 | */ 100 | public static boolean isMobileConnected(Context context) { 101 | if (context != null) { 102 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 103 | .getSystemService(Context.CONNECTIVITY_SERVICE); 104 | NetworkInfo mMobileNetworkInfo = mConnectivityManager 105 | .getNetworkInfo(ConnectivityManager.TYPE_MOBILE); 106 | if (mMobileNetworkInfo != null) { 107 | return mMobileNetworkInfo.isAvailable(); 108 | } 109 | } 110 | return false; 111 | } 112 | 113 | /** 114 | * 获取当前网络连接的类型信息 115 | * 116 | * @param context 上下文 117 | * @return 判断结果, 118 | */ 119 | public static int getConnectedType(Context context) { 120 | if (context != null) { 121 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 122 | .getSystemService(Context.CONNECTIVITY_SERVICE); 123 | NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); 124 | if (mNetworkInfo != null && mNetworkInfo.isAvailable()) { 125 | return mNetworkInfo.getType(); 126 | } 127 | } 128 | return -1; 129 | } 130 | 131 | /** 132 | * 判断主机是否存在! 133 | * 134 | * @param host 主机 135 | * @param timeout 超时值! 136 | */ 137 | public static boolean isHostReachable(String host, int timeout) { 138 | try { 139 | return InetAddress.getByName(host).isReachable(timeout); 140 | } catch (UnknownHostException e) { 141 | e.printStackTrace(); 142 | } catch (IOException e) { 143 | e.printStackTrace(); 144 | } 145 | return false; 146 | } 147 | 148 | /** 149 | * 判断主机是否可以连接! 150 | * 151 | * @param host 主机 152 | * @param port 端口 153 | * @param timeout 超时值 154 | */ 155 | public static boolean isHostConnectable(String host, int port, int timeout) { 156 | Socket socket = new Socket(); 157 | try { 158 | socket.connect(new InetSocketAddress(host, port), timeout); 159 | } catch (IOException e) { 160 | e.printStackTrace(); 161 | return false; 162 | } finally { 163 | try { 164 | socket.close(); 165 | } catch (IOException e) { 166 | e.printStackTrace(); 167 | } 168 | } 169 | return true; 170 | } 171 | 172 | /** 173 | * 判断主机是否可以连接! 174 | * 175 | * @param host 主机 176 | * @param port 端口 177 | */ 178 | public static boolean isHostConnectable(String host, int port) { 179 | Socket socket = new Socket(); 180 | try { 181 | socket.connect(new InetSocketAddress(host, port)); 182 | } catch (IOException e) { 183 | e.printStackTrace(); 184 | return false; 185 | } finally { 186 | try { 187 | socket.close(); 188 | } catch (IOException e) { 189 | e.printStackTrace(); 190 | } 191 | } 192 | return true; 193 | } 194 | 195 | } -------------------------------------------------------------------------------- /appmain/utils/tools/Properties.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import com.proxgrind.chameleon.utils.stream.FileUtils; 4 | 5 | import java.io.File; 6 | 7 | public interface Properties { 8 | String APP_SDCARD = FileUtils.getAppFilesDir("files").getAbsolutePath(); 9 | String APP_SETTINH_DIR = "settings"; 10 | String APP_SETTINGS_NAME = "settings.ky"; 11 | // APP的配置文件保存目录! 12 | String APP_CONF_PATH = APP_SDCARD + File.separator + APP_SETTINH_DIR; 13 | // app的通用配置文件! 14 | String APP_CONF_FILE = APP_CONF_PATH + File.separator + APP_SETTINGS_NAME; 15 | // 设备的自动关闭状态设置key! 16 | String APP_AUTO_CLOSE_KEY = "autoClose"; 17 | // 设备的自动断开时间! 18 | String APP_AUTO_CLOSE_TIME_KEY = "autoCloseTime"; 19 | // 新手模式的标志! 20 | String APP_NOVICE_MODE = "noviceMode"; 21 | // 绑定的mac地址 22 | String APP_BIND_MAC = "bindMac"; 23 | // 是否启用了MAC地址绑定! 24 | String APP_BIND_MAC_STATUS = "bindMacStatus"; 25 | // 设备备注 26 | String APP_DEVICE_REMARKS = "device_remarks"; 27 | // UI模式 28 | String APP_UI_MODE = "ui_mode"; 29 | // DUMP模式 30 | String APP_DUMP_MODE = "dump_mode"; 31 | } 32 | -------------------------------------------------------------------------------- /appmain/utils/tools/RegexGroupUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import java.util.ArrayList; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | /* 8 | * TODO 正则组匹配工具类 9 | * 根据给出的组标签反选或者正选内容! 10 | * */ 11 | public class RegexGroupUtils { 12 | 13 | /*public static void main(String args[]) { 14 | String c = "UID : 8b 36 8b eb"; 15 | String s = matcherGroup(c, ".*UID : (.{11}).*", 1, 0); 16 | System.out.println("最终测试组匹配截取: " + s); 17 | }*/ 18 | 19 | /** 20 | * @param content 被匹配的内容! 21 | * @param regex 匹配规则 22 | * @return 匹配的组! 23 | * @Method 匹配组多个,根据组得到内容结果! 24 | */ 25 | public static String[] matcherGroups(String content, String regex, int group) { 26 | //准备格式匹配对象! 27 | Pattern p = Pattern.compile(regex); 28 | //准备匹配器对象! 29 | Matcher m = p.matcher(content); 30 | //结果集! 31 | ArrayList ret = new ArrayList<>(); 32 | //迭代查组 33 | while (m.find()) { 34 | ret.add(m.group(group)); 35 | } 36 | return ret.toArray(new String[0]); 37 | } 38 | 39 | /* 40 | * Method 匹配一个组 41 | * @Param content 被匹配的内容! 42 | * @Param regex 被匹配的正则! 43 | * @Param index 组索引,位于字符串中的第一次pos 44 | * @Return 返回指定索引的组内容! 45 | * */ 46 | public static String matcherGroup(String content, String regex, int group, int index) { 47 | String[] res = matcherGroups(content, regex, group); 48 | if (index >= res.length || index < 0) return null; 49 | return res[index]; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /appmain/utils/tools/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | public class StringUtils { 4 | 5 | //字符串数组转字符串,可选择性的添加分隔符! 6 | public static String arr2Str(String[] arr, String split, boolean addSplitInEnd) { 7 | StringBuilder sb = new StringBuilder(); 8 | //进行迭代添加! 9 | for (int i = 0; i < arr.length; ++i) { 10 | //判断是否是在尾部 11 | if (i == arr.length - 1 && !addSplitInEnd) { 12 | //不添加换行符! 13 | sb.append(arr[i]); 14 | } else { 15 | sb.append(arr[i]).append(split); 16 | } 17 | } 18 | return sb.toString(); 19 | } 20 | 21 | //是否是空串 22 | public static boolean isEmpty(String str) { 23 | return str.isEmpty() || str.equals(" ") || str.matches("\\s*"); 24 | } 25 | 26 | //是否是十六进制字符串 27 | public static boolean isHexStr(String str) { 28 | return str.matches("[0-9a-fA-F]+"); 29 | } 30 | 31 | //是否是数字 32 | public static boolean isNumStr(String str) { 33 | return str.matches("[0-9]+"); 34 | } 35 | 36 | //是否是字母 37 | public static boolean isLetter(String str) { 38 | return str.matches("[A-Fa-f]+"); 39 | } 40 | 41 | //是否是纯空格 42 | public static boolean isSpaces(String str) { 43 | return str.matches(" +"); 44 | } 45 | 46 | //删除所有的空格和转为大写! 47 | public static String trimO2Upper(String content) { 48 | return content.replaceAll(" ", "").toUpperCase(); 49 | } 50 | 51 | //删除所有的空格和转为小写! 52 | public static String trimO2Lower(String content) { 53 | return content.replaceAll(" ", "").toLowerCase(); 54 | } 55 | 56 | //删除所有的空格和转为大写! 57 | public static void trimO2Upper(String[] datas) { 58 | for (int i = 0; i < datas.length; i++) { 59 | datas[i] = trimO2Upper(datas[i]); 60 | } 61 | } 62 | 63 | //删除所有的空格和转为小写! 64 | public static void trimO2Lower(String[] datas) { 65 | for (int i = 0; i < datas.length; i++) { 66 | datas[i] = trimO2Lower(datas[i]); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /appmain/utils/tools/TextStyleUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.content.Context; 4 | import android.text.SpannableString; 5 | import android.text.SpannableStringBuilder; 6 | import android.text.Spanned; 7 | import android.text.style.ForegroundColorSpan; 8 | import android.text.style.TextAppearanceSpan; 9 | 10 | /* 11 | * 设置文本的样式! 12 | * */ 13 | public class TextStyleUtils { 14 | 15 | /* 16 | * 合并多个富文本对象到构造器里! 17 | * */ 18 | public static SpannableStringBuilder merge(SpannableString... text) { 19 | SpannableStringBuilder ssb = new SpannableStringBuilder(); 20 | for (SpannableString ss : text) { 21 | ssb.append(ss); 22 | } 23 | return ssb; 24 | } 25 | 26 | /* 27 | * 设置字体前景色! 28 | * */ 29 | public static SpannableString getColorString(String str, int color) { 30 | SpannableString ret = new SpannableString(str); 31 | ret.setSpan(new ForegroundColorSpan(color), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 32 | return ret; 33 | } 34 | 35 | /* 36 | * 设置背景样式! 37 | * */ 38 | public static SpannableString getStyleString(Context context, String str, int style) { 39 | // TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色) 40 | SpannableString ret = new SpannableString(str); 41 | ret.setSpan(new TextAppearanceSpan(context, style), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 42 | return ret; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /appmain/utils/tools/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.utils.tools; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewTreeObserver; 7 | import android.view.inputmethod.InputMethodManager; 8 | import android.widget.EditText; 9 | import android.widget.ScrollView; 10 | 11 | public class ViewUtils { 12 | //加载layout文件并且返回view引用 13 | public static View inflate(Context context, int layID) { 14 | View v = LayoutInflater.from(context).inflate(layID, null); 15 | 16 | return v; 17 | } 18 | 19 | public static void measureUnspecified(View view) { 20 | view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); 21 | } 22 | 23 | // ScrollView自动滑动到底部! 24 | public static void fullScroll(ScrollView scrollView) { 25 | scrollView.getViewTreeObserver() 26 | .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 27 | @Override 28 | public void onGlobalLayout() { 29 | scrollView.post(new Runnable() { 30 | public void run() { 31 | scrollView.fullScroll(View.FOCUS_DOWN); 32 | } 33 | }); 34 | } 35 | }); 36 | } 37 | 38 | //给编辑器请求焦点和虚拟键盘 39 | public static void requestFocusAndShowInputMethod(EditText edt) { 40 | if (edt == null) return; 41 | edt.post(new Runnable() { 42 | @Override 43 | public void run() { 44 | edt.setFocusable(true); 45 | edt.setFocusableInTouchMode(true); 46 | edt.requestFocus(); 47 | InputMethodManager imm = (InputMethodManager) edt.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 48 | if (imm != null) 49 | imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_NOT_ALWAYS); 50 | } 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /appmain/xmodem/AbstractXModem.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.xmodem; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | import com.proxgrind.chameleon.posixio.PosixCom; 8 | import com.proxgrind.chameleon.utils.tools.HexUtil; 9 | 10 | /** 11 | * @author DXL 12 | * 抽象XModem,定义协议的基本特性,通用动作! 13 | */ 14 | public abstract class AbstractXModem { 15 | 16 | protected String LOG_TAG = this.getClass().getSimpleName(); 17 | 18 | // 结束 19 | protected byte mEOT = 0x04; 20 | // 应答 21 | protected byte mACK = 0x06; 22 | // 重传 23 | protected byte mNAK = 0x15; 24 | // 无条件结束 25 | protected byte mCAN = 0x18; 26 | 27 | // 以128字节块的形式传输数据 28 | protected int mBlockSize = 128; 29 | // 最大错误(无应答)包数 30 | protected int mErrorMax = 10; 31 | 32 | // 通信接口,用于读取串口数据 33 | protected PosixCom mCom; 34 | 35 | public AbstractXModem(PosixCom com) { 36 | this.mCom = com; 37 | } 38 | 39 | /** 40 | * @param sources 字节来源,可以是InputStream的任何有效实现! 41 | * @return 传输结果! 42 | */ 43 | public abstract boolean send(InputStream sources) throws IOException; 44 | 45 | /** 46 | * @param target 字节去向,可以是OutputStream的任何有效实现! 47 | * @return 传输结果! 48 | */ 49 | public abstract boolean recv(OutputStream target) throws IOException; 50 | 51 | /** 52 | * 刷新数据,进行剩余字节发送!! 53 | * 54 | * @throws IOException 异常 55 | */ 56 | protected void flush() throws IOException { 57 | mCom.flush(); 58 | } 59 | 60 | /** 61 | * 获取数据,每次在超时值内读取一个字节! 62 | * 63 | * @return 数据 64 | * @throws IOException 异常 65 | */ 66 | protected byte read(int timeout) throws IOException { 67 | byte[] b = new byte[1]; 68 | mCom.read(b, 0, 1, timeout); 69 | return b[0]; 70 | } 71 | 72 | /** 73 | * 发送数据 74 | * 75 | * @param data 数据 76 | * @return 发送成功的字节长度! 77 | * @throws IOException 异常 78 | */ 79 | protected int write(byte data, int timeout) throws IOException { 80 | byte[] b = {data}; 81 | return mCom.write(b, 0, 1, timeout); 82 | } 83 | 84 | /** 85 | * 发送数据 86 | * 87 | * @param dataByte 数据 88 | * @param checkSum 校验和 89 | * @return 发送成功的字节 90 | * @throws IOException 异常 91 | */ 92 | protected int write(byte[] dataByte, byte[] checkSum, int timeout) throws IOException { 93 | return write(HexUtil.bytesMerge(dataByte, checkSum), timeout); 94 | } 95 | 96 | /** 97 | * 发送数据 98 | * 99 | * @param dataByte 数据 100 | * @return 发送成功的字节 101 | * @throws IOException 异常 102 | */ 103 | protected int write(byte[] dataByte, int timeout) throws IOException { 104 | return mCom.write(dataByte, 0, dataByte.length, timeout); 105 | } 106 | 107 | /** 108 | * 取消传输。使停止! 109 | * 110 | * @param timeout 超时值! 111 | */ 112 | public void cancel(int timeout) throws IOException { 113 | write(mCAN, timeout); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /appmain/xmodem/XModem1024.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.xmodem; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | import com.proxgrind.chameleon.posixio.PosixCom; 8 | 9 | /** 10 | * Unfinished 11 | * 12 | * @author DXL 13 | * @version 1.1 14 | * @deprecated 15 | */ 16 | public class XModem1024 extends AbstractXModem { 17 | 18 | //起始头! 19 | private byte STX = 0x02; 20 | 21 | public XModem1024(PosixCom com) { 22 | super(com); 23 | } 24 | 25 | @Override 26 | public boolean send(InputStream sources) throws IOException { 27 | return false; 28 | } 29 | 30 | @Override 31 | public boolean recv(OutputStream target) throws IOException { 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /appmain/xmodem/XModem128.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.xmodem; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | import com.proxgrind.chameleon.posixio.PosixCom; 11 | import com.proxgrind.chameleon.utils.tools.HexUtil; 12 | import com.proxgrind.chameleon.utils.system.LogUtils; 13 | import com.proxgrind.chameleon.utils.system.SystemUtils; 14 | 15 | /** 16 | * @author DXL 17 | * @version 1.1 18 | */ 19 | public class XModem128 extends AbstractXModem { 20 | 21 | // 开始 22 | private byte SOH = 0x01; 23 | // 超时 24 | private final int TIMEOUT = 1000; 25 | 26 | public XModem128(PosixCom com) { 27 | super(com); 28 | } 29 | 30 | final byte calcChecksum(byte[] datas, int count) { 31 | byte checksum = 0; 32 | int pos = 0; 33 | while (count-- != 0) { 34 | checksum += datas[pos++]; 35 | } 36 | return checksum; 37 | } 38 | 39 | @Override 40 | public boolean send(InputStream sources) throws IOException { 41 | // 错误包数 42 | int errorCount; 43 | // 包序号 44 | byte blockNumber = 0x01; 45 | // 读取到缓冲区的字节数量 46 | int nbytes; 47 | // 初始化数据缓冲区 48 | byte[] sector = new byte[mBlockSize]; 49 | 50 | /*if (read(3000) != mNAK) { 51 | LogUtils.d("接收端没有NAK回复发起接收"); 52 | return false; 53 | }*/ 54 | // 读取字节初始化 55 | while ((nbytes = sources.read(sector)) > 0) { 56 | // 如果最后一包数据小于128个字节,以0xff补齐 57 | if (nbytes < mBlockSize) { 58 | for (int i = nbytes; i < mBlockSize; i++) { 59 | sector[i] = (byte) 0x1A; 60 | } 61 | } 62 | // 同一包数据最多发送10次 63 | errorCount = 0; 64 | while (errorCount < mErrorMax) { 65 | // 不分包且一次性发送! 66 | ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 67 | buffer.write(SOH); 68 | buffer.write(blockNumber); 69 | buffer.write((255 - blockNumber)); 70 | buffer.write(sector); 71 | buffer.write(calcChecksum(sector, sector.length)); 72 | mCom.write(buffer.toByteArray(), 0, buffer.size(), TIMEOUT); 73 | flush(); //6、刷新缓冲区,发送数据! 74 | 75 | // 获取应答数据 76 | byte data = read(TIMEOUT); 77 | // 如果收到应答数据则跳出循环,发送下一包数据 78 | // 未收到应答,错误包数+1,继续重发 79 | if (data == mNAK) { 80 | Log.d(LOG_TAG, "NAK已收到,将会无条件重新传输!"); 81 | //重传! 82 | ++errorCount; 83 | } else if (data == mCAN) { 84 | //终止命令! 85 | Log.d(LOG_TAG, "CAN已收到,将会无条件结束发送!"); 86 | return false; 87 | } else if (data == mACK) { 88 | Log.d(LOG_TAG, "ACK已收到,可以进行下一轮发送!"); 89 | break; 90 | } else { 91 | Log.d(LOG_TAG, "未知的值: " + HexUtil.toHexString(data)); 92 | //重传! 93 | ++errorCount; 94 | } 95 | } 96 | // 包序号自增 97 | blockNumber = (byte) ((++blockNumber) % 256); 98 | } 99 | boolean isAck = false; 100 | while (!isAck) { 101 | write(mEOT, TIMEOUT); 102 | isAck = read(TIMEOUT) == mACK; 103 | } 104 | // 接收与发送一个字节,告知结束发送! 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean recv(OutputStream target) throws IOException { 110 | // 错误包数 111 | int errorCount = 0; 112 | // 包序号 113 | byte blocknumber = 0x01; 114 | // 数据 115 | byte data; 116 | // 校验和 117 | int checkSum; 118 | // 初始化数据缓冲区 119 | byte[] sector = new byte[mBlockSize]; 120 | // 握手,发起传输! 121 | write(mNAK, TIMEOUT); 122 | while (true) { 123 | if (errorCount > mErrorMax) { 124 | LogUtils.d("错误重试次数已达上限!"); 125 | return false; 126 | } 127 | // 获取应答数据 128 | data = read(TIMEOUT); 129 | if (data == -1) { 130 | LogUtils.d("收到 -1,可能无数据或者读取超时了。"); 131 | return false; 132 | } 133 | if (data == SOH) { 134 | try { 135 | // 获取包序号 136 | data = read(TIMEOUT); 137 | // 获取包序号的反码 138 | byte _blocknumber = read(TIMEOUT); 139 | //Log.d(LOG_TAG, "包序号: " + data); 140 | //Log.d(LOG_TAG, "包序号的反码: " + _blocknumber); 141 | // 判断包序号是否正确 142 | if (data != blocknumber) { 143 | LogUtils.d("包序号不正常!"); 144 | errorCount++; 145 | continue; 146 | } 147 | // 判断包序号的反码是否正确 148 | if (data + _blocknumber != (byte) 255) { 149 | LogUtils.d("包序号的反码不正常!"); 150 | errorCount++; 151 | continue; 152 | } 153 | // 获取数据 154 | for (int i = 0; i < mBlockSize; i++) { 155 | sector[i] = read(TIMEOUT); 156 | } 157 | //Log.d(LOG_TAG, "获取到的数据: " + HexUtil.toHexString(sector)); 158 | // 获取校验和 159 | checkSum = read(TIMEOUT); 160 | //Log.d(LOG_TAG, "接收到的校验和: " + checkSum); 161 | // 判断校验和是否正确 162 | int crc = SystemUtils.calcChecksum(sector, false); 163 | //Log.d(LOG_TAG, "计算到的校验和: " + crc); 164 | if (crc != checkSum) { 165 | LogUtils.d("包数据的校验不正常!"); 166 | errorCount++; 167 | continue; 168 | } 169 | //Log.d(LOG_TAG, "接收一帧完成!"); 170 | // 发送应答 171 | write(mACK, TIMEOUT); 172 | // 包序号自增 173 | blocknumber++; 174 | // 将数据写入本地 175 | target.write(sector); 176 | // 错误包数归零 177 | errorCount = 0; 178 | } catch (Exception e) { 179 | e.printStackTrace(); 180 | } finally { 181 | // 如果出错发送重传标识 182 | if (errorCount != 0) { 183 | Log.d(LOG_TAG, "错误,将发送重传标志!"); 184 | write(mNAK, TIMEOUT); 185 | } 186 | } 187 | } else if (data == mEOT) { 188 | LogUtils.d("收到0x04 EOT码,结束传输!"); 189 | write(mACK, TIMEOUT); 190 | return true; 191 | } else { 192 | LogUtils.d("未知回复: " + HexUtil.toHexString(data)); 193 | return false; 194 | } 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /appmain/xmodem/XModemUtils.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.xmodem; 2 | 3 | import com.proxgrind.chameleon.posixio.PosixCom; 4 | import com.proxgrind.chameleon.utils.chameleon.ChameleonUtils; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | 10 | public class XModemUtils { 11 | public static byte[] recv128(PosixCom com) { 12 | if (com == null) return new byte[0]; 13 | XModem128 x128 = new XModem128(com); 14 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(64); 15 | try { 16 | ChameleonUtils.autoCRLF = false; 17 | x128.recv(outputStream); 18 | ChameleonUtils.autoCRLF = true; 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | return outputStream.toByteArray(); 23 | } 24 | 25 | public static boolean send128(PosixCom com, byte[] datas) { 26 | if (com == null || datas == null) return false; 27 | XModem128 x128 = new XModem128(com); 28 | ByteArrayInputStream inputStream = new ByteArrayInputStream(datas); 29 | try { 30 | boolean ret; 31 | ChameleonUtils.autoCRLF = false; 32 | ret = x128.send(inputStream); 33 | ChameleonUtils.autoCRLF = true; 34 | return ret; 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/code.rar -------------------------------------------------------------------------------- /packets/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /packets/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 19 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | consumerProguardFiles 'consumer-rules.pro' 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation 'androidx.appcompat:appcompat:1.1.0' 29 | } 30 | -------------------------------------------------------------------------------- /packets/build/generated/source/buildConfig/debug/com/proxgrind/chameleon/packets/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Automatically generated file. DO NOT MODIFY 3 | */ 4 | package com.proxgrind.chameleon.packets; 5 | 6 | public final class BuildConfig { 7 | public static final boolean DEBUG = Boolean.parseBoolean("true"); 8 | public static final String LIBRARY_PACKAGE_NAME = "com.proxgrind.chameleon.packets"; 9 | /** 10 | * @deprecated APPLICATION_ID is misleading in libraries. For the library package name use LIBRARY_PACKAGE_NAME 11 | */ 12 | @Deprecated 13 | public static final String APPLICATION_ID = "com.proxgrind.chameleon.packets"; 14 | public static final String BUILD_TYPE = "debug"; 15 | public static final String FLAVOR = ""; 16 | public static final int VERSION_CODE = 1; 17 | public static final String VERSION_NAME = "1.0"; 18 | } 19 | -------------------------------------------------------------------------------- /packets/build/generated/source/buildConfig/release/com/proxgrind/chameleon/packets/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Automatically generated file. DO NOT MODIFY 3 | */ 4 | package com.proxgrind.chameleon.packets; 5 | 6 | public final class BuildConfig { 7 | public static final boolean DEBUG = false; 8 | public static final String LIBRARY_PACKAGE_NAME = "com.proxgrind.chameleon.packets"; 9 | /** 10 | * @deprecated APPLICATION_ID is misleading in libraries. For the library package name use LIBRARY_PACKAGE_NAME 11 | */ 12 | @Deprecated 13 | public static final String APPLICATION_ID = "com.proxgrind.chameleon.packets"; 14 | public static final String BUILD_TYPE = "release"; 15 | public static final String FLAVOR = ""; 16 | public static final int VERSION_CODE = 1; 17 | public static final String VERSION_NAME = "1.0"; 18 | } 19 | -------------------------------------------------------------------------------- /packets/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /packets/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"AAPT_FRIENDLY_MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"packets-debug.aar","fullName":"debug","baseName":"debug","dirName":""},"path":"AndroidManifest.xml","properties":{"packageId":"com.proxgrind.chameleon.packets","split":""}}] -------------------------------------------------------------------------------- /packets/build/intermediates/aapt_friendly_merged_manifests/release/aapt/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /packets/build/intermediates/aapt_friendly_merged_manifests/release/aapt/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"AAPT_FRIENDLY_MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"packets-release.aar","fullName":"release","baseName":"release","dirName":""},"path":"AndroidManifest.xml","properties":{"packageId":"com.proxgrind.chameleon.packets","split":""}}] -------------------------------------------------------------------------------- /packets/build/intermediates/annotation_processor_list/debug/annotationProcessors.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packets/build/intermediates/annotation_processor_list/release/annotationProcessors.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packets/build/intermediates/compile_library_classes/debug/classes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/compile_library_classes/debug/classes.jar -------------------------------------------------------------------------------- /packets/build/intermediates/compile_library_classes/release/classes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/compile_library_classes/release/classes.jar -------------------------------------------------------------------------------- /packets/build/intermediates/compile_only_not_namespaced_r_class_jar/debug/R.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/compile_only_not_namespaced_r_class_jar/debug/R.jar -------------------------------------------------------------------------------- /packets/build/intermediates/compile_only_not_namespaced_r_class_jar/release/R.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/compile_only_not_namespaced_r_class_jar/release/R.jar -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/debug-mergeNativeLibs/merge-state: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/incremental/debug-mergeNativeLibs/merge-state -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/mergeDebugShaders/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/mergeReleaseShaders/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageDebugAssets/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageDebugResources/compile-file-map.properties: -------------------------------------------------------------------------------- 1 | #Fri May 15 17:05:45 CST 2020 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageDebugResources/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageReleaseAssets/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties: -------------------------------------------------------------------------------- 1 | #Mon May 18 10:37:09 CST 2020 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/packageReleaseResources/merger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packets/build/intermediates/incremental/release-mergeNativeLibs/merge-state: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/incremental/release-mergeNativeLibs/merge-state -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/exceptions/CMDInvalidException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/exceptions/CMDInvalidException.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/exceptions/DataInvalidException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/exceptions/DataInvalidException.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/BuildConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/BuildConfig.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataBean.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataBean.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataHead.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataHead.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets$1.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets$Mode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets$Mode.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/debug/classes/com/proxgrind/chameleon/packets/DataPackets.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/exceptions/CMDInvalidException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/exceptions/CMDInvalidException.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/exceptions/DataInvalidException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/exceptions/DataInvalidException.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/BuildConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/BuildConfig.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataBean.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataBean.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataHead.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataHead.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets$1.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets$Mode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets$Mode.class -------------------------------------------------------------------------------- /packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/javac/release/classes/com/proxgrind/chameleon/packets/DataPackets.class -------------------------------------------------------------------------------- /packets/build/intermediates/library_java_res/debug/res.jar: -------------------------------------------------------------------------------- 1 | PK -------------------------------------------------------------------------------- /packets/build/intermediates/library_java_res/release/res.jar: -------------------------------------------------------------------------------- 1 | PK -------------------------------------------------------------------------------- /packets/build/intermediates/library_manifest/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /packets/build/intermediates/library_manifest/release/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /packets/build/intermediates/local_only_symbol_list/debug/R-def.txt: -------------------------------------------------------------------------------- 1 | R_DEF: Internal format may change without notice 2 | local 3 | -------------------------------------------------------------------------------- /packets/build/intermediates/local_only_symbol_list/release/R-def.txt: -------------------------------------------------------------------------------- 1 | R_DEF: Internal format may change without notice 2 | local 3 | -------------------------------------------------------------------------------- /packets/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 6 | 6 7 | 7 C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 10 | 9 android:targetSdkVersion="29" /> 11 | 9-->C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 12 | 10 13 | 11 14 | -------------------------------------------------------------------------------- /packets/build/intermediates/manifest_merge_blame_file/release/manifest-merger-blame-release-report.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 6 | 6 7 | 7 C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 10 | 9 android:targetSdkVersion="29" /> 11 | 9-->C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 12 | 10 13 | 11 14 | -------------------------------------------------------------------------------- /packets/build/intermediates/merged_manifests/debug/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"packets-debug.aar","fullName":"debug","baseName":"debug","dirName":""},"path":"../../library_manifest/debug/AndroidManifest.xml","properties":{"packageId":"com.proxgrind.chameleon.packets","split":""}}] -------------------------------------------------------------------------------- /packets/build/intermediates/merged_manifests/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"packets-release.aar","fullName":"release","baseName":"release","dirName":""},"path":"../../library_manifest/release/AndroidManifest.xml","properties":{"packageId":"com.proxgrind.chameleon.packets","split":""}}] -------------------------------------------------------------------------------- /packets/build/intermediates/navigation_json/debug/navigation.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packets/build/intermediates/navigation_json/release/navigation.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /packets/build/intermediates/runtime_library_classes/debug/classes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/runtime_library_classes/debug/classes.jar -------------------------------------------------------------------------------- /packets/build/intermediates/runtime_library_classes/release/classes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RfidResearchGroup/ChameleonBLEAPI/56b5310c3e2a6c89d139d2dda6438969a92abb5b/packets/build/intermediates/runtime_library_classes/release/classes.jar -------------------------------------------------------------------------------- /packets/build/outputs/logs/manifest-merger-debug-report.txt: -------------------------------------------------------------------------------- 1 | -- Merging decision tree log --- 2 | manifest 3 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 4 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 5 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 6 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 7 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 8 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 9 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 10 | package 11 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:2:5-46 12 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 13 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 14 | android:versionName 15 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 16 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 17 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 18 | android:versionCode 19 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 20 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 21 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 22 | xmlns:android 23 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:11-69 24 | uses-sdk 25 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml reason: use-sdk injection requested 26 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 27 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 28 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 29 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 30 | android:targetSdkVersion 31 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 32 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 33 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 34 | android:minSdkVersion 35 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 36 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 37 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 38 | -------------------------------------------------------------------------------- /packets/build/outputs/logs/manifest-merger-release-report.txt: -------------------------------------------------------------------------------- 1 | -- Merging decision tree log --- 2 | manifest 3 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 4 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 5 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 6 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 7 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 8 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 9 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 10 | package 11 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:2:5-46 12 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 13 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 14 | android:versionName 15 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 16 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 17 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 18 | android:versionCode 19 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 20 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:1-2:49 21 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 22 | xmlns:android 23 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml:1:11-69 24 | uses-sdk 25 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml reason: use-sdk injection requested 26 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 27 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 28 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 29 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 30 | android:targetSdkVersion 31 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 32 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 33 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 34 | android:minSdkVersion 35 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 36 | ADDED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 37 | INJECTED from C:\Users\tssmcu\AndroidStudioProjects\Chameleon\packets\src\main\AndroidManifest.xml 38 | -------------------------------------------------------------------------------- /packets/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /packets/src/main/java/com/proxgrind/chameleon/exceptions/CMDInvalidException.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.exceptions; 2 | 3 | public class CMDInvalidException 4 | extends RuntimeException { 5 | 6 | public CMDInvalidException(String a) { 7 | super(a); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packets/src/main/java/com/proxgrind/chameleon/exceptions/DataInvalidException.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.exceptions; 2 | 3 | public class DataInvalidException 4 | extends RuntimeException { 5 | 6 | public DataInvalidException(String a) { 7 | super(a); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packets/src/main/java/com/proxgrind/chameleon/packets/DataBean.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.packets; 2 | 3 | public class DataBean { 4 | private DataHead head; 5 | private byte[] source; 6 | 7 | public DataHead getHead() { 8 | return head; 9 | } 10 | 11 | public DataBean setHead(DataHead head) { 12 | this.head = head; 13 | return this; 14 | } 15 | 16 | public byte[] getSource() { 17 | return source; 18 | } 19 | 20 | public DataBean setSource(byte[] source) { 21 | this.source = source; 22 | return this; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packets/src/main/java/com/proxgrind/chameleon/packets/DataHead.java: -------------------------------------------------------------------------------- 1 | package com.proxgrind.chameleon.packets; 2 | 3 | /* 4 | * Data Head! 5 | * */ 6 | public class DataHead { 7 | private byte sign = (byte) DataPackets.SIGN_HEX; // 头部标志 8 | private byte command; // 命令标志 9 | private byte length; // 命令长度 10 | private byte status; // 命令状态 11 | 12 | public byte getSign() { 13 | return sign; 14 | } 15 | 16 | public DataHead setSign(byte sign) { 17 | this.sign = sign; 18 | return this; 19 | } 20 | 21 | public byte getCommand() { 22 | return command; 23 | } 24 | 25 | public DataHead setCommand(byte command) { 26 | this.command = command; 27 | return this; 28 | } 29 | 30 | public byte getLength() { 31 | return length; 32 | } 33 | 34 | public DataHead setLength(byte length) { 35 | this.length = length; 36 | return this; 37 | } 38 | 39 | public byte getStatus() { 40 | return status; 41 | } 42 | 43 | public DataHead setStatus(byte status) { 44 | this.status = status; 45 | return this; 46 | } 47 | 48 | public byte[] getHead() { 49 | return new byte[]{sign, command, length, status}; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "DataHead{" + 55 | "sign=" + sign + 56 | ", command=" + command + 57 | ", length=" + length + 58 | ", status=" + status + 59 | '}'; 60 | } 61 | } 62 | --------------------------------------------------------------------------------