parent
3c32b696c8
commit
55a5e15d48
Binary file not shown.
Binary file not shown.
@ -0,0 +1,25 @@
|
||||
package com.idormy.sms.forwarder.database;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {Config.class}, version = 2, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
private static volatile AppDatabase instance;
|
||||
|
||||
public abstract ConfigDao configDao();
|
||||
|
||||
public static AppDatabase getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (AppDatabase.class) {
|
||||
if (instance == null) {
|
||||
instance = Room.databaseBuilder(context, AppDatabase.class, "sms_forwarder.db").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.idormy.sms.forwarder.database;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
|
||||
public class Config {
|
||||
|
||||
@PrimaryKey
|
||||
@NonNull
|
||||
private String uid;
|
||||
private String name;
|
||||
private String cfg;
|
||||
@Ignore
|
||||
private Boolean connecting;
|
||||
|
||||
@Ignore
|
||||
public Config() {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Config(String cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
public Config(@NonNull String uid, String name, String cfg) {
|
||||
this.uid = uid;
|
||||
this.name = name;
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public Config setUid(@NonNull String uid) {
|
||||
this.uid = uid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Config setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getConnecting() {
|
||||
return connecting;
|
||||
}
|
||||
|
||||
public Config setConnecting(Boolean connecting) {
|
||||
this.connecting = connecting;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCfg() {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
public Config setCfg(String cfg) {
|
||||
this.cfg = cfg;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Config config = (Config) o;
|
||||
return Objects.equals(uid, config.uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Config{" +
|
||||
"uid='" + uid + '\'' +
|
||||
", cfg='" + cfg + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.idormy.sms.forwarder.database;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
@Dao
|
||||
public interface ConfigDao {
|
||||
@Query("SELECT * FROM config")
|
||||
Single<List<Config>> getAll();
|
||||
|
||||
@Query("SELECT * FROM config where uid=:uid")
|
||||
Single<Config> getConfigByUid(String uid);
|
||||
|
||||
@Update
|
||||
Completable update(Config config);
|
||||
|
||||
@Insert
|
||||
Completable insert(Config config);
|
||||
|
||||
@Delete
|
||||
Completable delete(Config config);
|
||||
}
|
@ -1,106 +1,106 @@
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CacheUtil {
|
||||
/**
|
||||
* 获取缓存大小
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 缓存大小
|
||||
*/
|
||||
public static String getTotalCacheSize(Context context) {
|
||||
long cacheSize = getFolderSize(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cacheSize += getFolderSize(context.getExternalCacheDir());
|
||||
}
|
||||
return getFormatSize(cacheSize);
|
||||
}
|
||||
|
||||
/***
|
||||
* 清理所有缓存
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void clearAllCache(Context context) {
|
||||
deleteDir(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
deleteDir(context.getExternalCacheDir());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean deleteDir(File dir) {
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
assert children != null;
|
||||
for (String child : children) {
|
||||
boolean success = deleteDir(new File(dir, child));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert dir != null;
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
// 获取文件
|
||||
//Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
|
||||
//Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
|
||||
public static long getFolderSize(File file) {
|
||||
long size = 0;
|
||||
try {
|
||||
File[] fileList = file.listFiles();
|
||||
assert fileList != null;
|
||||
for (File value : fileList) {
|
||||
// 如果下面还有文件
|
||||
if (value.isDirectory()) {
|
||||
size = size + getFolderSize(value);
|
||||
} else {
|
||||
size = size + value.length();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单位
|
||||
*
|
||||
* @param size 文件大小
|
||||
* @return 结果
|
||||
*/
|
||||
public static String getFormatSize(double size) {
|
||||
double kiloByte = size / 1024;
|
||||
if (kiloByte < 1) {
|
||||
return "0KB";
|
||||
}
|
||||
|
||||
double megaByte = kiloByte / 1024;
|
||||
if (megaByte < 1) {
|
||||
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
|
||||
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
|
||||
}
|
||||
|
||||
double gigaByte = megaByte / 1024;
|
||||
if (gigaByte < 1) {
|
||||
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
|
||||
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
|
||||
}
|
||||
|
||||
double teraBytes = gigaByte / 1024;
|
||||
if (teraBytes < 1) {
|
||||
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
|
||||
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
|
||||
}
|
||||
|
||||
BigDecimal result4 = new BigDecimal(teraBytes);
|
||||
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
|
||||
}
|
||||
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CacheUtils {
|
||||
/**
|
||||
* 获取缓存大小
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 缓存大小
|
||||
*/
|
||||
public static String getTotalCacheSize(Context context) {
|
||||
long cacheSize = getFolderSize(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cacheSize += getFolderSize(context.getExternalCacheDir());
|
||||
}
|
||||
return getFormatSize(cacheSize);
|
||||
}
|
||||
|
||||
/***
|
||||
* 清理所有缓存
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void clearAllCache(Context context) {
|
||||
deleteDir(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
deleteDir(context.getExternalCacheDir());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean deleteDir(File dir) {
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
assert children != null;
|
||||
for (String child : children) {
|
||||
boolean success = deleteDir(new File(dir, child));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert dir != null;
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
// 获取文件
|
||||
//Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
|
||||
//Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
|
||||
public static long getFolderSize(File file) {
|
||||
long size = 0;
|
||||
try {
|
||||
File[] fileList = file.listFiles();
|
||||
assert fileList != null;
|
||||
for (File value : fileList) {
|
||||
// 如果下面还有文件
|
||||
if (value.isDirectory()) {
|
||||
size = size + getFolderSize(value);
|
||||
} else {
|
||||
size = size + value.length();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单位
|
||||
*
|
||||
* @param size 文件大小
|
||||
* @return 结果
|
||||
*/
|
||||
public static String getFormatSize(double size) {
|
||||
double kiloByte = size / 1024;
|
||||
if (kiloByte < 1) {
|
||||
return "0KB";
|
||||
}
|
||||
|
||||
double megaByte = kiloByte / 1024;
|
||||
if (megaByte < 1) {
|
||||
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
|
||||
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
|
||||
}
|
||||
|
||||
double gigaByte = megaByte / 1024;
|
||||
if (gigaByte < 1) {
|
||||
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
|
||||
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
|
||||
}
|
||||
|
||||
double teraBytes = gigaByte / 1024;
|
||||
if (teraBytes < 1) {
|
||||
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
|
||||
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
|
||||
}
|
||||
|
||||
BigDecimal result4 = new BigDecimal(teraBytes);
|
||||
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
|
||||
}
|
||||
|
||||
}
|
@ -1,185 +1,186 @@
|
||||
package com.idormy.sms.forwarder;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hjq.toast.ToastUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告
|
||||
*/
|
||||
public class CrashHandler implements UncaughtExceptionHandler {
|
||||
private static final String TAG = "CrashHandler";
|
||||
//系统默认的UncaughtException处理类
|
||||
private Thread.UncaughtExceptionHandler mDefaultHandler;
|
||||
//CrashHandler实例
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static final CrashHandler INSTANCE = new CrashHandler();
|
||||
//程序的Context对象
|
||||
private Context mContext;
|
||||
//用来存储设备信息和异常信息
|
||||
private final Map<String, String> infos = new HashMap<>();
|
||||
//用于格式化日期,作为日志文件名的一部分
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
private final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
/**
|
||||
* 保证只有一个CrashHandler实例
|
||||
*/
|
||||
private CrashHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CrashHandler实例 ,单例模式
|
||||
*/
|
||||
public static CrashHandler getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public void init(Context context) {
|
||||
mContext = context;
|
||||
//获取系统默认的UncaughtException处理器
|
||||
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
//设置该CrashHandler为程序的默认处理器
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当UncaughtException发生时会转入该函数来处理
|
||||
*/
|
||||
@Override
|
||||
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
|
||||
if (!handleException(ex) && mDefaultHandler != null) {
|
||||
//如果用户没有处理则让系统默认的异常处理器来处理
|
||||
mDefaultHandler.uncaughtException(thread, ex);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "error : ", e);
|
||||
} //退出程序
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成
|
||||
*
|
||||
* @return true:如果处理了该异常信息;否则返回false.
|
||||
*/
|
||||
private boolean handleException(Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
} //使用Toast来显示异常信息
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
ToastUtils.delayedShow(R.string.crash_tip, 3000);
|
||||
Looper.loop();
|
||||
}
|
||||
}.start();
|
||||
//收集设备参数信息
|
||||
collectDeviceInfo(mContext);
|
||||
//保存日志文件
|
||||
saveCrashInfo2File(ex);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集设备参数信息
|
||||
*/
|
||||
public void collectDeviceInfo(Context ctx) {
|
||||
try {
|
||||
PackageManager pm = ctx.getPackageManager();
|
||||
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
|
||||
if (pi != null) {
|
||||
String versionName = pi.versionName == null ? "null" : pi.versionName;
|
||||
String versionCode = pi.versionCode + "";
|
||||
infos.put("versionName", versionName);
|
||||
infos.put("versionCode", versionCode);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "an error occured when collect package info", e);
|
||||
}
|
||||
Field[] fields = Build.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
infos.put(field.getName(), Objects.requireNonNull(field.get(null)).toString());
|
||||
Log.d(TAG, field.getName() + " : " + field.get(null));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "an error occured when collect crash info", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存错误信息到文件中
|
||||
*/
|
||||
@SuppressWarnings({"ResultOfMethodCallIgnored", "UnusedReturnValue"})
|
||||
private String saveCrashInfo2File(Throwable ex) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : infos.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
sb.append(key).append("=").append(value).append("\n");
|
||||
}
|
||||
Writer writer = new StringWriter();
|
||||
PrintWriter printWriter = new PrintWriter(writer);
|
||||
ex.printStackTrace(printWriter);
|
||||
Throwable cause = ex.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(printWriter);
|
||||
cause = cause.getCause();
|
||||
}
|
||||
printWriter.close();
|
||||
String result = writer.toString();
|
||||
sb.append(result);
|
||||
try {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String time = formatter.format(new Date());
|
||||
String fileName = "crash-" + time + "-" + timestamp + ".log";
|
||||
|
||||
String path = mContext.getCacheDir().getPath() + File.separator + "crash" + File.separator;
|
||||
Log.e(TAG, path);
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(path + fileName);
|
||||
fos.write(sb.toString().getBytes());
|
||||
fos.close();
|
||||
|
||||
return fileName;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "an error occured while writing file...", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import com.idormy.sms.forwarder.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告
|
||||
*/
|
||||
public class CrashHandler implements UncaughtExceptionHandler {
|
||||
private static final String TAG = "CrashHandler";
|
||||
//系统默认的UncaughtException处理类
|
||||
private Thread.UncaughtExceptionHandler mDefaultHandler;
|
||||
//CrashHandler实例
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static final CrashHandler INSTANCE = new CrashHandler();
|
||||
//程序的Context对象
|
||||
private Context mContext;
|
||||
//用来存储设备信息和异常信息
|
||||
private final Map<String, String> infos = new HashMap<>();
|
||||
//用于格式化日期,作为日志文件名的一部分
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
private final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
/**
|
||||
* 保证只有一个CrashHandler实例
|
||||
*/
|
||||
private CrashHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CrashHandler实例 ,单例模式
|
||||
*/
|
||||
public static CrashHandler getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public void init(Context context) {
|
||||
mContext = context;
|
||||
//获取系统默认的UncaughtException处理器
|
||||
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
//设置该CrashHandler为程序的默认处理器
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当UncaughtException发生时会转入该函数来处理
|
||||
*/
|
||||
@Override
|
||||
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
|
||||
if (!handleException(ex) && mDefaultHandler != null) {
|
||||
//如果用户没有处理则让系统默认的异常处理器来处理
|
||||
mDefaultHandler.uncaughtException(thread, ex);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "error : ", e);
|
||||
} //退出程序
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成
|
||||
*
|
||||
* @return true:如果处理了该异常信息;否则返回false.
|
||||
*/
|
||||
private boolean handleException(Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
} //使用Toast来显示异常信息
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
ToastUtils.delayedShow(R.string.crash_tip, 3000);
|
||||
Looper.loop();
|
||||
}
|
||||
}.start();
|
||||
//收集设备参数信息
|
||||
collectDeviceInfo(mContext);
|
||||
//保存日志文件
|
||||
saveCrashInfo2File(ex);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集设备参数信息
|
||||
*/
|
||||
public void collectDeviceInfo(Context ctx) {
|
||||
try {
|
||||
PackageManager pm = ctx.getPackageManager();
|
||||
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
|
||||
if (pi != null) {
|
||||
String versionName = pi.versionName == null ? "null" : pi.versionName;
|
||||
String versionCode = pi.versionCode + "";
|
||||
infos.put("versionName", versionName);
|
||||
infos.put("versionCode", versionCode);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "an error occured when collect package info", e);
|
||||
}
|
||||
Field[] fields = Build.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
infos.put(field.getName(), Objects.requireNonNull(field.get(null)).toString());
|
||||
Log.d(TAG, field.getName() + " : " + field.get(null));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "an error occured when collect crash info", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存错误信息到文件中
|
||||
*/
|
||||
@SuppressWarnings({"ResultOfMethodCallIgnored", "UnusedReturnValue"})
|
||||
private String saveCrashInfo2File(Throwable ex) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : infos.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
sb.append(key).append("=").append(value).append("\n");
|
||||
}
|
||||
Writer writer = new StringWriter();
|
||||
PrintWriter printWriter = new PrintWriter(writer);
|
||||
ex.printStackTrace(printWriter);
|
||||
Throwable cause = ex.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(printWriter);
|
||||
cause = cause.getCause();
|
||||
}
|
||||
printWriter.close();
|
||||
String result = writer.toString();
|
||||
sb.append(result);
|
||||
try {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String time = formatter.format(new Date());
|
||||
String fileName = "crash-" + time + "-" + timestamp + ".log";
|
||||
|
||||
String path = mContext.getCacheDir().getPath() + File.separator + "crash" + File.separator;
|
||||
Log.e(TAG, path);
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(path + fileName);
|
||||
fos.write(sb.toString().getBytes());
|
||||
fos.close();
|
||||
|
||||
return fileName;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "an error occured while writing file...", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,72 +1,72 @@
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import com.idormy.sms.forwarder.R;
|
||||
|
||||
public class NetUtil {
|
||||
//没有网络
|
||||
public static final int NETWORK_NONE = 0;
|
||||
//移动网络
|
||||
public static final int NETWORK_MOBILE = 1;
|
||||
//无线网络
|
||||
public static final int NETWORK_WIFI = 2;
|
||||
|
||||
static Boolean hasInit = false;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
static Context context;
|
||||
|
||||
public static void init(Context context1) {
|
||||
//noinspection SynchronizeOnNonFinalField
|
||||
synchronized (hasInit) {
|
||||
if (hasInit) return;
|
||||
hasInit = true;
|
||||
context = context1;
|
||||
}
|
||||
}
|
||||
|
||||
//获取网络启动
|
||||
public static int getNetWorkStatus() {
|
||||
//连接服务 CONNECTIVITY_SERVICE
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
//网络信息 NetworkInfo
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
|
||||
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
|
||||
//判断是否是wifi
|
||||
if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_WIFI)) {
|
||||
//返回无线网络
|
||||
ToastUtils.show(R.string.on_wireless_network);
|
||||
return NETWORK_WIFI;
|
||||
//判断是否移动网络
|
||||
} else if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_MOBILE)) {
|
||||
ToastUtils.show(R.string.on_mobile_network);
|
||||
//返回移动网络
|
||||
return NETWORK_MOBILE;
|
||||
}
|
||||
} else {
|
||||
//没有网络
|
||||
ToastUtils.show(R.string.no_network);
|
||||
return NETWORK_NONE;
|
||||
}
|
||||
//默认返回 没有网络
|
||||
return NETWORK_NONE;
|
||||
}
|
||||
|
||||
public static String getLocalIp(Context context) {
|
||||
if (NETWORK_WIFI != getNetWorkStatus()) return context.getString(R.string.not_connected_wifi);
|
||||
|
||||
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||
int ipAddress = wifiInfo.getIpAddress();
|
||||
if (ipAddress == 0) return context.getString(R.string.failed_to_get_ip);
|
||||
return ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "."
|
||||
+ (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff));
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import com.idormy.sms.forwarder.R;
|
||||
|
||||
public class NetUtils {
|
||||
//没有网络
|
||||
public static final int NETWORK_NONE = 0;
|
||||
//移动网络
|
||||
public static final int NETWORK_MOBILE = 1;
|
||||
//无线网络
|
||||
public static final int NETWORK_WIFI = 2;
|
||||
|
||||
static Boolean hasInit = false;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
static Context context;
|
||||
|
||||
public static void init(Context context1) {
|
||||
//noinspection SynchronizeOnNonFinalField
|
||||
synchronized (hasInit) {
|
||||
if (hasInit) return;
|
||||
hasInit = true;
|
||||
context = context1;
|
||||
}
|
||||
}
|
||||
|
||||
//获取网络启动
|
||||
public static int getNetWorkStatus() {
|
||||
//连接服务 CONNECTIVITY_SERVICE
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
//网络信息 NetworkInfo
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
|
||||
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
|
||||
//判断是否是wifi
|
||||
if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_WIFI)) {
|
||||
//返回无线网络
|
||||
ToastUtils.show(R.string.on_wireless_network);
|
||||
return NETWORK_WIFI;
|
||||
//判断是否移动网络
|
||||
} else if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_MOBILE)) {
|
||||
ToastUtils.show(R.string.on_mobile_network);
|
||||
//返回移动网络
|
||||
return NETWORK_MOBILE;
|
||||
}
|
||||
} else {
|
||||
//没有网络
|
||||
ToastUtils.show(R.string.no_network);
|
||||
return NETWORK_NONE;
|
||||
}
|
||||
//默认返回 没有网络
|
||||
return NETWORK_NONE;
|
||||
}
|
||||
|
||||
public static String getLocalIp(Context context) {
|
||||
if (NETWORK_WIFI != getNetWorkStatus()) return context.getString(R.string.not_connected_wifi);
|
||||
|
||||
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||
int ipAddress = wifiInfo.getIpAddress();
|
||||
if (ipAddress == 0) return context.getString(R.string.failed_to_get_ip);
|
||||
return ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "."
|
||||
+ (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff));
|
||||
}
|
||||
}
|
@ -1,91 +1,91 @@
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.idormy.sms.forwarder.MyApplication;
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SimUtil {
|
||||
private static final String TAG = "SimUtil";
|
||||
|
||||
//获取卡槽信息ID
|
||||
public static int getSimId(Bundle bundle) {
|
||||
int whichSIM = -1;
|
||||
if (bundle == null) {
|
||||
return whichSIM;
|
||||
}
|
||||
|
||||
if (bundle.containsKey("simId")) {
|
||||
whichSIM = bundle.getInt("simId");
|
||||
Log.d(TAG, "simId = " + whichSIM);
|
||||
} else if (bundle.containsKey("com.android.phone.extra.slot")) {
|
||||
whichSIM = bundle.getInt("com.android.phone.extra.slot");
|
||||
Log.d(TAG, "com.android.phone.extra.slot = " + whichSIM);
|
||||
} else {
|
||||
String keyName = "";
|
||||
for (String key : bundle.keySet()) {
|
||||
if (key.contains("sim"))
|
||||
keyName = key;
|
||||
}
|
||||
if (bundle.containsKey(keyName)) {
|
||||
whichSIM = bundle.getInt(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Slot Number " + whichSIM);
|
||||
return whichSIM + 1;
|
||||
}
|
||||
|
||||
//通过SubscriptionId获取卡槽信息ID
|
||||
public static int getSimIdBySubscriptionId(int subscriptionId) {
|
||||
try {
|
||||
Log.d(TAG, MyApplication.SimInfoList.toString());
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, simInfo.toString());
|
||||
if (simInfo.mSubscriptionId == subscriptionId) {
|
||||
return simInfo.mSimSlotIndex + 1;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//通过卡槽ID获取SubscriptionId
|
||||
public static int getSubscriptionIdBySimId(int simId) {
|
||||
try {
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, "mSimSlotIndex = " + simInfo.mSimSlotIndex);
|
||||
if (simInfo.mSimSlotIndex != -1 && simInfo.mSimSlotIndex == simId) {
|
||||
return simInfo.mSubscriptionId;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//获取卡槽备注
|
||||
public static String getSimInfo(int simId) {
|
||||
String res = "";
|
||||
try {
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, String.valueOf(simInfo));
|
||||
if (simInfo.mSimSlotIndex != -1 && simInfo.mSimSlotIndex + 1 == simId) {
|
||||
res = simInfo.mCarrierName + "_" + simInfo.mNumber;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return res.replace("null", "unknown");
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.idormy.sms.forwarder.MyApplication;
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SimUtils {
|
||||
private static final String TAG = "SimUtils";
|
||||
|
||||
//获取卡槽信息ID
|
||||
public static int getSimId(Bundle bundle) {
|
||||
int whichSIM = -1;
|
||||
if (bundle == null) {
|
||||
return whichSIM;
|
||||
}
|
||||
|
||||
if (bundle.containsKey("simId")) {
|
||||
whichSIM = bundle.getInt("simId");
|
||||
Log.d(TAG, "simId = " + whichSIM);
|
||||
} else if (bundle.containsKey("com.android.phone.extra.slot")) {
|
||||
whichSIM = bundle.getInt("com.android.phone.extra.slot");
|
||||
Log.d(TAG, "com.android.phone.extra.slot = " + whichSIM);
|
||||
} else {
|
||||
String keyName = "";
|
||||
for (String key : bundle.keySet()) {
|
||||
if (key.contains("sim"))
|
||||
keyName = key;
|
||||
}
|
||||
if (bundle.containsKey(keyName)) {
|
||||
whichSIM = bundle.getInt(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Slot Number " + whichSIM);
|
||||
return whichSIM + 1;
|
||||
}
|
||||
|
||||
//通过SubscriptionId获取卡槽信息ID
|
||||
public static int getSimIdBySubscriptionId(int subscriptionId) {
|
||||
try {
|
||||
Log.d(TAG, MyApplication.SimInfoList.toString());
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, simInfo.toString());
|
||||
if (simInfo.mSubscriptionId == subscriptionId) {
|
||||
return simInfo.mSimSlotIndex + 1;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//通过卡槽ID获取SubscriptionId
|
||||
public static int getSubscriptionIdBySimId(int simId) {
|
||||
try {
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, "mSimSlotIndex = " + simInfo.mSimSlotIndex);
|
||||
if (simInfo.mSimSlotIndex != -1 && simInfo.mSimSlotIndex == simId) {
|
||||
return simInfo.mSubscriptionId;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//获取卡槽备注
|
||||
public static String getSimInfo(int simId) {
|
||||
String res = "";
|
||||
try {
|
||||
for (PhoneUtils.SimInfo simInfo : MyApplication.SimInfoList) {
|
||||
Log.d(TAG, String.valueOf(simInfo));
|
||||
if (simInfo.mSimSlotIndex != -1 && simInfo.mSimSlotIndex + 1 == simId) {
|
||||
res = simInfo.mCarrierName + "_" + simInfo.mNumber;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getSimExtra Fail: " + e.getMessage());
|
||||
}
|
||||
|
||||
return res.replace("null", "unknown");
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.idormy.sms.forwarder;
|
||||
package com.idormy.sms.forwarder.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -1,3 +1,3 @@
|
||||
#Fri Jul 16 10:33:23 CST 2021
|
||||
versionName=2.4.4
|
||||
versionCode=37
|
||||
versionName=2.5.0
|
||||
versionCode=38
|
||||
|
Loading…
Reference in New Issue