This commit is contained in:
fengjignqi
2026-05-16 16:19:39 +08:00
commit 1b1575eb8a
1632 changed files with 242221 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
public class AppInfoUtil {
public static int packageCode(Context context) {
PackageManager manager = context.getPackageManager();
int code = 0;
try {
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
code = info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return code;
}
public static String getVersionName(Context context) {
PackageManager manager = context.getPackageManager();
String name = "";
try {
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
name = info.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return name;
}
public static long getAppVersionCode(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
return packageInfo.getLongVersionCode();
} else {
//noinspection deprecation
return packageInfo.versionCode;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return -1;
}
}
/**
*
* @return
*/
public static boolean isHuawei() {
return "Huawei".equalsIgnoreCase(Build.MANUFACTURER);
}
}

View File

@@ -0,0 +1,223 @@
package com.ckkj.water.utils;
import android.content.Context;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
public class CalendarJsonGenerator {
// 农历月份名称
private static final String[] LUNAR_MONTHS = {
"正月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "冬月", "腊月"
};
// 农历日期名称
private static final String[] LUNAR_DAYS = {
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"
};
// 农历数据表 (1900-2100)
private static final long[] LUNAR_INFO = {
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0,
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,
0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0
};
public static void generateCalendarFiles(Context context) {
new Thread(() -> {
try {
File solarFile = new File(context.getExternalFilesDir(null), "solar_calendar.json");
File lunarFile = new File(context.getExternalFilesDir(null), "lunar_calendar.json");
generateUnifiedCalendar(solarFile, false);
generateUnifiedCalendar(lunarFile, true);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
private static void generateUnifiedCalendar(File outputFile, boolean isLunar) throws IOException, JSONException {
JSONObject calendarJson = new JSONObject();
Calendar cal = Calendar.getInstance();
// 生成1980-2030年的数据
for (int year = 1980; year <= 2030; year++) {
JSONObject yearObj = new JSONObject();
for (int month = 0; month < 12; month++) {
cal.set(year, month, 1);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
JSONArray monthArray = new JSONArray();
for (int day = 1; day <= daysInMonth; day++) {
JSONObject dayObj = new JSONObject();
if (isLunar) {
// 农历数据
int[] lunar = solarToLunar(year, month + 1, day);
dayObj.put("year", lunar[0]); // 农历年份
dayObj.put("month", getLunarMonthString(lunar[1], lunar[3] == 1)); // 农历月份字符串
dayObj.put("day", getLunarDayString(lunar[2])); // 农历日期字符串
dayObj.put("isLeap", lunar[3] == 1); // 是否闰月
dayObj.put("display", formatLunarDisplay(lunar[0], lunar[1], lunar[2], lunar[3] == 1)); // 完整显示字符串
} else {
// 公历数据
dayObj.put("year", year); // 公历年
dayObj.put("month", String.valueOf(month + 1)); // 公历月份(字符串)
dayObj.put("day", String.valueOf(day)); // 公历日期(字符串)
dayObj.put("isLeap", false); // 公历没有闰月
dayObj.put("display", formatSolarDisplay(year, month + 1, day)); // 完整显示字符串
}
monthArray.put(dayObj);
}
yearObj.put(String.valueOf(month + 1), monthArray);
}
calendarJson.put(String.valueOf(year), yearObj);
}
// 写入文件
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
fos.write(calendarJson.toString(2).getBytes(StandardCharsets.UTF_8));
}
}
// 获取农历月份字符串
private static String getLunarMonthString(int month, boolean isLeap) {
if (month < 1 || month > 12) return "";
return (isLeap ? "" : "") + LUNAR_MONTHS[month - 1];
}
// 获取农历日期字符串
private static String getLunarDayString(int day) {
if (day < 1 || day > 30) return "";
return LUNAR_DAYS[day - 1];
}
// 格式化农历显示
private static String formatLunarDisplay(int year, int month, int day, boolean isLeap) {
return year + "" + getLunarMonthString(month, isLeap) + getLunarDayString(day);
}
// 格式化公历显示
private static String formatSolarDisplay(int year, int month, int day) {
return year + "" + month + "" + day + "";
}
private static int[] solarToLunar(int year, int month, int day) {
int lunarYear, lunarMonth, lunarDay;
boolean isLeap = false;
// 计算与1900年1月31日的时间差
Calendar baseDate = Calendar.getInstance();
baseDate.set(1900, 0, 31);
Calendar targetDate = Calendar.getInstance();
targetDate.set(year, month - 1, day);
long offset = (targetDate.getTimeInMillis() - baseDate.getTimeInMillis()) / 86400000;
// 用农历数据计算年月日
int iYear, daysOfYear = 0;
for (iYear = 1900; iYear < 2100 && offset > 0; iYear++) {
daysOfYear = daysInLunarYear(iYear);
offset -= daysOfYear;
}
if (offset < 0) {
offset += daysOfYear;
iYear--;
}
lunarYear = iYear;
int leapMonth = leapMonth(iYear);
boolean isLeapYear = leapMonth > 0;
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {
// 处理闰月
if (isLeapYear && iMonth == (leapMonth + 1) && !isLeap) {
iMonth--;
isLeap = true;
daysOfMonth = leapDays(lunarYear);
} else {
daysOfMonth = monthDays(lunarYear, iMonth);
}
offset -= daysOfMonth;
// 如果不是闰月或处理完闰月后月份加1
if (!isLeap && isLeapYear && iMonth == (leapMonth + 1)) {
iMonth--;
isLeap = true;
} else {
isLeap = false;
}
}
if (offset == 0 && isLeapYear && iMonth == (leapMonth + 1)) {
if (isLeap) {
isLeap = false;
} else {
isLeap = true;
iMonth--;
}
}
if (offset < 0) {
offset += daysOfMonth;
iMonth--;
}
lunarMonth = iMonth;
lunarDay = (int) (offset + 1);
return new int[]{lunarYear, lunarMonth, lunarDay, isLeap ? 1 : 0};
}
private static int daysInLunarYear(int year) {
int sum = 348; // 12个月*29天=348
for (int i = 0x8000; i > 0x8; i >>= 1) {
if ((LUNAR_INFO[year - 1900] & i) != 0) {
sum++;
}
}
return sum + leapDays(year);
}
private static int leapDays(int year) {
if (leapMonth(year) != 0) {
return (LUNAR_INFO[year - 1900] & 0x10000) != 0 ? 30 : 29;
}
return 0;
}
private static int leapMonth(int year) {
return (int) (LUNAR_INFO[year - 1900] & 0xf);
}
private static int monthDays(int year, int month) {
return (LUNAR_INFO[year - 1900] & (0x10000 >> month)) != 0 ? 30 : 29;
}
}

View File

@@ -0,0 +1,248 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.util.JsonWriter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class CalendarJsonGenerator1 {
// 农历月份名称
private static final String[] LUNAR_MONTHS = {
"正月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "冬月", "腊月"
};
// 农历日期名称
private static final String[] LUNAR_DAYS = {
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"
};
// 农历数据表 (1900-2100)
private static final long[] LUNAR_INFO = {
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0,
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,
0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0
};
public static void generateCalendarFiles(Context context) {
new Thread(() -> {
try {
File solarFile = new File(context.getExternalFilesDir(null), "solar_calendar.json");
File lunarFile = new File(context.getExternalFilesDir(null), "lunar_calendar.json");
generateSolarCalendar(solarFile);
generateLunarCalendar(lunarFile);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
private static void generateSolarCalendar(File outputFile) throws IOException {
try (FileOutputStream fos = new FileOutputStream(outputFile);
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
JsonWriter writer = new JsonWriter(osw)) {
writer.setIndent(" ");
writer.beginObject();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
Calendar cal = Calendar.getInstance();
// 生成1980-2030年的公历
for (int year = 1980; year <= 2030; year++) {
writer.name(String.valueOf(year)).beginObject();
for (int month = 0; month < 12; month++) {
writer.name(String.valueOf(month + 1)).beginArray();
cal.set(year, month, 1);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int day = 1; day <= daysInMonth; day++) {
cal.set(year, month, day);
Date date = cal.getTime();
writer.beginObject();
writer.name("date").value(sdf.format(date));
writer.name("dayOfMonth").value(day);
writer.endObject();
}
writer.endArray();
}
writer.endObject();
}
writer.endObject();
}
}
private static void generateLunarCalendar(File outputFile) throws IOException, JSONException {
JSONObject lunarJson = new JSONObject();
Calendar cal = Calendar.getInstance();
// 生成1980-2030年的农历
for (int year = 1980; year <= 2030; year++) {
JSONObject yearObj = new JSONObject();
for (int month = 0; month < 12; month++) {
cal.set(year, month, 1);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
JSONArray monthArray = new JSONArray();
for (int day = 1; day <= daysInMonth; day++) {
int[] lunar = solarToLunar(year, month + 1, day);
String lunarMonthStr = getLunarMonthString(lunar[1], lunar[3] == 1);
String lunarDayStr = getLunarDayString(lunar[2]);
JSONObject dayObj = new JSONObject();
dayObj.put("solar", String.format(Locale.US, "%04d-%02d-%02d", year, month + 1, day));
dayObj.put("lunarYear", lunar[0]); // 农历年份(数字)
dayObj.put("lunarMonth", lunarMonthStr); // 农历月份(字符串)
dayObj.put("lunarDay", lunarDayStr); // 农历日期(字符串)
dayObj.put("isLeap", lunar[3] == 1); // 是否闰月
monthArray.put(dayObj);
}
yearObj.put(String.valueOf(month + 1), monthArray);
}
lunarJson.put(String.valueOf(year), yearObj);
}
// 写入文件
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
fos.write(lunarJson.toString(2).getBytes(StandardCharsets.UTF_8));
}
}
// 获取农历月份字符串
private static String getLunarMonthString(int month, boolean isLeap) {
if (month < 1 || month > 12) return "";
return (isLeap ? "" : "") + LUNAR_MONTHS[month - 1];
}
// 获取农历日期字符串
private static String getLunarDayString(int day) {
if (day < 1 || day > 30) return "";
return LUNAR_DAYS[day - 1];
}
private static int[] solarToLunar(int year, int month, int day) {
int lunarYear, lunarMonth, lunarDay;
boolean isLeap = false;
// 计算与1900年1月31日的时间差
Calendar baseDate = Calendar.getInstance();
baseDate.set(1900, 0, 31);
Calendar targetDate = Calendar.getInstance();
targetDate.set(year, month - 1, day);
long offset = (targetDate.getTimeInMillis() - baseDate.getTimeInMillis()) / 86400000;
// 用农历数据计算年月日
int iYear, daysOfYear = 0;
for (iYear = 1900; iYear < 2100 && offset > 0; iYear++) {
daysOfYear = daysInLunarYear(iYear);
offset -= daysOfYear;
}
if (offset < 0) {
offset += daysOfYear;
iYear--;
}
lunarYear = iYear;
int leapMonth = leapMonth(iYear);
boolean isLeapYear = leapMonth > 0;
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {
// 处理闰月
if (isLeapYear && iMonth == (leapMonth + 1) && !isLeap) {
iMonth--;
isLeap = true;
daysOfMonth = leapDays(lunarYear);
} else {
daysOfMonth = monthDays(lunarYear, iMonth);
}
offset -= daysOfMonth;
// 如果不是闰月或处理完闰月后月份加1
if (!isLeap && isLeapYear && iMonth == (leapMonth + 1)) {
iMonth--;
isLeap = true;
} else {
isLeap = false;
}
}
if (offset == 0 && isLeapYear && iMonth == (leapMonth + 1)) {
if (isLeap) {
isLeap = false;
} else {
isLeap = true;
iMonth--;
}
}
if (offset < 0) {
offset += daysOfMonth;
iMonth--;
}
lunarMonth = iMonth;
lunarDay = (int) (offset + 1);
return new int[]{lunarYear, lunarMonth, lunarDay, isLeap ? 1 : 0};
}
private static int daysInLunarYear(int year) {
int sum = 348; // 12个月*29天=348
for (int i = 0x8000; i > 0x8; i >>= 1) {
if ((LUNAR_INFO[year - 1900] & i) != 0) {
sum++;
}
}
return sum + leapDays(year);
}
private static int leapDays(int year) {
if (leapMonth(year) != 0) {
return (LUNAR_INFO[year - 1900] & 0x10000) != 0 ? 30 : 29;
}
return 0;
}
private static int leapMonth(int year) {
return (int) (LUNAR_INFO[year - 1900] & 0xf);
}
private static int monthDays(int year, int month) {
return (LUNAR_INFO[year - 1900] & (0x10000 >> month)) != 0 ? 30 : 29;
}
}

View File

@@ -0,0 +1,446 @@
package com.ckkj.water.utils;
import android.annotation.SuppressLint;
import com.ckkj.water.utils.show.FL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
* 日历工具类 Create by “AriaLyy@outlook.com” on 13-7-8.
*/
public class CalendarUtils {
/**
* 完整的日期时间格式
*/
public final static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* 只有日期的格式
*/
public final static String DATE_FORMAT = "yyyy-MM-dd";
/**
* 只有时间的格式
*/
public final static String TIME_FORMAT = "HH:mm:ss";
/**
* 带中文的日期格式(2000年01月01日)
*/
public final static String DATE_FORMAT_WITH_CHINESE = "yyyy年MM月dd日";
/**
* 短时间格式(HH:mm)
*/
public final static String SHORT_TIME_FORMAT = "HH:mm";
private static final String TAG = "CalendarUtils";
/**
* 星期天至星期六
*/
public final static String[] WEEKARRAY =
{ "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY" };
/**
* 私有构造
*/
private CalendarUtils() {
}
/**
* 20:30
*/
public static String getShortTime() {
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(SHORT_TIME_FORMAT);
return sdf.format(c.getTime());
}
/**
* 获取当月的天数
*/
public static int getDayCount() {
Calendar aCalendar = Calendar.getInstance(Locale.CHINA);
aCalendar.set(Calendar.DATE, 1);//把日期设置为当月第一天
aCalendar.roll(Calendar.DATE, -1);//日期回滚一天,也就是最后一天
int sumDay = aCalendar.get(Calendar.DATE);
return sumDay;
}
/**
* 获取本月剩余天数
*/
public static int getRemainDay() {
Calendar aCalendar = Calendar.getInstance(Locale.CHINA);
int day = aCalendar.get(Calendar.DAY_OF_MONTH);
return CalendarUtils.getDayCount() - day + 1;
}
/**
* 把String类型的日期转换成Calendar对象
*
* @param string (日期时间:2000-00-00 00:00:00)
*/
public static Calendar transformStringToCalendar(String string) {
return transformStringToCalendar(string, DATE_TIME_FORMAT);
}
/**
* 通过SimpleDataFormat格式把string转换成Calendar
*
* @param string 日期字符串
* @param format 目标日期格式
*/
public static Calendar transformStringToCalendar(String string, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date date = null;
try {
date = sdf.parse(string);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
/**
* 把日期字符串转换成TimeMillis
*/
public static long transformStringToMillis(String string) {
return transformStringToCalendar(string).getTimeInMillis();
}
/**
* 通过TimeMillis转换成秒钟
*
* @param millis TimeMillis
*/
public static long getSecondWithTimeMillis(long millis) {
return millis / 1000;
}
/**
* 返回两个日期相差的秒
*/
public static long getIntervalInSeconds(Calendar calendar, Calendar targetCalendar) {
return (calendar.getTimeInMillis() - targetCalendar.getTimeInMillis()) / 1000;
}
/**
* 格式化日期
*
* @param string 有效的日期字符
* @param format 格式化的格式
*/
public static String formatWithString(String string, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(transformStringToCalendar(string).getTime());
}
/**
* 格式化日期
*
* @param src 源日期字符
* @param srcFormat 源日期格式
* @param targetFormat 目标日期格式
*/
public static String formatWithString(String src, String srcFormat, String targetFormat) {
SimpleDateFormat sdf = new SimpleDateFormat(srcFormat);
try {
Date date = sdf.parse(src);
SimpleDateFormat targetSdf = new SimpleDateFormat(targetFormat);
return targetSdf.format(date);
} catch (Exception e) {
FL.e(TAG, "src=" + src + " " + srcFormat + " " + targetFormat);
e.printStackTrace();
}
return null;
}
/**
* 格式化成日期时间
*
* @param string 将要被格式化的日期字符串
* @return 格式:(2000-00-00 00:00:00)
*/
public static String formatDateTimeWithString(String string) {
return formatWithString(string, DATE_TIME_FORMAT);
}
/**
* 格式化日期
*
* @param srcDate 源日期字符
* @param srcDateFormat 源日期格式
* @param targetFormat 目标格式
*/
public static String formatDateTimeWithString(String srcDate, String srcDateFormat,
String targetFormat) {
SimpleDateFormat sdf = new SimpleDateFormat(srcDateFormat);
try {
Date date = sdf.parse(srcDate);
SimpleDateFormat parseSdf = new SimpleDateFormat(targetFormat);
return parseSdf.format(date);
} catch (ParseException e) {
FL.e(TAG, "srcDate:"
+ srcDate
+ " srcDateFormat:"
+ srcDateFormat
+ " targetFormat"
+ targetFormat);
e.printStackTrace();
}
return null;
}
/**
* 字符转日期
*/
public static Date StringToDate(String time) {
@SuppressLint("SimpleDateFormat")
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
try {
return format.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
return new Date();
}
/**
* 日期转字符
*/
public static String DateToString(Date time) {
if (time==null){
return "";
}
@SuppressLint("SimpleDateFormat")
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
return format.format(time);
}
/**
* 格式化日期
*
* @param string 将要被格式化的日期字符串
* @return 格式:(2000-00-00)
*/
public static String formatDateWithString(String string) {
return formatWithString(string, DATE_FORMAT);
}
/**
* 格式化日期
*
* @param string 将要被格式化的日期字符串
* @return 格式:(00:00:00)
*/
public static String formatTimeWithString(String string) {
return formatWithString(string, TIME_FORMAT);
}
/**
* 格式化日期
*
* @param string 将要被格式化的日期字符串
* @return 格式:(2000年01月01日)
*/
public static String formatStringToChinese(String string) {
return formatWithString(string, DATE_FORMAT_WITH_CHINESE);
}
/**
* Data日期格式化成String
*
* @param date 将要被格式化的data
* @return 格式:(2000-00-00 00:00:00)
*/
public static String formatDateTimeWithDate(Date date) {
return formatStringWithDate(date, DATE_TIME_FORMAT);
}
/**
* 时间戳格式的数据格式化成需要的格式
*
* @param string 将要被格式化的时间戳
* @return 格式:(2000-00-00 00:00:00)
*/
public static String formatDateTimeWithTime(String string) {
return formatStringWithDate(timeToData(string), DATE_TIME_FORMAT);
}
/**
* 把中文日期2000年01月01日)格式化成标准日期(2000-01-01)
*
* @param data 将要格式化的日期字符串
* @return 格式:(2000-00-00);
*/
public static String formatChineseDataToData(String data) {
data = data.replace("", "-");
data = data.replace("", "-");
data = data.replace("", "");
return data;
}
/**
* 日期格式化成String
*
* @param date 将要格式化的日期字符串
* @return 格式format格式
*/
public static String formatStringWithDate(Date date, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
/**
* 把String类型的时间转换成Calendar
*
* @param time 时间格式00:00:00
*/
public static Calendar transformStringTimeToCalendar(String time) {
Calendar calendar = Calendar.getInstance();
String[] split = time.split(":");
if (split.length > 0) {
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(split[0]));
}
if (split.length > 1) {
calendar.set(Calendar.MINUTE, Integer.parseInt(split[1]));
}
if (split.length > 2) {
calendar.set(Calendar.SECOND, Integer.parseInt(split[2]));
}
return calendar;
}
/**
* 把时间戳:1234567890123,转换成Date对象
*/
public static Date timeToData(String time) {
return new Date(Long.parseLong(time));
}
/**
* 比较两个字符串日期的大小
*
* @return 小于0srcData 小于 tagData;
* 等于0则srcData = tagData;
* 大于0则srcData 大余 tagData
*/
public static int compare(String srcDate, String tagDate) {
return srcDate.compareTo(tagDate);
}
/**
* 返回现在的日期和时间
*
* @return 格式:2000-00-00 00:00:00
*/
public static String getNowDataTime() {
Calendar calendar = Calendar.getInstance();
return formatDateTimeWithDate(calendar.getTime());
}
/**
* 返回当前的日期
*
* @return 格式2000-00-00
*/
public static String getData() {
return getNowDataTime().split(" ")[0];
}
/**
* 返回当前时间
*
* @return 格式00:00:00
*/
public static String getTime() {
return getNowDataTime().split(" ")[1];
}
/**
* 获取当前星期数
*/
public static String getWeekFromCalendar() {
String weekIndex = null;
Calendar c = Calendar.getInstance();
int week = c.get(Calendar.DAY_OF_WEEK);
switch (week) {
case 1:
weekIndex = "SUNDAY";
break;
case 2:
weekIndex = "MONDAY";
break;
case 3:
weekIndex = "TUESDAY";
break;
case 4:
weekIndex = "WEDNESDAY";
break;
case 5:
weekIndex = "THURSDAY";
break;
case 6:
weekIndex = "FRIDAY";
break;
case 7:
weekIndex = "SATURDAY";
break;
}
return weekIndex;
}
//根据秒数转化为时分秒 00:00:00
public static String getTime(int second) {
if (second < 10) {
return "00:0" + second;
}
if (second < 60) {
return "00:" + second;
}
if (second < 3600) {
int minute = second / 60;
second = second - minute * 60;
if (minute < 10) {
if (second < 10) {
return "0" + minute + ":0" + second;
}
return "0" + minute + ":" + second;
}
if (second < 10) {
return minute + ":0" + second;
}
return minute + ":" + second;
}
int hour = second / 3600;
int minute = (second - hour * 3600) / 60;
second = second - hour * 3600 - minute * 60;
if (hour < 10) {
if (minute < 10) {
if (second < 10) {
return "0" + hour + ":0" + minute + ":0" + second;
}
return "0" + hour + ":0" + minute + ":" + second;
}
if (second < 10) {
return "0" + hour + ":" + minute + ":0" + second;
}
return "0" + hour + ":" + minute + ":" + second;
}
if (minute < 10) {
if (second < 10) {
return hour + ":0" + minute + ":0" + second;
}
return hour + ":0" + minute + ":" + second;
}
if (second < 10) {
return hour + ":" + minute + ":0" + second;
}
return hour + ":" + minute + ":" + second;
}
}

View File

@@ -0,0 +1,30 @@
package com.ckkj.water.utils;
import android.util.Log;
public class ClickUtils {
/**
* Android优雅地处理按钮重复点击的几种方法
* add by wangqianzhou
*/
private static long mLastClickTime = 0;
public static final long TIME_INTERVAL = 3000L;
public static boolean onclickTimes() {
long nowTime = System.currentTimeMillis();
if (nowTime - mLastClickTime > TIME_INTERVAL) {
// do something
Log.e("TAGTIME_INTERVAL", "nowTime: " + nowTime);
Log.e("TAGTIME_INTERVAL", "mLastClickTime: " + mLastClickTime);
Log.e("TAGTIME_INTERVAL", nowTime - mLastClickTime + "");
Log.e("TAGTIME_INTERVAL", "onclickTime: " + "11111111111");
mLastClickTime = nowTime;
return true;
} else {
Log.e("TAGTIME_INTERVAL", "onclickTime: " + "11111111111222");
return false;
}
}
}

View File

@@ -0,0 +1,77 @@
package com.ckkj.water.utils;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
/**
* 汉字转换位汉语拼音,英文字符不变
*/
public class Cn2Spell {
public static StringBuffer sb = new StringBuffer();
/**
* 获取汉字字符串的首字母,英文字符不变
* 例如阿飞→af
*/
public static String getPinYinHeadChar(String chines) {
sb.setLength(0);
char[] chars = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < chars.length; i++) {
if (chars[i] > 128) {
try {
sb.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0));
} catch (Exception e) {
e.printStackTrace();
}
} else {
sb.append(chars[i]);
}
}
return sb.toString();
}
/**
* 获取汉字字符串的第一个字母
*/
public static String getPinYinFirstLetter(String str) {
sb.setLength(0);
char c = str.charAt(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
if (pinyinArray != null) {
sb.append(pinyinArray[0].charAt(0));
} else {
sb.append(c);
}
return sb.toString();
}
/**
* 获取汉字字符串的汉语拼音,英文字符不变
*/
public static String getPinYin(String chines) {
sb.setLength(0);
char[] nameChar = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
sb.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]);
} catch (Exception e) {
e.printStackTrace();
}
} else {
sb.append(nameChar[i]);
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,52 @@
package com.ckkj.water.utils;
import android.text.Layout;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.widget.TextView;
public class CustomLinkMovementMethod extends LinkMovementMethod {
private static CustomLinkMovementMethod instance;
public static CustomLinkMovementMethod getInstance() {
if (instance == null) {
instance = new CustomLinkMovementMethod();
}
return instance;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
if (line >= 0 && line < layout.getLineCount()) {
int offset = layout.getOffsetForHorizontal(line, x);
// 判断点击坐标是否在文字区域
float left = layout.getLineLeft(line);
float right = layout.getLineRight(line);
if (x >= left && x <= right) {
ClickableSpan[] clickableSpans = buffer.getSpans(offset, offset, ClickableSpan.class);
if (clickableSpans.length > 0) {
clickableSpans[0].onClick(widget);
return true;
}
}
}
}
return false;
}
}

View File

@@ -0,0 +1,254 @@
package com.ckkj.water.utils;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import com.ckkj.water.utils.show.ToastUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class DownFileUtil {
private DownFileCallback mCallback;
public interface DownFileCallback{
void downSuccess(String msg);
}
public DownFileUtil(Context context,String fileUrl,DownFileCallback callback) {
new Thread(){
@Override
public void run() {
super.run();
String fileName = null;
try {
// 找到最后一个"/"的位置
int lastSlashIndex = fileUrl.lastIndexOf("/");
int firstQuestionIndex = -1;
fileName = "";
if(fileUrl.contains("?")){
firstQuestionIndex = fileUrl.indexOf("?");
fileName = fileUrl.substring(lastSlashIndex + 1,firstQuestionIndex);
}else{
// 截取最后一个"/"之后的内容
fileName = fileUrl.substring(lastSlashIndex + 1);
}
} catch (Exception e) {
}
// 检查 Android 版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// 1. 获取公共下载目录的 URI适用于 Android 10 及以上)
Uri downloadUri = getDownloadDirectoryUri();
// 2. 获取 "ChaoYueCang" 文件夹的路径
Uri folderUri = getFolderUri(downloadUri, "ChaoYueCang");
if (folderUri == null) {
// 文件夹不存在,创建该文件夹
createFolderInDownloads(downloadUri, context,"ChaoYueCang");
}
// 1. 获取 MediaStore 的下载目录 URI
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
// 2. 创建用于保存文件的 ContentValues
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); // 文件名
values.put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(fileName)); // 根据文件扩展名设置 MIME 类型
values.put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/ChaoYueCang"); // 保存到 Downloads 目录
// 3. 使用 resolver 插入文件
Uri fileUri = resolver.insert(collection, values);
if (fileUri == null) {
Log.e("FileDownload", "Failed to create new file in Downloads directory.");
return;
}
File sourceFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/ChaoYueCang/"+ fileName);
String sourceFilePath = sourceFile.getAbsolutePath();
// 4. 打开输出流,将文件内容写入公共 Downloads 目录
try (InputStream inputStream = downloadFileFromUrl(fileUrl);
OutputStream outputStream = resolver.openOutputStream(fileUri)) {
if (outputStream == null) {
Log.e("FileDownload", "Failed to open output stream for file.");
return;
}
byte[] buffer = new byte[8192]; // 缓冲区
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
callback.downSuccess("成功下载至Download文件目录中");
} catch (IOException e) {
Log.e("FileDownload", "Error writing to file", e);
}
} else {
// 1. 获取公共下载目录路径
File downloadsDirectory = new File(Environment.getExternalStorageDirectory(), "Download/ChaoYueCang");
if (!downloadsDirectory.exists()) {
downloadsDirectory.mkdirs(); // 如果目录不存在,创建目录
}
// 2. 创建目标文件路径
File targetFile = new File(downloadsDirectory, fileName);
// 3. 下载文件并保存到公共下载目录
try (InputStream inputStream = downloadFileFromUrl(fileUrl);
OutputStream outputStream = new FileOutputStream(targetFile)) {
byte[] buffer = new byte[4096]; // 缓冲区
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
callback.downSuccess("成功下载至Download文件目录中");
} catch (IOException e) {
Log.e("FileDownload", "Error downloading file", e);
}
}
}
}.start();
}
// 获取文件的 MIME 类型
private String getMimeType(String fileName) {
if (fileName.endsWith(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (fileName.endsWith(".xls")) {
return "application/vnd.ms-excel";
}else if (fileName.endsWith(".doc")) {
return "application/msword";
}else if (fileName.endsWith(".pdf")) {
return "application/pdf";
}else if (fileName.endsWith(".png")) {
return "image/png";
}else if (fileName.endsWith(".jpg")) {
return "image/jpeg";
}else if (fileName.endsWith(".jpeg")) {
return "image/jpeg";
}
return "application/octet-stream"; // 默认 MIME 类型
}
// 从 URL 下载文件并返回输入流
private InputStream downloadFileFromUrl(String fileUrl) throws IOException {
URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000); // 设置连接超时
connection.setReadTimeout(10000); // 设置读取超时
connection.connect();
return new BufferedInputStream(connection.getInputStream());
}
// 获取公共存储的 Downloads 目录 URI适配 Android 10 及以上)
private Uri getDownloadDirectoryUri() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
} else {
return Uri.parse("file://" + Environment.getExternalStorageDirectory() + "/Download");
}
}
// 获取指定文件夹的 URI
private Uri getFolderUri(Uri baseUri, String folderName) {
Uri folderUri = baseUri.buildUpon().appendPath(folderName).build();
File folder = new File(folderUri.getPath());
if (folder.exists()) {
return folderUri;
} else {
return null;
}
}
// 在 Downloads 目录中创建一个新文件夹
private void createFolderInDownloads(Uri baseUri, Context context, String folderName) {
try {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, folderName);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/" + folderName);
ContentResolver resolver = context.getContentResolver();
Uri folderUri = resolver.insert(baseUri, values);
if (folderUri == null) {
} else {
}
} catch (Exception e) {
}
}
public static void downloadImage(Context context, String imageUrl) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(imageUrl)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
// 失败处理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
// 下载失败处理
return;
}
byte[] imageData = response.body().bytes();
// 获取图片文件名
String fileName = "IMG_" + System.currentTimeMillis() + ".jpg";
// 保存到 MediaStore
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/DingDingCar"); // 自定义子目录
values.put(MediaStore.Images.Media.IS_PENDING, 1);
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
Uri item = resolver.insert(collection, values);
if (item != null) {
try (OutputStream out = resolver.openOutputStream(item)) {
out.write(imageData);
}
// 更新状态为可见
values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
resolver.update(item, values, null, null);
ToastUtil.showShort(context,"图片已下载至手机");
}
}
});
}
}

View File

@@ -0,0 +1,168 @@
package com.ckkj.water.utils;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class DownLoadApk {
private static final String CHANNEL_ID = "download_channel"; // 通知通道ID
private Context context;
private NotificationManager notificationManager;
private OkHttpClient client;
private NotificationCompat.Builder notificationBuilder;
private DownLoadCallback mCallBack;
private boolean mIsForceUpdate;
public interface DownLoadCallback{
void updateProgress(long currentProgress,long total );
void downLoadFinish();
}
public void setDownLoadCallback(DownLoadCallback callback){
this.mCallBack = callback;
}
public DownLoadApk(Context context, boolean isForceUpdate) {
this.context = context;
this.mIsForceUpdate = isForceUpdate;
this.client = new OkHttpClient();
this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if(!mIsForceUpdate){
// 创建通知通道Android 8.0及以上版本)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Download", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(channel);
}
}
}
public void startDownload(String url, String fileName, String apkPath) {
new Thread(new Runnable() {
@Override
public void run() {
try {
if(!mIsForceUpdate){
// 创建通知
createNotification(fileName);
}
// 发送请求
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
// 获取输入流
if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
long contentLength = response.body().contentLength();
File outputFile = new File(context.getExternalFilesDir(null), fileName);
String apkLocalPath = outputFile.getAbsolutePath();
OutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[8192];
long downloaded = 0;
int read;
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
downloaded += read;
if(!mIsForceUpdate){
// 更新下载进度
updateNotification(downloaded, contentLength);
}else{
if(mCallBack != null){
mCallBack.updateProgress(downloaded,contentLength);
}
}
}
outputStream.flush();
outputStream.close();
inputStream.close();
if(mCallBack != null){
mCallBack.downLoadFinish();
}
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500); // 延迟 2 秒
startInstall(context,apkLocalPath);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} else {
Log.e("Download", "Download failed: " + response.message());
}
} catch (IOException e) {
e.printStackTrace();
Log.e("Download", "Error downloading file", e);
}
}
}).start();
}
private void createNotification(String fileName) {
notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle("发现新版本")
.setContentText("下载中")
.setProgress(100, 0, false)
.setOngoing(true); // 设置为持续的通知
notificationManager.notify(1, notificationBuilder.build());
}
private void updateNotification(long downloaded, long total) {
int progress = (int) ((downloaded * 100) / total);
notificationBuilder.setProgress(100, progress, false)
.setContentText("下载中: " + progress + "%");
notificationManager.notify(1, notificationBuilder.build());
if(progress == 100){
notificationManager.cancel(1);
}
}
private void onDownloadComplete() {
// 下载完成后更新通知
notificationBuilder.setContentText("下载完成")
.setProgress(0, 0, false)
.setOngoing(false)
.setAutoCancel(true); // 下载完成后自动取消通知
notificationManager.notify(1, notificationBuilder.build());
}
public static void startInstall(Context context, String path) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri cDownloadUri = Uri.parse(path);
if (cDownloadUri != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
File file = new File(cDownloadUri.getPath());
String authority = context.getPackageName() + ".provider";
Uri contentUri = FileProvider.getUriForFile(context, authority, file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
} else {
intent.setDataAndType(cDownloadUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
}
}

View File

@@ -0,0 +1,19 @@
package com.ckkj.water.utils;
import android.content.Context;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-17-2025 周四 16:10
*/
public class Dp2PxUtils {
public static int dp2px(Context context,int dpValue) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * density + 0.5f);
}
}

View File

@@ -0,0 +1,33 @@
package com.ckkj.water.utils;
public class FileNameHelper {
// 从 URL 中提取文件名
public static String getFileNameFromUrl(String url) {
if (url == null || url.isEmpty()) {
return "unknown_file";
}
// 获取最后的路径部分
int lastSlashIndex = url.lastIndexOf('/');
if (lastSlashIndex == -1 || lastSlashIndex == url.length() - 1) {
return "unknown_file";
}
return url.substring(lastSlashIndex + 1); // 提取文件名部分
}
// 从文件名中提取扩展名
public static String getFileExtension(String fileName) {
if (fileName == null || fileName.isEmpty()) {
return "";
}
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
return ""; // 无扩展名
}
return fileName.substring(lastDotIndex + 1); // 提取扩展名
}
}

View File

@@ -0,0 +1,196 @@
package com.ckkj.water.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Locale;
public class IDCardValidate {
private static final String[] ValCodeArr = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };
private static final String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" };
// 身份证的最小出生日期,1900年1月1日
private final static Date MINIMAL_BIRTH_DATE = new Date(-2209017600000L);
private static final String BIRTH_DATE_FORMAT="yyyyMMdd";
private final static int NEW_CARD_NUMBER_LENGTH = 18;
private final static int OLD_CARD_NUMBER_LENGTH = 15;
private final static String LENGTH_ERROR="身份证长度必须为15或者18位";
private final static String NUMBER_ERROR="15位身份证都应该为数字18位身份证都应该前17位应该都为数字";
private final static String DATE_ERROR="身份证日期验证无效!";
private final static String AREA_ERROR="身份证地区编码错误!";
private final static String CHECKCODE_ERROR="身份证最后一位校验码有误!";
//是否需要返回自动补全成的身份证
private static boolean isNeedReturn_AutoCard=false;
/**
*
* @param idcardNumber 需要验证的身份证
* @param isreturn_AutoCard 验证无误后,是否需要返回自动补全身份证
* @return 身份证无误返回传入的身份证号
*/
public static boolean validate_effective(String idcardNumber,boolean isreturn_AutoCard){
isNeedReturn_AutoCard=isreturn_AutoCard;
return validate_effective(idcardNumber);
}
/**
* 身份证校验
* @param idcardNumber 需要验证的身份证
* @return 身份证无误返回传入的身份证号
*/
public static boolean validate_effective(String idcardNumber){
String Ai=idcardNumber.trim();
System.out.println(Ai.length()!=15);
if(Ai.length()==15|Ai.length()==18){
//如果为15位则自动补全到18位
if(Ai.length()==OLD_CARD_NUMBER_LENGTH){
Ai=contertToNewCardNumber(Ai);
}
}else{
//LENGTH_ERROR
return false;
}
// 身份证号的前15,17位必须是阿拉伯数字
for (int i = 0; i < NEW_CARD_NUMBER_LENGTH - 1; i++) {
char ch = Ai.charAt(i);
if( ch < '0' || ch > '9'){return false;}
}
//校验身份证日期信息是否有效 出生日期不能晚于当前时间并且不能早于1900年
try {
Date birthDate =getBirthDate(Ai);
if(null == birthDate){
//DATE_ERROR
return false;
}
if(!birthDate.before(new Date())){
//DATE_ERROR
return false;
}
if(!birthDate.after(MINIMAL_BIRTH_DATE)){
//DATE_ERROR
return false;
}
/**
* 出生日期中的年、月、日必须正确,比如月份范围是[1,12],日期范围是[1,31],还需要校验闰年、大月、小月的情况时,
* 月份和日期相符合
*/
String birthdayPart = getBirthDayPart(Ai);
String realBirthdayPart =createBirthDateParser().format(birthDate);
if(!birthdayPart.equals(realBirthdayPart)){
//DATE_ERROR
return false;
}
} catch (Exception e) {
//DATE_ERROR
return false;
}
//校验地区码是否正确
Hashtable<String, String> h = GetAreaCode();
if (h.get(Ai.substring(0, 2)) == null) {
//AREA_ERROR
return false;
}
//校验身份证最后一位 身份证校验码
if(!calculateVerifyCode(Ai) .equals(String.valueOf(Ai.charAt(NEW_CARD_NUMBER_LENGTH - 1)))){
//CHECKCODE_ERROR
return false;
}
//通过验证则返回true
return true;
}
/**
* 把15位身份证号码转换到18位身份证号码<br>
* 15位身份证号码与18位身份证号码的区别为<br>
* 1、15位身份证号码中"出生年份"字段是2位转换时需要补入"19"表示20世纪<br>
* 2、15位身份证无最后一位校验码。18位身份证中校验码根据根据前17位生成
*
*
* @return
*/
private static String contertToNewCardNumber(String oldCardNumber) {
StringBuilder buf = new StringBuilder(NEW_CARD_NUMBER_LENGTH);
buf.append(oldCardNumber.substring(0, 6));
buf.append("19");
buf.append(oldCardNumber.substring(6));
buf.append(calculateVerifyCode(buf));
return buf.toString();
}
/**计算最后一位校验码 加权值%11
* 1十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 先对前17位数字的权求和
* Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
* 2计算模 Y = mod(S, 11)
* 3通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2
* @param cardNumber
* @return
*/
private static String calculateVerifyCode(CharSequence cardNumber) {
int sum = 0;
for (int i = 0; i < NEW_CARD_NUMBER_LENGTH - 1; i++) {
char ch = cardNumber.charAt(i);
sum += ((int) (ch - '0')) * Integer.parseInt(Wi[i]);
}
return ValCodeArr[sum % 11];
}
/**
* 功能:设置地区编码
*
* @return Hashtable 对象
*/
private static Hashtable<String, String> GetAreaCode() {
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("11", "北京");
hashtable.put("12", "天津");
hashtable.put("13", "河北");
hashtable.put("14", "山西");
hashtable.put("15", "内蒙古");
hashtable.put("21", "辽宁");
hashtable.put("22", "吉林");
hashtable.put("23", "黑龙江");
hashtable.put("31", "上海");
hashtable.put("32", "江苏");
hashtable.put("33", "浙江");
hashtable.put("34", "安徽");
hashtable.put("35", "福建");
hashtable.put("36", "江西");
hashtable.put("37", "山东");
hashtable.put("41", "河南");
hashtable.put("42", "湖北");
hashtable.put("43", "湖南");
hashtable.put("44", "广东");
hashtable.put("45", "广西");
hashtable.put("46", "海南");
hashtable.put("50", "重庆");
hashtable.put("51", "四川");
hashtable.put("52", "贵州");
hashtable.put("53", "云南");
hashtable.put("54", "西藏");
hashtable.put("61", "陕西");
hashtable.put("62", "甘肃");
hashtable.put("63", "青海");
hashtable.put("64", "宁夏");
hashtable.put("65", "新疆");
hashtable.put("71", "台湾");
hashtable.put("81", "香港");
hashtable.put("82", "澳门");
hashtable.put("91", "国外");
return hashtable;
}
private static Date getBirthDate(String idcard) {
Date cacheBirthDate=null;
try {
cacheBirthDate = createBirthDateParser().parse(getBirthDayPart(idcard));
} catch (Exception e) {
throw new RuntimeException("身份证的出生日期无效");
}
return new Date(cacheBirthDate.getTime());
}
private static SimpleDateFormat createBirthDateParser() {
return new SimpleDateFormat(BIRTH_DATE_FORMAT, Locale.CHINA);
}
private static String getBirthDayPart(String idcardnumber) {
return idcardnumber.substring(6, 14);
}
}

View File

@@ -0,0 +1,67 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.text.TextUtils;
import java.io.File;
import top.zibin.luban.CompressionPredicate;
import top.zibin.luban.Luban;
import top.zibin.luban.OnCompressListener;
/**
* 鲁班压缩文件
*/
public class LubanCompressUtil {
private static LubanCompressUtil mInstance;
private Context mContext;
public static LubanCompressUtil getInstance() {
if (mInstance == null) {
if (mInstance == null) {
mInstance = new LubanCompressUtil();
}
}
return mInstance;
}
public interface CompressCallback{
void success(File file);
void fail(String failMsg);
}
public void getCompressFile(Context context,File oldFile,CompressCallback callback){
File compressFile = null;
Luban.with(context)
.load(oldFile) // 原始图片文件
.ignoreBy(100) // 忽略不压缩图片大小
.filter(new CompressionPredicate() {
@Override
public boolean apply(String path) {
return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif"));
}
})
.setCompressListener(new OnCompressListener() {
@Override
public void onStart() {
// 压缩开始前调用
}
@Override
public void onSuccess(File file) {
// 压缩成功后调用
if(callback!= null){
callback.success(file);
}
}
@Override
public void onError(Throwable e) {
// 当压缩过程出现问题时调用
}
}).launch();
}
}

View File

@@ -0,0 +1,100 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.os.Environment;
import com.nlf.calendar.LunarMonth;
import com.nlf.calendar.LunarYear;
import com.ckkj.water.utils.show.ToastUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.*;
import java.util.List;
public class LunarDataGenerator {
public static void generate(Context context) {
try {
JSONArray originArray = readFromAssets(context, "nongli-1.json");
JSONArray finalArray = new JSONArray();
// 添加 18001899 年农历数据
for (int year = 1800; year < 1900; year++) {
finalArray.put(generateYearJson(year));
}
// 添加已有 19002099 数据
for (int i = 0; i < originArray.length(); i++) {
finalArray.put(originArray.getJSONObject(i));
}
// 保存为 json 文件
saveJsonToDownload(context, finalArray.toString(2));
} catch (Exception e) {
e.printStackTrace();
}
}
// 生成单个年份的农历信息
private static JSONObject generateYearJson(int year) {
try {
JSONObject yearObj = new JSONObject();
yearObj.put("year", String.valueOf(year));
JSONArray monthArray = new JSONArray();
List<LunarMonth> lunarMonths = LunarYear.fromYear(year).getMonths();
for (LunarMonth month : lunarMonths) {
// ✅ 只保留该月属于当前年份的月
if (month.getYear() != year) continue;
JSONObject monthObj = new JSONObject();
int realMonth = Math.abs(month.getMonth());
monthObj.put("name", String.valueOf(realMonth));
monthObj.put("isRun", month.isLeap() ? 1 : 0);
monthObj.put("isAllDay", month.getDayCount() == 30 ? 1 : 0);
monthArray.put(monthObj);
}
yearObj.put("month", monthArray);
return yearObj;
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
// 读取 assets 中已有 JSON 文件
private static JSONArray readFromAssets(Context context, String fileName) throws IOException {
InputStream is = context.getAssets().open(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) builder.append(line);
try {
return new JSONArray(builder.toString());
} catch (JSONException e) {
throw new RuntimeException("原始 JSON 文件格式错误: " + e.getMessage(), e);
}
}
// 保存 JSON 文件到 Download 目录
private static void saveJsonToDownload(Context context, String json) {
try {
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (!dir.exists()) dir.mkdirs();
File file = new File(dir, "lunar_1800_2099_002.json");
FileOutputStream fos = new FileOutputStream(file);
fos.write(json.getBytes());
fos.close();
ToastUtil.showShort(context, "✅ 保存成功:" + file.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,34 @@
package com.ckkj.water.utils;
public class NicknameValidator {
/**
* 校验昵称是否合法
*
* @param nickname 用户输入的昵称
* @return 合法返回 true不合法返回 false
*/
public static boolean isValidNickname(String nickname) {
if (nickname == null) {
return false;
}
// nickname = nickname.trim(); // 先去掉两端空格
// 长度限制2-20个字符
int length = nickname.length();
if (length < 2 || length > 20) {
return false;
}
// 正则规则
String pattern = "^[\\u4e00-\\u9fa5_a-zA-Z0-9]+$";
// 只允许:中文、英文、数字、下划线
if (!nickname.matches(pattern)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,139 @@
package com.ckkj.water.utils;
import android.os.Environment;
import android.text.TextUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Created by win7 on 2018/10/24.
*/
public class OSUtil {
//MIUI标识
private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
//EMUI标识
private static final String KEY_EMUI_VERSION_CODE = "ro.build.version.emui";
private static final String KEY_EMUI_API_LEVEL = "ro.build.hw_emui_api_level";
private static final String KEY_EMUI_CONFIG_HW_SYS_VERSION = "ro.confg.hw_systemversion";
//Flyme标识
private static final String KEY_FLYME_ID_FALG_KEY = "ro.build.display.id";
private static final String KEY_FLYME_ID_FALG_VALUE_KEYWORD = "Flyme";
private static final String KEY_FLYME_ICON_FALG = "persist.sys.use.flyme.icon";
private static final String KEY_FLYME_SETUP_FALG = "ro.meizu.setupwizard.flyme";
private static final String KEY_FLYME_PUBLISH_FALG = "ro.flyme.published";
/**
* 是否是Flyme系统 * @return
*/
public static boolean isFlyme() {
if (isPropertiesExist(KEY_FLYME_ICON_FALG, KEY_FLYME_SETUP_FALG, KEY_FLYME_PUBLISH_FALG)) {
return true;
}
try {
BuildProperties buildProperties = BuildProperties.newInstance();
if (buildProperties.containsKey(KEY_FLYME_ID_FALG_KEY)) {
String romName = buildProperties.getProperty(KEY_FLYME_ID_FALG_KEY);
if (!TextUtils.isEmpty(romName) && romName.contains(KEY_FLYME_ID_FALG_VALUE_KEYWORD)) {
return true;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* 是否是EMUI系统 * @return
*/
public static boolean isEMUI() {
return isPropertiesExist(KEY_EMUI_VERSION_CODE, KEY_EMUI_API_LEVEL, KEY_EMUI_CONFIG_HW_SYS_VERSION);
}
/**
* 是否是MIUI系统 * @return
*/
public static boolean isMIUI() {
return isPropertiesExist(KEY_MIUI_VERSION_CODE, KEY_MIUI_VERSION_NAME, KEY_MIUI_INTERNAL_STORAGE);
}
private static boolean isPropertiesExist(String... keys) {
if (keys == null || keys.length == 0) {
return false;
}
try {
BuildProperties properties = BuildProperties.newInstance();
for (String key : keys) {
String value = properties.getProperty(key);
if (value != null) return true;
}
return false;
} catch (IOException e) {
return false;
}
}
private static final class BuildProperties {
private final Properties properties;
private BuildProperties() throws IOException {
properties = new Properties();
// 读取系统配置信息build.prop类
properties.load(new FileInputStream(new File(Environment.getRootDirectory(), "build" + ".prop")));
}
public boolean containsKey(final Object key) {
return properties.containsKey(key);
}
public boolean containsValue(final Object value) {
return properties.containsValue(value);
}
public Set<Map.Entry<Object, Object>> entrySet() {
return properties.entrySet();
}
public String getProperty(final String name) {
return properties.getProperty(name);
}
public String getProperty(final String name, final String defaultValue) {
return properties.getProperty(name, defaultValue);
}
public boolean isEmpty() {
return properties.isEmpty();
}
public Enumeration<Object> keys() {
return properties.keys();
}
public Set<Object> keySet() {
return properties.keySet();
}
public int size() {
return properties.size();
}
public Collection<Object> values() {
return properties.values();
}
public static BuildProperties newInstance() throws IOException {
return new BuildProperties();
}
}
}

View File

@@ -0,0 +1,100 @@
package com.ckkj.water.utils;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class OfficePreviewUtil {
public static void downloadFile(String fileUrl, File destinationFile, DownloadCallback callback) {
new Thread(() -> {
try {
URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
callback.onError("Failed to download file: " + connection.getResponseCode());
return;
}
InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(destinationFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
callback.onSuccess(destinationFile);
} catch (Exception e) {
callback.onError(e.getMessage());
}
}).start();
}
public interface DownloadCallback {
void onSuccess(File file);
void onError(String error);
}
public static void openWithWps(Activity context, File file) {
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
// 转换文件 URI
Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
// 设置文件路径及 MIME 类型
// Uri fileUri = Uri.fromFile(file);
String mimeType = getMimeType(file.getPath());
intent.setDataAndType(fileUri, mimeType);
// 设置 WPS 专属参数
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 授予读权限
intent.putExtra("packageName", "cn.wps.moffice_eng"); // WPS 国际版包名
intent.putExtra("openMode", "normal"); // 打开模式:只读
intent.putExtra("sendCloseBroad", true); // 文件关闭时发送广播
intent.putExtra("thirdPackage", context.getPackageName()); // 第三方应用包名
// 启动 WPS App
context.startActivity(intent);
} catch (Exception e) {
context.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "无法打开文件,请确保已安装 WPS Office", Toast.LENGTH_SHORT).show();
}
});
}
}
// 获取文件 MIME 类型
private static String getMimeType(String filePath) {
if (filePath.endsWith(".doc") || filePath.endsWith(".docx")) {
return "application/msword";
} else if (filePath.endsWith(".xls") || filePath.endsWith(".xlsx")) {
return "application/vnd.ms-excel";
} else if (filePath.endsWith(".ppt") || filePath.endsWith(".pptx")) {
return "application/vnd.ms-powerpoint";
} else if (filePath.endsWith(".pdf")) {
return "application/pdf";
} else {
return "*/*";
}
}
}

View File

@@ -0,0 +1,50 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.ckkj.water.custom.view.PhotoViewActivity;
public class PreviewFileUtil {
/**
* 预览文件
* @param suffix
* @param fileUrl
*/
public static void previewFiles(Context mContext,String suffix, String fileUrl) {
if(!TextUtils.isEmpty(suffix)){
if(suffix.contains(".jpg") || suffix.contains(".jpeg") || suffix.contains(".png")){
Intent intent = new Intent(mContext, PhotoViewActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("img_url", fileUrl);
bundle.putInt("img_item", 0);
intent.putExtras(bundle);
mContext.startActivity(intent);
}
// else if(suffix.equals("doc")
// || suffix.equals("docx")){
// Intent intent = new Intent(mContext, FileWebActivity.class);
// Bundle bundle = new Bundle();
// bundle.putString("file_url",fileUrl);
// intent.putExtras(bundle);
// mContext.startActivity(intent);
// }else if(suffix.equals("xlsx")
// || suffix.equals("xltx")
// || suffix.equals("xls")){
// Intent intent = new Intent(mContext,FileWebActivity.class);
// Bundle bundle = new Bundle();
// bundle.putString("file_url",fileUrl);
// intent.putExtras(bundle);
// mContext.startActivity(intent);
// }else if(suffix.equals("pdf")){
// Intent intent = new Intent(mContext, PDFWebActivity.class);
// Bundle bundle = new Bundle();
// bundle.putString("file_url",fileUrl);
// intent.putExtras(bundle);
// mContext.startActivity(intent);
// }
}
}
}

View File

@@ -0,0 +1,26 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import androidx.annotation.NonNull;
import pub.devrel.easypermissions.EasyPermissions;
public class StorageUtils {
// 检查是否拥有 MANAGE_EXTERNAL_STORAGE 权限
public static boolean hasManageExternalStoragePermission(Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
return EasyPermissions.hasPermissions(context, "android.permission.MANAGE_EXTERNAL_STORAGE");
}
return false;
}
// 引导用户前往设置页面以授予 MANAGE_EXTERNAL_STORAGE 权限
public static void requestManageExternalStoragePermission(@NonNull Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
context.startActivity(intent);
}
}
}

View File

@@ -0,0 +1,54 @@
package com.ckkj.water.utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class TrueSolarTimeCalculator {
/**
* 计算真太阳时
* @param year 出生年
* @param month 出生月 (1-12)
* @param day 出生日
* @param hour 出生时 (0-23)
* @param minute 出生分 (0-59)
* @param longitude 当地经度(东经为正,西经为负)
* @param timeZoneStandardLongitude 时区标准经度如东八区为120.0
* @return 真太阳时的小时和分钟数组 [小时, 分钟]
*/
public static String calculateTrueSolarTime(
int year, int month, int day,
int hour, int minute,
double longitude, double timeZoneStandardLongitude) {
// 1. 创建Calendar实例并设置日期和时间
Calendar calendar = Calendar.getInstance();
calendar.set(year, month - 1, day, hour, minute, 0);
calendar.set(Calendar.MILLISECOND, 0);
// 2. 计算年内天数1月1日为第1天
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
// 3. 计算日行差时差EoT单位分钟
double B = 360.0 * (dayOfYear - 81) / 365; // 日角
double B_rad = Math.toRadians(B);
double eot = 9.87 * Math.sin(2 * B_rad)
- 7.53 * Math.cos(B_rad)
- 1.5 * Math.sin(B_rad);
// 4. 计算经度时差(单位:分钟)
double longitudeTimeDiff = (longitude - timeZoneStandardLongitude) * 4;
// 5. 计算总调整分钟数(经度时差 + 日行差)
double totalAdjustment = longitudeTimeDiff + eot;
// 6. 应用调整(四舍五入到最近的分钟)
int adjustmentMinutes = (int) Math.round(totalAdjustment);
calendar.add(Calendar.MINUTE, adjustmentMinutes);
// 7. 格式化为"yyyy-MM-dd HH:mm"字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
return sdf.format(calendar.getTime());
}
}

View File

@@ -0,0 +1,135 @@
package com.ckkj.water.utils;
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import androidx.core.app.NotificationCompat;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class UtilApp {
private static final String CHANNEL_ID = "download_channel";
private static final int NOTIFICATION_ID = 1;
/**
* @param downloadUrl
* @param savePath
* @param fileName
* @下载APK新版本
*/
public static void downloadApp(Context context, final String downloadUrl, final String savePath, String fileName) {
createNotificationChannel(context);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle("星语明灯")
.setContentText("版本更新中")
.setPriority(NotificationCompat.PRIORITY_LOW)
.setProgress(100, 0, false);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
new Thread() {
public void run() {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileName);//记得加扩展名
file.getParentFile().mkdir();
try {
file.createNewFile();
URL url2 = new URL(downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url2.openConnection();
conn.connect();
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
// 获取文件大小
int fileLength = conn.getContentLength();
InputStream ips = conn.getInputStream();
FileOutputStream fops = new FileOutputStream(file);
byte[] data = new byte[4096];
long total = 0;
int count = 0;
byte[] buf = new byte[1024];
int read = ips.read(buf);
while (read != -1) {
total += count;
fops.write(buf, 0, read);
fops.flush();
read = ips.read(buf);
// 更新通知进度
if (fileLength > 0) {
int progress = (int) (total * 100 / fileLength);
notificationBuilder.setProgress(100, progress, false);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
}
fops.close();
ips.close();
conn.disconnect();
notificationBuilder
.setContentText("下载完成")
.setProgress(0, 0, false)
.setSmallIcon(android.R.drawable.stat_sys_download_done);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
} catch (Exception e) {
String msg = e.getMessage();
int a = 0;
}
}
}.start();
}
// 创建通知通道
private static void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"Download Notifications",
NotificationManager.IMPORTANCE_LOW
);
channel.setDescription("Shows download progress");
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
}
/**
* 安装新的Apk
* @param activity
* @param apkPath 安装的apk路径
*/
public static void installNewApk(Activity activity, String apkPath) {
File apkfile = new File(apkPath);
if (!apkfile.exists()) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//兼容android7.0以上版本
Uri uri = Uri.fromFile(apkfile);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//通过FileProvider创建一个content类型的Uri
uri = FileProvider.getUriForFile(activity, "com.zuanuniverse.universe.fileprovider", apkfile);
// 给目标应用一个临时授权
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
intent.setDataAndType(uri, "application/vnd.android.package-archive");
activity.startActivity(intent);
}
}

View File

@@ -0,0 +1,56 @@
package com.ckkj.water.utils;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-18-2025 周五 11:12
*/
public class ViewShowOrHideAnimate {
public static void showOptionsLayout(View view) {
if (view.getHeight() == 0) {
// View还没测量好post到下一帧去执行
view.post(new Runnable() {
@Override
public void run() {
startShowAnim(view);
}
});
} else {
startShowAnim(view);
}
}
public static void startShowAnim(View view) {
view.setVisibility(View.VISIBLE);
view.setAlpha(0f);
view.setTranslationY(100); // 100px下移初始
view.animate()
.translationY(0)
.setDuration(300)
.setInterpolator(new DecelerateInterpolator()) // 出现时慢慢减速
.start();
}
public static void hideOptionsLayout(View view) {
view.animate()
.translationY(100) // 往下移
.setDuration(300)
.setInterpolator(new AccelerateInterpolator()) // 消失时加速离开
.withEndAction(new Runnable() {
@Override
public void run() {
view.setVisibility(View.GONE);
}
})
.start();
}
}

View File

@@ -0,0 +1,18 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.widget.ImageView;
import com.ckkj.water.R;
public class WeatherIconUtil {
public static void loadWeatherIcon(Context context, ImageView imageView, String code) {
String iconName = "icon_hf_" + code;
int resId = context.getResources().getIdentifier(iconName, "mipmap", context.getPackageName());
if (resId != 0) {
imageView.setImageResource(resId);
} else {
imageView.setImageResource(R.mipmap.icon_hf_100); // 默认图标
}
}
}

View File

@@ -0,0 +1,171 @@
package com.ckkj.water.utils;
import android.content.Context;
import android.util.Log;
import com.ckkj.water.fate.entity.CityDataEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/8/11
* @description 城市信息JSON处理工具类
*/
public class YfjJsonHadnlerUtil {
private static final String TAG = "YfjJsonHadnlerUtil";
private static final String CITY_INFO_FILE = "yfj_city_info.json";
private static JSONObject cityInfoJson = null;
/**
* 初始化城市信息数据
* @param context 上下文
*/
public static void initCityInfo(Context context) {
if (cityInfoJson == null) {
cityInfoJson = loadCityInfoFromAssets(context);
}
}
/**
* 从assets文件夹加载城市信息JSON文件
* @param context 上下文
* @return JSONObject 城市信息数据
*/
private static JSONObject loadCityInfoFromAssets(Context context) {
try {
InputStream inputStream = context.getAssets().open(CITY_INFO_FILE);
int size = inputStream.available();
byte[] buffer = new byte[size];
inputStream.read(buffer);
inputStream.close();
String jsonString = new String(buffer, StandardCharsets.UTF_8);
return new JSONObject(jsonString);
} catch (IOException | JSONException e) {
Log.e(TAG, "加载城市信息文件失败: " + e.getMessage());
return null;
}
}
/**
* 根据城市名称查找匹配的城市信息
* @param cityEntity 城市名称,如"济宁市"、"北京市"、"XX地区"
* @return 匹配的城市名称,如果找不到则返回空字符串
*/
public static String findCityByName(CityDataEntity cityEntity) {
String cityResult = "";
if (cityInfoJson == null) {
Log.e(TAG, "城市信息未初始化请先调用initCityInfo方法");
return "";
}
if (cityEntity == null || cityEntity.getCityName().trim().isEmpty()) {
return "";
}
try {
// 遍历所有省份/直辖市
JSONArray provinceNames = cityInfoJson.names();
if (provinceNames != null) {
for (int i = 0; i < provinceNames.length(); i++) {
String provinceName = provinceNames.getString(i);
// 检查省份名称是否包含城市名称
if (cityEntity.getCityName().contains(provinceName) || provinceName.contains(cityEntity.getCityName())) {
String proName = provinceName.replace("","");
return proName;
}else if(cityEntity.getCityType().equals("特别行政区")){
}
if(cityEntity.getProvinceName().equals(provinceName)){
// 获取该省份下的城市列表
JSONArray cityList = cityInfoJson.getJSONArray(provinceName);
if (cityList != null) {
for (int j = 0; j < cityList.length(); j++) {
String city = cityList.getString(j);
// 检查城市名称是否包含城市名称参数,或者城市名称参数是否包含城市名称
if ((cityEntity.getCityName().contains(city) || city.contains(cityEntity.getCityName()))
&& cityEntity.getProvinceName().equals(provinceName)) {
cityResult = city;
return cityResult;
}else{
cityResult = cityEntity.getCapitalCity();
}
}
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, "解析城市信息失败: " + e.getMessage());
}
return cityResult;
}
/**
* 获取所有省份名称
* @return 省份名称列表
*/
public static List<String> getAllProvinces() {
List<String> provinces = new ArrayList<>();
if (cityInfoJson == null) {
return provinces;
}
try {
JSONArray provinceNames = cityInfoJson.names();
if (provinceNames != null) {
for (int i = 0; i < provinceNames.length(); i++) {
provinces.add(provinceNames.getString(i));
}
}
} catch (JSONException e) {
Log.e(TAG, "获取省份列表失败: " + e.getMessage());
}
return provinces;
}
/**
* 根据省份名称获取该省份下的城市列表
* @param provinceName 省份名称
* @return 城市列表
*/
public static List<String> getCitiesByProvince(String provinceName) {
List<String> cities = new ArrayList<>();
if (cityInfoJson == null || provinceName == null || provinceName.trim().isEmpty()) {
return cities;
}
try {
if (cityInfoJson.has(provinceName)) {
JSONArray cityList = cityInfoJson.getJSONArray(provinceName);
if (cityList != null) {
for (int i = 0; i < cityList.length(); i++) {
cities.add(cityList.getString(i));
}
}
}
} catch (JSONException e) {
Log.e(TAG, "获取城市列表失败: " + e.getMessage());
}
return cities;
}
}

View File

@@ -0,0 +1,29 @@
package com.ckkj.water.utils.click;
import android.graphics.Rect;
import android.view.TouchDelegate;
import android.view.View;
/**
* @author FengJingQi
* @date 2025/3/20 15:12
*/
public class ClickUtil {
public static void addClickPart(View view, int size) {
//增加按钮的点击区域
View parentView = (View) view.getParent(); // 获取父视图
parentView.post(() -> {
Rect delegateArea = new Rect();
view.getHitRect(delegateArea); // 获取按钮的初始点击区域
// 扩展点击区域(上下左右各增加 50 像素)
delegateArea.top -= size;
delegateArea.bottom += size;
delegateArea.left -= size;
delegateArea.right += size;
TouchDelegate touchDelegate = new TouchDelegate(delegateArea, view);
if (View.class.isInstance(parentView)) {
((View) parentView).setTouchDelegate(touchDelegate);
}
});
}
}

View File

@@ -0,0 +1,44 @@
package com.ckkj.water.utils.click;
import android.content.Context;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
public class HapticUtil {
private static long lastVibrateTime = 0;
private static final long VIBRATE_INTERVAL_MS = 50; // 最小震动间隔
public static void vibrate(Context context, long durationMillis) {
if (context == null) return;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12 及以上
VibratorManager vibratorManager = (VibratorManager) context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE);
if (vibratorManager != null) {
Vibrator vibrator = vibratorManager.getDefaultVibrator();
vibrator.vibrate(VibrationEffect.createOneShot(durationMillis, VibrationEffect.DEFAULT_AMPLITUDE));
}
} else {
// 旧版本
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null && vibrator.hasVibrator()) {
vibrator.vibrate(VibrationEffect.createOneShot(durationMillis, VibrationEffect.DEFAULT_AMPLITUDE));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void vibrateOnScroll(Context context) {
long now = System.currentTimeMillis();
if (now - lastVibrateTime >= VIBRATE_INTERVAL_MS) {
lastVibrateTime = now;
HapticUtil.vibrate(context, 10); // 震动 10ms
}
}
}

View File

@@ -0,0 +1,64 @@
package com.ckkj.water.utils.color;
public class FateDataUtil {
/**
* 根据分数返回对应的颜色值int 类型,适用于 Android
* @param score 分数0-100
* @return 对应颜色的 int 值
*/
public static int getScoreColor(int score) {
if (score >= 90 && score <= 100) {
return parseColor("#6BB96F"); // 绿色
} else if (score >= 80 && score <= 89) {
return parseColor("#8BC34A"); // 浅绿
} else if (score >= 70 && score <= 79) {
return parseColor("#FFC107"); // 黄色
} else if (score >= 60 && score <= 69) {
return parseColor("#FF9800"); // 橙色
} else {
return parseColor("#FF5722"); // 红色
}
}
/**
* 将十六进制颜色字符串转换为 int 类型的颜色
* @param colorStr 类似 "#RRGGBB"
* @return 颜色的 int 值
*/
private static int parseColor(String colorStr) {
return android.graphics.Color.parseColor(colorStr);
}
/**
* 根据星座名称或符号返回所属的星象类型
* @param constellation 星座字符串,例如 "双鱼座" 或 "♓"
* @return 返回对应的星象类型(如:火象星座、水象星座等)
*/
public static String getConstellationType(String constellation) {
if (constellation == null || constellation.isEmpty()) {
return "星座";
}
if (constellation.contains("双鱼") || constellation.contains("")) {
return "水象星座";
} else if (constellation.contains("白羊") || constellation.contains("") ||
constellation.contains("狮子") || constellation.contains("") ||
constellation.contains("射手") || constellation.contains("")) {
return "火象星座";
} else if (constellation.contains("金牛") || constellation.contains("") ||
constellation.contains("处女") || constellation.contains("") ||
constellation.contains("摩羯") || constellation.contains("")) {
return "土象星座";
} else if (constellation.contains("双子") || constellation.contains("") ||
constellation.contains("天秤") || constellation.contains("") ||
constellation.contains("水瓶") || constellation.contains("")) {
return "风象星座";
} else if (constellation.contains("巨蟹") || constellation.contains("") ||
constellation.contains("天蝎") || constellation.contains("")) {
return "水象星座";
}
return "星座";
}
}

View File

@@ -0,0 +1,66 @@
package com.ckkj.water.utils.dataUtil;
import java.math.BigDecimal;
/**
* 小数计算
*/
public class DoubleTrans {
public static String doubleTrans(double d){
if(Math.round(d)-d==0){
return String.valueOf((long)d);
}
return String.valueOf(d);
}
/**
* 保留两位小数,并四舍五入
*/
public static double fromatDoubleTwo(double Num) {
BigDecimal bg = new BigDecimal(String.valueOf(Num));
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return f1;
}
public static String fromatDoubleTwoStr(String Num) {
BigDecimal bg = new BigDecimal(Num);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return String.format("%.2f", f1);
}
/**
* 保留两位小数,并四舍五入
*/
public static String fromatDoubleTwoStr(double Num) {
BigDecimal bg = new BigDecimal(Num);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return String.format("%.2f", f1);
}
/**
* 保留两位小数,并四舍五入
*/
public static String fromatDoubleTwoStr(BigDecimal Num) {
double f1 = Num.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return String.format("%.2f", f1);
}
public static String getCountVipPrice(String marketPrice,double userDiscount){
BigDecimal bgMark = new BigDecimal(marketPrice);
BigDecimal bgDis = new BigDecimal(String.valueOf(userDiscount));
BigDecimal bgVipPirce = bgMark.multiply(bgDis);
String countPriceStr = fromatDoubleTwoStr(bgVipPirce);
// double doublePrice = Double.parseDouble(marketPrice);
// double vipPrice = doublePrice * userDiscount;
// String countPriceStr = fromatDoubleTwoStr(fromatDoubleTwo(vipPrice));
return countPriceStr;
}
public static String getCountVipPriceInt(String marketPrice,int userDiscount){
double doublePrice = Double.parseDouble(marketPrice);
double vipPrice = doublePrice * userDiscount;
String countPriceStr = fromatDoubleTwoStr(fromatDoubleTwo(vipPrice));
return countPriceStr;
}
}

View File

@@ -0,0 +1,534 @@
package com.ckkj.water.utils.dataUtil;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.File;
/**
* Created by dty on 2015/11/9.
* 指定文件的打开方式,可直接打开
*/
public class FileOpenWays {
/**
* -- MIME 列表 --
*/
public static final String[][] MIME_MapTable =
{
// --{后缀名, MIME类型} --
{".3gp", "video/3gpp"},
{".3gpp", "video/3gpp"},
{".aac", "audio/x-mpeg"},
{".amr", "audio/x-mpeg"},
{".apk", "application/vnd.android.package-archive"},
{".avi", "video/x-msvideo"},
{".aab", "application/x-authoware-bin"},
{".aam", "application/x-authoware-map"},
{".aas", "application/x-authoware-seg"},
{".ai", "application/postscript"},
{".aif", "audio/x-aiff"},
{".aifc", "audio/x-aiff"},
{".aiff", "audio/x-aiff"},
{".als", "audio/x-alpha5"},
{".amc", "application/x-mpeg"},
{".ani", "application/octet-stream"},
{".asc", "text/plain"},
{".asd", "application/astound"},
{".asf", "video/x-ms-asf"},
{".asn", "application/astound"},
{".asp", "application/x-asap"},
{".asx", " video/x-ms-asf"},
{".au", "audio/basic"},
{".avb", "application/octet-stream"},
{".awb", "audio/amr-wb"},
{".bcpio", "application/x-bcpio"},
{".bld", "application/bld"},
{".bld2", "application/bld2"},
{".bpk", "application/octet-stream"},
{".bz2", "application/x-bzip2"},
{".bin", "application/octet-stream"},
{".bmp", "image/bmp"},
{".c", "text/plain"},
{".class", "application/octet-stream"},
{".conf", "text/plain"},
{".cpp", "text/plain"},
{".cal", "image/x-cals"},
{".ccn", "application/x-cnc"},
{".cco", "application/x-cocoa"},
{".cdf", "application/x-netcdf"},
{".cgi", "magnus-internal/cgi"},
{".chat", "application/x-chat"},
{".clp", "application/x-msclip"},
{".cmx", "application/x-cmx"},
{".co", "application/x-cult3d-object"},
{".cod", "image/cis-cod"},
{".cpio", "application/x-cpio"},
{".cpt", "application/mac-compactpro"},
{".crd", "application/x-mscardfile"},
{".csh", "application/x-csh"},
{".csm", "chemical/x-csml"},
{".csml", "chemical/x-csml"},
{".css", "text/css"},
{".cur", "application/octet-stream"},
{".doc", "application/msword"},
{".dcm", "x-lml/x-evm"},
{".dcr", "application/x-director"},
{".dcx", "image/x-dcx"},
{".dhtml", "text/html"},
{".dir", "application/x-director"},
{".dll", "application/octet-stream"},
{".dmg", "application/octet-stream"},
{".dms", "application/octet-stream"},
{".dot", "application/x-dot"},
{".dvi", "application/x-dvi"},
{".dwf", "drawing/x-dwf"},
{".dwg", "application/x-autocad"},
{".dxf", "application/x-autocad"},
{".dxr", "application/x-director"},
{".ebk", "application/x-expandedbook"},
{".emb", "chemical/x-embl-dl-nucleotide"},
{".embl", "chemical/x-embl-dl-nucleotide"},
{".eps", "application/postscript"},
{".epub", "application/epub+zip"},
{".eri", "image/x-eri"},
{".es", "audio/echospeech"},
{".esl", "audio/echospeech"},
{".etc", "application/x-earthtime"},
{".etx", "text/x-setext"},
{".evm", "x-lml/x-evm"},
{".evy", "application/x-envoy"},
{".exe", "application/octet-stream"},
{".fh4", "image/x-freehand"},
{".fh5", "image/x-freehand"},
{".fhc", "image/x-freehand"},
{".fif", "image/fif"},
{".fm", "application/x-maker"},
{".fpx", "image/x-fpx"},
{".fvi", "video/isivideo"},
{".flv", "video/x-msvideo"},
{".gau", "chemical/x-gaussian-input"},
{".gca", "application/x-gca-compressed"},
{".gdb", "x-lml/x-gdb"},
{".gif", "image/gif"},
{".gps", "application/x-gps"},
{".gtar", "application/x-gtar"},
{".gz", "application/x-gzip"},
{".gif", "image/gif"},
{".gtar", "application/x-gtar"},
{".gz", "application/x-gzip"},
{".h", "text/plain"},
{".hdf", "application/x-hdf"},
{".hdm", "text/x-hdml"},
{".hdml", "text/x-hdml"},
{".htm", "text/html"},
{".html", "text/html"},
{".hlp", "application/winhlp"},
{".hqx", "application/mac-binhex40"},
{".hts", "text/html"},
{".ice", "x-conference/x-cooltalk"},
{".ico", "application/octet-stream"},
{".ief", "image/ief"},
{".ifm", "image/gif"},
{".ifs", "image/ifs"},
{".imy", "audio/melody"},
{".ins", "application/x-net-install"},
{".ips", "application/x-ipscript"},
{".ipx", "application/x-ipix"},
{".it", "audio/x-mod"},
{".itz", "audio/x-mod"},
{".ivr", "i-world/i-vrml"},
{".j2k", "image/j2k"},
{".jad", "text/vnd.sun.j2me.app-descriptor"},
{".jam", "application/x-jam"},
{".jnlp", "application/x-java-jnlp-file"},
{".jpe", "image/jpeg"},
{".jpz", "image/jpeg"},
{".jwc", "application/jwc"},
{".jar", "application/java-archive"},
{".java", "text/plain"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpg"},
{".js", "application/x-javascript"},
{".kjx", "application/x-kjx"},
{".lak", "x-lml/x-lak"},
{".latex", "application/x-latex"},
{".lcc", "application/fastman"},
{".lcl", "application/x-digitalloca"},
{".lcr", "application/x-digitalloca"},
{".lgh", "application/lgh"},
{".lha", "application/octet-stream"},
{".lml", "x-lml/x-lml"},
{".lmlpack", "x-lml/x-lmlpack"},
{".log", "text/plain"},
{".lsf", "video/x-ms-asf"},
{".lsx", "video/x-ms-asf"},
{".lzh", "application/x-lzh "},
{".m13", "application/x-msmediaview"},
{".m14", "application/x-msmediaview"},
{".m15", "audio/x-mod"},
{".m3u", "audio/x-mpegurl"},
{".m3url", "audio/x-mpegurl"},
{".ma1", "audio/ma1"},
{".ma2", "audio/ma2"},
{".ma3", "audio/ma3"},
{".ma5", "audio/ma5"},
{".man", "application/x-troff-man"},
{".map", "magnus-internal/imagemap"},
{".mbd", "application/mbedlet"},
{".mct", "application/x-mascot"},
{".mdb", "application/x-msaccess"},
{".mdz", "audio/x-mod"},
{".me", "application/x-troff-me"},
{".mel", "text/x-vmel"},
{".mi", "application/x-mif"},
{".mid", "audio/midi"},
{".midi", "audio/midi"},
{".m4a", "audio/mp4a-latm"},
{".m4b", "audio/mp4a-latm"},
{".m4p", "audio/mp4a-latm"},
{".m4u", "video/vnd.mpegurl"},
{".m4v", "video/x-m4v"},
{".mov", "video/quicktime"},
{".mp2", "audio/x-mpeg"},
{".mp3", "audio/x-mpeg"},
{".mp4", "video/mp4"},
{".mpc", "application/vnd.mpohun.certificate"},
{".mpe", "video/mpeg"},
{".mpeg", "video/mpeg"},
{".mpg", "video/mpeg"},
{".mpg4", "video/mp4"},
{".mpga", "audio/mpeg"},
{".msg", "application/vnd.ms-outlook"},
{".mif", "application/x-mif"},
{".mil", "image/x-cals"},
{".mio", "audio/x-mio"},
{".mmf", "application/x-skt-lbs"},
{".mng", "video/x-mng"},
{".mny", "application/x-msmoney"},
{".moc", "application/x-mocha"},
{".mocha", "application/x-mocha"},
{".mod", "audio/x-mod"},
{".mof", "application/x-yumekara"},
{".mol", "chemical/x-mdl-molfile"},
{".mop", "chemical/x-mopac-input"},
{".movie", "video/x-sgi-movie"},
{".mpn", "application/vnd.mophun.application"},
{".mpp", "application/vnd.ms-project"},
{".mps", "application/x-mapserver"},
{".mrl", "text/x-mrml"},
{".mrm", "application/x-mrm"},
{".ms", "application/x-troff-ms"},
{".mts", "application/metastream"},
{".mtx", "application/metastream"},
{".mtz", "application/metastream"},
{".mzv", "application/metastream"},
{".nar", "application/zip"},
{".nbmp", "image/nbmp"},
{".nc", "application/x-netcdf"},
{".ndb", "x-lml/x-ndb"},
{".ndwn", "application/ndwn"},
{".nif", "application/x-nif"},
{".nmz", "application/x-scream"},
{".nokia-op-logo", "image/vnd.nok-oplogo-color"},
{".npx", "application/x-netfpx"},
{".nsnd", "audio/nsnd"},
{".nva", "application/x-neva1"},
{".oda", "application/oda"},
{".oom", "application/x-atlasMate-plugin"},
{".ogg", "audio/ogg"},
{".pac", "audio/x-pac"},
{".pae", "audio/x-epac"},
{".pan", "application/x-pan"},
{".pbm", "image/x-portable-bitmap"},
{".pcx", "image/x-pcx"},
{".pda", "image/x-pda"},
{".pdb", "chemical/x-pdb"},
{".pdf", "application/pdf"},
{".pfr", "application/font-tdpfr"},
{".pgm", "image/x-portable-graymap"},
{".pict", "image/x-pict"},
{".pm", "application/x-perl"},
{".pmd", "application/x-pmd"},
{".png", "image/png"},
{".pnm", "image/x-portable-anymap"},
{".pnz", "image/png"},
{".pot", "application/vnd.ms-powerpoint"},
{".ppm", "image/x-portable-pixmap"},
{".pps", "application/vnd.ms-powerpoint"},
{".ppt", "application/vnd.ms-powerpoint"},
{".pqf", "application/x-cprplayer"},
{".pqi", "application/cprplayer"},
{".prc", "application/x-prc"},
{".proxy", "application/x-ns-proxy-autoconfig"},
{".prop", "text/plain"},
{".ps", "application/postscript"},
{".ptlk", "application/listenup"},
{".pub", "application/x-mspublisher"},
{".pvx", "video/x-pv-pvx"},
{".qcp", "audio/vnd.qcelp"},
{".qt", "video/quicktime"},
{".qti", "image/x-quicktime"},
{".qtif", "image/x-quicktime"},
{".r3t", "text/vnd.rn-realtext3d"},
{".ra", "audio/x-pn-realaudio"},
{".ram", "audio/x-pn-realaudio"},
{".ras", "image/x-cmu-raster"},
{".rdf", "application/rdf+xml"},
{".rf", "image/vnd.rn-realflash"},
{".rgb", "image/x-rgb"},
{".rlf", "application/x-richlink"},
{".rm", "audio/x-pn-realaudio"},
{".rmf", "audio/x-rmf"},
{".rmm", "audio/x-pn-realaudio"},
{".rnx", "application/vnd.rn-realplayer"},
{".roff", "application/x-troff"},
{".rp", "image/vnd.rn-realpix"},
{".rpm", "audio/x-pn-realaudio-plugin"},
{".rt", "text/vnd.rn-realtext"},
{".rte", "x-lml/x-gps"},
{".rtf", "application/rtf"},
{".rtg", "application/metastream"},
{".rtx", "text/richtext"},
{".rv", "video/vnd.rn-realvideo"},
{".rwc", "application/x-rogerwilco"},
{".rar", "application/x-rar-compressed"},
{".rc", "text/plain"},
{".rmvb", "audio/x-pn-realaudio"},
{".s3m", "audio/x-mod"},
{".s3z", "audio/x-mod"},
{".sca", "application/x-supercard"},
{".scd", "application/x-msschedule"},
{".sdf", "application/e-score"},
{".sea", "application/x-stuffit"},
{".sgm", "text/x-sgml"},
{".sgml", "text/x-sgml"},
{".shar", "application/x-shar"},
{".shtml", "magnus-internal/parsed-html"},
{".shw", "application/presentations"},
{".si6", "image/si6"},
{".si7", "image/vnd.stiwap.sis"},
{".si9", "image/vnd.lgtwap.sis"},
{".sis", "application/vnd.symbian.install"},
{".sit", "application/x-stuffit"},
{".skd", "application/x-koan"},
{".skm", "application/x-koan"},
{".skp", "application/x-koan"},
{".skt", "application/x-koan"},
{".slc", "application/x-salsa"},
{".smd", "audio/x-smd"},
{".smi", "application/smil"},
{".smil", "application/smil"},
{".smp", "application/studiom"},
{".smz", "audio/x-smd"},
{".sh", "application/x-sh"},
{".snd", "audio/basic"},
{".spc", "text/x-speech"},
{".spl", "application/futuresplash"},
{".spr", "application/x-sprite"},
{".sprite", "application/x-sprite"},
{".sdp", "application/sdp"},
{".spt", "application/x-spt"},
{".src", "application/x-wais-source"},
{".stk", "application/hyperstudio"},
{".stm", "audio/x-mod"},
{".sv4cpio", "application/x-sv4cpio"},
{".sv4crc", "application/x-sv4crc"},
{".svf", "image/vnd"},
{".svg", "image/svg-xml"},
{".svh", "image/svh"},
{".svr", "x-world/x-svr"},
{".swf", "application/x-shockwave-flash"},
{".swfl", "application/x-shockwave-flash"},
{".t", "application/x-troff"},
{".tad", "application/octet-stream"},
{".talk", "text/x-speech"},
{".tar", "application/x-tar"},
{".taz", "application/x-tar"},
{".tbp", "application/x-timbuktu"},
{".tbt", "application/x-timbuktu"},
{".tcl", "application/x-tcl"},
{".tex", "application/x-tex"},
{".texi", "application/x-texinfo"},
{".texinfo", "application/x-texinfo"},
{".tgz", "application/x-tar"},
{".thm", "application/vnd.eri.thm"},
{".tif", "image/tiff"},
{".tiff", "image/tiff"},
{".tki", "application/x-tkined"},
{".tkined", "application/x-tkined"},
{".toc", "application/toc"},
{".toy", "image/toy"},
{".tr", "application/x-troff"},
{".trk", "x-lml/x-gps"},
{".trm", "application/x-msterminal"},
{".tsi", "audio/tsplayer"},
{".tsp", "application/dsptype"},
{".tsv", "text/tab-separated-values"},
{".ttf", "application/octet-stream"},
{".ttz", "application/t-time"},
{".txt", "text/plain"},
{".ult", "audio/x-mod"},
{".ustar", "application/x-ustar"},
{".uu", "application/x-uuencode"},
{".uue", "application/x-uuencode"},
{".vcd", "application/x-cdlink"},
{".vcf", "text/x-vcard"},
{".vdo", "video/vdo"},
{".vib", "audio/vib"},
{".viv", "video/vivo"},
{".vivo", "video/vivo"},
{".vmd", "application/vocaltec-media-desc"},
{".vmf", "application/vocaltec-media-file"},
{".vmi", "application/x-dreamcast-vms-info"},
{".vms", "application/x-dreamcast-vms"},
{".vox", "audio/voxware"},
{".vqe", "audio/x-twinvq-plugin"},
{".vqf", "audio/x-twinvq"},
{".vql", "audio/x-twinvq"},
{".vre", "x-world/x-vream"},
{".vrml", "x-world/x-vrml"},
{".vrt", "x-world/x-vrt"},
{".vrw", "x-world/x-vream"},
{".vts", "workbook/formulaone"},
{".wax", "audio/x-ms-wax"},
{".wbmp", "image/vnd.wap.wbmp"},
{".web", "application/vnd.xara"},
{".wav", "audio/x-wav"},
{".wma", "audio/x-ms-wma"},
{".wmv", "audio/x-ms-wmv"},
{".wi", "image/wavelet"},
{".wis", "application/x-InstallShield"},
{".wm", "video/x-ms-wm"},
{".wmd", "application/x-ms-wmd"},
{".wmf", "application/x-msmetafile"},
{".wml", "text/vnd.wap.wml"},
{".wmlc", "application/vnd.wap.wmlc"},
{".wmls", "text/vnd.wap.wmlscript"},
{".wmlsc", "application/vnd.wap.wmlscriptc"},
{".wmlscript", "text/vnd.wap.wmlscript"},
{".wmv", "video/x-ms-wmv"},
{".wmx", "video/x-ms-wmx"},
{".wmz", "application/x-ms-wmz"},
{".wpng", "image/x-up-wpng"},
{".wps", "application/vnd.ms-works"},
{".wpt", "x-lml/x-gps"},
{".wri", "application/x-mswrite"},
{".wrl", "x-world/x-vrml"},
{".wrz", "x-world/x-vrml"},
{".ws", "text/vnd.wap.wmlscript"},
{".wsc", "application/vnd.wap.wmlscriptc"},
{".wv", "video/wavelet"},
{".wvx", "video/x-ms-wvx"},
{".wxl", "application/x-wxl"},
{".x-gzip", "application/x-gzip"},
{".xar", "application/vnd.xara"},
{".xbm", "image/x-xbitmap"},
{".xdm", "application/x-xdma"},
{".xdma", "application/x-xdma"},
{".xdw", "application/vnd.fujixerox.docuworks"},
{".xht", "application/xhtml+xml"},
{".xhtm", "application/xhtml+xml"},
{".xhtml", "application/xhtml+xml"},
{".xla", "application/vnd.ms-excel"},
{".xlc", "application/vnd.ms-excel"},
{".xll", "application/x-excel"},
{".xlm", "application/vnd.ms-excel"},
{".xls", "application/vnd.ms-excel"},
{".xlt", "application/vnd.ms-excel"},
{".xlw", "application/vnd.ms-excel"},
{".xm", "audio/x-mod"},
{".xml", "text/xml"},
{".xmz", "audio/x-mod"},
{".xpi", "application/x-xpinstall"},
{".xpm", "image/x-xpixmap"},
{".xsit", "text/xml"},
{".xsl", "text/xml"},
{".xul", "text/xul"},
{".xwd", "image/x-xwindowdump"},
{".xyz", "chemical/x-pdb"},
{".yz1", "application/x-yz1"},
{".z", "application/x-compress"},
{".zac", "application/x-zaurus-zac"},
{".zip", "application/zip"},
{"", "*/*"}
};
private Context mContext;
public FileOpenWays(Context context) {
this.mContext = context;
}
public static Intent showOpenTypeDialog(String param) {
Log.e("ViChildError", "showOpenTypeDialog");
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(param));
intent.setDataAndType(uri, "*/*");
return intent;
}
/**
* --获取文件类型 --
*/
public static String getMIMEType(String filePath) {
String type = "*/*";
String fName = filePath;
int dotIndex = fName.lastIndexOf(".");
if (dotIndex < 0) {
return type;
}
String end = fName.substring(dotIndex, fName.length()).toLowerCase();
if (TextUtils.isEmpty(end)) {
return type;
}
for (int i = 0; i < MIME_MapTable.length; i++) {
if (end.equals(MIME_MapTable[i][0])) {
type = MIME_MapTable[i][1];
}
}
// 如果没查到mimeType就从系统里查
if (TextUtils.equals(type, "*/*")) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(end.substring(1));
if (type == null) {
type = "*/*";
}
}
return type;
}
//打开文件时调用
public void openFiles(String filesPath) {
Uri uri = Uri.parse("file://" + filesPath);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
String type = getMIMEType(filesPath);
intent.setDataAndType(uri, type);
if (!TextUtils.equals(type, "*/*")) {
try {
mContext.startActivity(intent);
} catch (Exception e) {
mContext.startActivity(showOpenTypeDialog(filesPath));
}
} else {
mContext.startActivity(showOpenTypeDialog(filesPath));
}
}
//显示打开方式
public void show(String filesPath) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
mContext.startActivity(showOpenTypeDialog(filesPath));
}
}

View File

@@ -0,0 +1,755 @@
package com.ckkj.water.utils.dataUtil;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Log;
import com.ckkj.water.utils.show.FL;
import com.ckkj.water.utils.show.L;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
/**
* 文件操作工具 可以创建和删除文件等
*/
public class FileUtil {
private static final String KB = "KB";
private static final String MB = "MB";
private static final String GB = "GB";
private static final String TAG = "FileUtil";
private static final String APPLICATION_FOLDER = "GameBar2";
private static final String ROM_FOLDER = "roms";
private static final String DOWNLOAD_FOLDER = "downloads";
private FileUtil() {
}
/**
* 获取文件夹大小
*/
public static long getDirSize(String filePath) {
long size = 0;
File f = new File(filePath);
if (f.isDirectory()) {
File[] files = f.listFiles();
for (File file : files) {
if (file.isDirectory()) {
size += getDirSize(file.getPath());
continue;
}
size += file.length();
}
} else {
size += f.length();
}
return size;
}
/**
* 存储bitmap
*/
public static void saveBitmap( String filePath, Bitmap bitmap) {
File file = createFile(filePath);
try {
FileOutputStream os = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.flush();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 格式化文件大小
*
* @param size file.length() 获取文件大小
*/
public static String formatFileSize(double size) {
double kiloByte = size / 1024;
if (kiloByte < 1) {
return size + "B";
}
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";
}
/**
* 获取文件后缀名
*/
public static String getFileExtensionName(String fileName) {
if (TextUtils.isEmpty(fileName)) {
return "";
}
int endP = fileName.lastIndexOf(".");
return endP > -1 ? fileName.substring(endP + 1, fileName.length()) : "";
}
/**
* 校验文件MD5码
*/
public static boolean checkMD5(String md5, File updateFile) {
if (TextUtils.isEmpty(md5) || updateFile == null) {
L.e(TAG, "MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = getFileMD5(updateFile);
if (calculatedDigest == null) {
L.e(TAG, "calculatedDigest null");
return false;
}
return calculatedDigest.equalsIgnoreCase(md5);
}
/**
* 获取文件MD5码
*/
public static String getFileMD5(File updateFile) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
L.e(TAG, "Exception while getting digest", e);
return null;
}
InputStream is;
try {
is = new FileInputStream(updateFile);
} catch (FileNotFoundException e) {
L.e(TAG, "Exception while getting FileInputStream", e);
return null;
}
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
// Fill to 32 chars
output = String.format("%32s", output).replace(' ', '0');
return output;
} catch (IOException e) {
throw new RuntimeException("Unable to process file for MD5", e);
} finally {
try {
is.close();
} catch (IOException e) {
L.e(TAG, "Exception on closing MD5 input stream", e);
}
}
}
/**
* 解压缩功能.
* 将ZIP_FILENAME文件解压到ZIP_DIR目录下.
*
* @param zipFile 压缩文件
* @param folderPath 解压目录
*/
public static int unZipFile(File zipFile, String folderPath) {
ZipFile zfile = null;
try {
zfile = new ZipFile(zipFile);
Enumeration zList = zfile.entries();
ZipEntry ze = null;
byte[] buf = new byte[1024];
while (zList.hasMoreElements()) {
ze = (ZipEntry) zList.nextElement();
if (ze.isDirectory()) {
// L.d(TAG, "ze.getName() = " + ze.getName());
String dirstr = folderPath + ze.getName();
//dirstr.trim();
dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
// L.d(TAG, "str = " + dirstr);
File f = new File(dirstr);
f.mkdir();
continue;
}
// L.d(TAG, "ze.getName() = " + ze.getName());
OutputStream os = new BufferedOutputStream(
new FileOutputStream(getRealFileName(folderPath, ze.getName())));
InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
int readLen = 0;
while ((readLen = is.read(buf)) != -1) {
os.write(buf, 0, readLen);
}
is.close();
os.close();
}
zfile.close();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
/**
* 给定根目录,返回一个相对路径所对应的实际文件名.
*
* @param baseDir 指定根目录
* @param absFileName 相对路径名来自于ZipEntry中的name
* @return java.io.File 实际的文件
*/
private static File getRealFileName(String baseDir, String absFileName) {
String[] dirs = absFileName.split("/");
File ret = new File(baseDir);
String substr = null;
if (dirs.length > 1) {
for (int i = 0; i < dirs.length - 1; i++) {
substr = dirs[i];
try {
//substr.trim();
substr = new String(substr.getBytes("8859_1"), "GB2312");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret = new File(ret, substr);
}
// L.d("upZipFile", "1ret = " + ret);
if (!ret.exists()) ret.mkdirs();
substr = dirs[dirs.length - 1];
try {
//substr.trim();
substr = new String(substr.getBytes("8859_1"), "GB2312");
// L.d("upZipFile", "substr = " + substr);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret = new File(ret, substr);
// L.d("upZipFile", "2ret = " + ret);
return ret;
}
return ret;
}
/**
* 通过流创建文件
*/
public static void createFileFormInputStream(InputStream is, String path) {
try {
FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[1376];
while (is.read(buf) > 0) {
fos.write(buf, 0, buf.length);
}
is.close();
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从文件读取对象
*/
public static Object readObj(String path) {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(path);
ois = new ObjectInputStream(fis);
return ois.readObject();
} catch (FileNotFoundException e) {
Log.e(TAG, FL.getExceptionString(e));
} catch (IOException e) {
FL.e(TAG, FL.getExceptionString(e));
} catch (ClassNotFoundException e) {
FL.e(TAG, FL.getExceptionString(e));
} finally {
try {
if (fis != null) {
fis.close();
}
if (ois != null) {
ois.close();
}
} catch (IOException e) {
FL.e(TAG, FL.getExceptionString(e));
}
}
return null;
}
/**
* 存储对象到文件,只有实现了Serailiable接口的对象才能被存储
*/
public static void writeObj(String path, Object object) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
File file = new File(path);
if (!file.getParentFile().exists()) {
file.mkdirs();
}
try {
fos = new FileOutputStream(path);
oos = new ObjectOutputStream(fos);
oos.writeObject(object);
} catch (FileNotFoundException e) {
FL.e(TAG, FL.getExceptionString(e));
} catch (IOException e) {
FL.e(TAG, FL.getExceptionString(e));
} finally {
try {
if (fos != null) {
fos.close();
}
if (oos != null) {
oos.close();
}
} catch (IOException e) {
FL.e(TAG, FL.getExceptionString(e));
}
}
}
/**
* 创建文件 当文件不存在的时候就创建一个文件,否则直接返回文件
*/
public static File createFile(String path) {
File file = new File(path);
return createFile(file);
}
public static File createFile(File file) {
if (!file.getParentFile().exists()) {
L.d(TAG, "目标文件所在路径不存在,准备创建……");
if (!createDir(file.getParent())) {
L.d(TAG, "创建目录文件所在的目录失败!文件路径【" + file.getPath() + "");
}
}
// 创建目标文件
try {
if (!file.exists()) {
if (file.createNewFile()) {
L.d(TAG, "创建文件成功:" + file.getAbsolutePath());
}
return file;
} else {
return file;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 创建目录 当目录不存在的时候创建文件否则返回false
*/
public static boolean createDir(String path) {
File file = new File(path);
if (!file.exists()) {
if (!file.mkdirs()) {
L.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
return false;
}
return true;
}
return false;
}
/**
* 拷贝文件
*/
public static boolean copy(String fromPath, String toPath) {
File file = new File(fromPath);
if (!file.exists()) {
return false;
}
createFile(toPath);
return copyFile(fromPath, toPath);
}
/**
* 拷贝文件
*/
private static boolean copyFile(String fromFile, String toFile) {
InputStream fosfrom = null;
OutputStream fosto = null;
try {
fosfrom = new FileInputStream(fromFile);
fosto = new FileOutputStream(toFile);
byte bt[] = new byte[1024];
int c;
while ((c = fosfrom.read(bt)) > 0) {
fosto.write(bt, 0, c);
}
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
try {
if (fosfrom != null) {
fosfrom.close();
}
if (fosto != null) {
fosto.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 删除文件 如果文件存在删除文件否则返回false
*/
public static boolean deleteFile(String path) {
if (TextUtils.isEmpty(path)) return false;
File file = new File(path);
if (file.exists()) {
file.delete();
return true;
}
return false;
}
/**
* 递归删除目录下的所有文件及子目录下所有文件
*
* @param dir 将要删除的文件目录
* @return 删除成功返回true否则返回false,如果文件是空那么永远返回true
*/
public static boolean deleteDir(File dir) {
if (dir == null) {
return true;
}
if (dir.isDirectory()) {
String[] children = dir.list();
// 递归删除目录中的子目录下
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return dir.delete();
}
/**
* 递归返回文件或者目录的大小(单位:KB
* 不建议使用这个方法,有点坑
* 可以使用下面的方法http://blog.csdn.net/loongggdroid/article/details/12304695
*/
private static float getSize(String path, Float size) {
File file = new File(path);
if (file.exists()) {
if (file.isDirectory()) {
String[] children = file.list();
for (int fileIndex = 0; fileIndex < children.length; ++fileIndex) {
float tmpSize =
getSize(file.getPath() + File.separator + children[fileIndex], size) / 1000;
size += tmpSize;
}
} else if (file.isFile()) {
size += file.length();
}
}
return size;
}
/**
* 获取apk文件的icon
*
* @param path apk文件路径
*/
public static Drawable getApkIcon(Context context, String path) {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
//android有bug需要下面这两句话来修复才能获取apk图片
appInfo.sourceDir = path;
appInfo.publicSourceDir = path;
// String packageName = appInfo.packageName; //得到安装包名称
// String version=info.versionName; //得到版本信息
return pm.getApplicationIcon(appInfo);
}
return null;
}
/**
* 判断有无Sd卡
*/
public static boolean judgeIsExistSdCard() {
if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
return true;
}
return false;
}
/**
* 更改文件权限
*/
public synchronized static void chmodFile(String path) {
String[] cmd = { "chmod", "777", path };
Process process = null;
InputStream errorStream = null;
InputStream inputStream = null;
try {
process = Runtime.getRuntime().exec(cmd);
byte[] buffer = new byte[64];
int len = -1;
inputStream = process.getInputStream();
while ((len = inputStream.read(buffer)) > 0) {
}
errorStream = process.getErrorStream();
len = -1;
while ((len = errorStream.read(buffer)) > 0) {
}
buffer = null;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (errorStream != null) {
errorStream.close();
}
if (inputStream != null) {
inputStream.close();
}
if (process != null) {
process.destroy();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取应用文件夹 /
*
* @return The application folder.
*/
public synchronized static File getApplicationFolder(Context mContext) {
File root = null;
if (judgeIsExistSdCard()) {
root = Environment.getExternalStorageDirectory();
} else {
root = mContext.getFilesDir();
}
chmodFile(root.getAbsolutePath());
if (root != null) {
File folder = new File(root, APPLICATION_FOLDER);
if (!folder.exists()) {
folder.mkdirs();
chmodFile(folder.getAbsolutePath());
}
return folder;
} else {
root.toString();
return null;
}
}
/**
* 获取 存放应用的文件夹
*/
public static File getRomloadFolder(Context context) {
File root = getApplicationFolder(context);
if (root != null) {
File folder = new File(root, ROM_FOLDER);
if (!folder.exists()) {
folder.mkdir();
chmodFile(folder.getAbsolutePath());
}
return folder;
} else {
return null;
}
}
/**
* 获取下载文件
*/
public synchronized static File getDownloadFolder(Context mContext) {
File root = getApplicationFolder(mContext);
if (root != null) {
File folder = new File(root, DOWNLOAD_FOLDER);
if (!folder.exists()) {
folder.mkdirs();
chmodFile(folder.getAbsolutePath());
}
return folder;
} else {
root.toString();
return null;
}
}
//判断是否存在sd卡
private static boolean getSDCardisExist() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
//获取sd卡根路径
private static String getSDPath() {
File sdDir = null;
boolean sdCardExist = (Environment.getExternalStorageState())
.equals(Environment.MEDIA_MOUNTED); //判断sd卡是否存在
if (sdCardExist) {
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString();
}
/**
*
* @param key
* @param files
* @return
*/
public static List<MultipartBody.Part> files2Parts(String key,
List<File> files) {
List<MultipartBody.Part> parts = new ArrayList<>();
if (files.size()>0){
for (File file : files) {
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.Part part = MultipartBody.Part.
createFormData(key, file.getName(), requestBody);
parts.add(part);
}
}else {
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), "");
MultipartBody.Part part = MultipartBody.Part.createFormData(key, "", requestBody);
parts.add(part);
}
return parts;
}
public static String getAbsolutePathFromUri(Context context,Uri uri) {
String path = null;
// 使用 ContentResolver 获取路径
if ("content".equalsIgnoreCase(uri.getScheme())) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
int columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
cursor.moveToFirst();
String displayName = cursor.getString(columnIndex);
cursor.close();
// 这里可以使用 displayName 进行后续处理
// 注意:这不是绝对路径,只是文件名
path = displayName;
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
path = uri.getPath();
} else if (DocumentsContract.isDocumentUri(context, uri)) {
String documentId = DocumentsContract.getDocumentId(uri);
String[] split = documentId.split(":");
String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
path = Environment.getExternalStorageDirectory() + "/" + split[1];
} else {
// 处理非主存储的情况
// 这里可能需要根据具体存储类型进行处理
}
}
return path;
}
/**
* 文件后缀名
* @param fileName
* @return
*/
public static String getFileSuffixWithQuestion(String url) {
if (url == null || url.isEmpty()) return "";
// 去掉问号之后的部分
int questionMarkIndex = url.indexOf("?");
if (questionMarkIndex != -1) {
url = url.substring(0, questionMarkIndex);
}
// 获取最后一个点后面的内容作为后缀
int lastDotIndex = url.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < url.length() - 1) {
return url.substring(lastDotIndex); // 包含“.”的后缀
}
return "";
}
}

View File

@@ -0,0 +1,20 @@
package com.ckkj.water.utils.dataUtil;
import java.util.regex.Pattern;
public class PhonePatternUtil {
private static final String PHONE_REGEX = "^(1(3[0-9]|4[5-9]|5[0-3,5-9]|6[5-6]|7[0-8]|8[0-9]|9[1,3,5,8,9])\\d{8})$";
private static final Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
public static boolean phoneReg(String phoneNumber) {
if (isValidPhoneNumber(phoneNumber)) {
return true;
} else {
return false;
}
}
public static boolean isValidPhoneNumber(String phoneNumber) {
return PHONE_PATTERN.matcher(phoneNumber).matches();
}
}

View File

@@ -0,0 +1,226 @@
package com.ckkj.water.utils.dataUtil;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.ckkj.water.ConstantUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 配置文件工具类
*
* @author “AriaLyy@outlook.com”
*/
public class SharePreUtil {
/**
* 删除键值对
*/
public static void removeKey(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.remove(key);
editor.commit();
}
/**
* 从配置文件读取字符串
*
* @param preName 配置文件名
* @param key 字符串键值
* @return 键值对应的字符串, 默认返回""
*/
public static String getString(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
if(ConstantUtil.USER_LOCATION_PROVICE_NAME.equals(key)){
return pre.getString(key, "");
}else if(ConstantUtil.USER_LOCATION_CITY_NAME.equals(key)){
return pre.getString(key, "");
}
return pre.getString(key, "");
}
/**
* 从配置文件读取int数据
*
* @param preName 配置文件名
* @param key int的键值
* @return 键值对应的int, 默认返回-1
*/
public static int getInt(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getInt(key, -1);
}
/**
* 从配置文件读取Boolean值
*
* @return 如果没有默认返回false
*/
public static Boolean getBoolean(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getBoolean(key, false);
}
/**
* 从配置文件读取Boolean值
*
* @return 如果没有默认返回false
*/
public static Boolean getBooleanDefTrue(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getBoolean(key, true);
}
/**
* 从配置文件获取float数据
*
* @return 默认返回0.0f
*/
public static float getFloat(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getFloat(key, 0.0f);
}
/**
* 从配置文件获取对象
*/
public static <T> T getObject(String preName, Context context, String key, Class<T> clazz) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
String str = pre.getString(key, "");
return TextUtils.isEmpty(str) ? null : new Gson().fromJson(str, clazz);
}
/**
* 存储字符串到配置文件
*
* @param preName 配置文件名
* @param key 存储的键值
* @param value 需要存储的字符串
* @return 成功标志
*/
public static Boolean putString(String preName, Context context, String key, String value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putString(key, value);
return editor.commit();
}
/**
* 保存Float数据到配置文件
*/
public static Boolean putFloat(String preName, Context context, String key, float value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putFloat(key, value);
return editor.commit();
}
/**
* 存储数字到配置文件
*
* @param preName 配置文件名
* @param key 存储的键值
* @param value 需要存储的数字
* @return 成功标志
*/
public static Boolean putInt(String preName, Context context, String key, int value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putInt(key, value);
return editor.commit();
}
/**
* 存储Boolean值到配置文件
*
* @param preName 配置文件名
* @param key 键值
* @param value 需要存储的boolean值
*/
public static Boolean putBoolean(String preName, Context context, String key, Boolean value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putBoolean(key, value);
return editor.commit();
}
/**
* 存储Long值到配置文件
*
* @param preName 配置文件名
* @param key 键值
* @param value 需要存储的boolean值
*/
public static Boolean putLong(String preName, Context context, String key, long value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putLong(key, value);
return editor.commit();
}
/**
* 从配置文件读取int数据
*
* @param preName 配置文件名
* @param key int的键值
* @return 键值对应的int, 默认返回-1
*/
public static long getLongDefaulTime(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getLong(key, System.currentTimeMillis());
}
/**
* 存放对象
*/
public static Boolean putObject(String preName, Context context, String key, Class<?> clazz,
Object obj) {
String str = new Gson().toJson(obj, clazz);
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
Editor editor = pre.edit();
editor.putString(key, str);
return editor.commit();
}
//偏好设置存储list
public static <T> void saveVideoSP(Context context, String tableName, String key, List<T> datalist) {
SharedPreferences preferences = context.getSharedPreferences(tableName, Context.MODE_PRIVATE);
Editor editor = preferences.edit();
Gson gson = new Gson();
String strJson = gson.toJson(datalist);
editor.clear();
editor.putString(key, strJson);
editor.commit();
}
//偏好设置取出list
public static <T> List<T> getModelList(Context context, String tableName, String key,Class<T> cls) {
if (context == null || tableName == null || key == null) {
return null;
}
SharedPreferences sharedPreferences = context.getSharedPreferences(tableName, Context.MODE_PRIVATE);
List<T> datalist = new ArrayList<>();
String strJson = sharedPreferences.getString(key, null);
if (strJson == null) {
return datalist;
}
JsonArray jsonArray = new JsonParser().parse(strJson).getAsJsonArray();
Gson gson = new Gson();
for (JsonElement jsonElement : jsonArray) {
datalist.add(gson.fromJson(jsonElement,cls)); //cls
}
return datalist;
}
}

View File

@@ -0,0 +1,168 @@
package com.ckkj.water.utils.helper;
import java.util.HashMap;
import java.util.Map;
public class FiveElementsHelper {
// 五行颜色值
private static final String COLOR_METAL = "#FFAA00"; // 金
private static final String COLOR_WOOD = "#4CAE50"; // 木
private static final String COLOR_WATER = "#2196F3"; // 水
private static final String COLOR_FIRE = "#E54E4E"; // 火
private static final String COLOR_EARTH = "#B9653D"; // 土
// 天干映射表
private static final Map<String, String> celestialStems = new HashMap<>();
// 地支映射表
private static final Map<String, String> terrestrialBranches = new HashMap<>();
// 藏干映射表
private static final Map<String, String[]> hiddenStems = new HashMap<>();
// 五行颜色映射
private static final Map<String, String> elementColors = new HashMap<>();
static {
// 初始化天干五行
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
celestialStems.put("", "");
// 初始化地支五行
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
terrestrialBranches.put("", "");
// 初始化藏干
hiddenStems.put("", new String[]{""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{"", ""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{""});
hiddenStems.put("", new String[]{"", "", ""});
hiddenStems.put("", new String[]{"", ""});
// 初始化五行颜色
elementColors.put("", COLOR_METAL);
elementColors.put("", COLOR_WOOD);
elementColors.put("", COLOR_WATER);
elementColors.put("", COLOR_FIRE);
elementColors.put("", COLOR_EARTH);
}
/**
* 获取五行属性信息
*
* @param element 天干、地支或藏干
* @return 包含五行名称和颜色值的Map如果未找到返回null
*/
public static Map<String, String> getElementInfo(String element) {
String elementType = null;
// 1. 检查是否为天干
if (celestialStems.containsKey(element)) {
elementType = celestialStems.get(element);
}
// 2. 检查是否为地支
else if (terrestrialBranches.containsKey(element)) {
elementType = terrestrialBranches.get(element);
}
// 3. 检查是否为藏干(需要遍历所有地支的藏干)
else {
for (String[] stems : hiddenStems.values()) {
for (String stem : stems) {
if (stem.equals(element)) {
elementType = celestialStems.get(stem);
break;
}
}
if (elementType != null) break;
}
}
// 未找到匹配项
if (elementType == null) return null;
// 返回结果
Map<String, String> result = new HashMap<>();
result.put("element", elementType);
result.put("color", elementColors.get(elementType));
return result;
}
/**
* 获取所有天干
*/
public static String[] getAllCelestialStems() {
return celestialStems.keySet().toArray(new String[0]);
}
/**
* 获取所有地支
*/
public static String[] getAllTerrestrialBranches() {
return terrestrialBranches.keySet().toArray(new String[0]);
}
/**
* 获取指定地支的藏干
*
* @param branch 地支
* @return 藏干数组如果地支不存在返回null
*/
public static String[] getHiddenStems(String branch) {
return hiddenStems.get(branch);
}
/**
* 获取天干的阴阳属性
*
* @param stem 天干
* @return "阳"或"阴"无效输入返回null
*/
public static String getYinYang(String stem) {
// 阳干:甲、丙、戊、庚、壬
// 阴干:乙、丁、己、辛、癸
if ("甲丙戊庚壬".contains(stem)) return "";
if ("乙丁己辛癸".contains(stem)) return "";
return null;
}
/**
* 获取地支的阴阳属性
*
* @param branch 地支
* @return "阳"或"阴"无效输入返回null
*/
public static String getBranchYinYang(String branch) {
// 阳支:子、寅、辰、午、申、戌
// 阴支:丑、卯、巳、未、酉、亥
if ("子寅辰午申戌".contains(branch)) return "";
if ("丑卯巳未酉亥".contains(branch)) return "";
return null;
}
}

View File

@@ -0,0 +1,31 @@
package com.ckkj.water.utils.helper;
public class ShiShen {
private String fullName; // 十神全称(如"正官"
private String shortName; // 十神简称(如"官"
private String relation; // 生克关系(如"克我"
private String yinYang; // 阴阳关系(如"阳克阴"
public ShiShen(String fullName, String shortName, String relation, String yinYang) {
this.fullName = fullName;
this.shortName = shortName;
this.relation = relation;
this.yinYang = yinYang;
}
// Getters
public String getFullName() { return fullName; }
public String getShortName() { return shortName; }
public String getRelation() { return relation; }
public String getYinYang() { return yinYang; }
@Override
public String toString() {
return "ShiShen{" +
"全称='" + fullName + '\'' +
", 简称='" + shortName + '\'' +
", 关系='" + relation + '\'' +
", 阴阳='" + yinYang + '\'' +
'}';
}
}

View File

@@ -0,0 +1,156 @@
package com.ckkj.water.utils.helper;
import java.util.HashMap;
import java.util.Map;
public class ShiShenCalculator {
// 十神全称到简称的映射表
private static final Map<String, String> SHEN_SHORT_FORM = new HashMap<>();
static {
SHEN_SHORT_FORM.put("比肩", "");
SHEN_SHORT_FORM.put("劫财", "");
SHEN_SHORT_FORM.put("食神", "");
SHEN_SHORT_FORM.put("伤官", "");
SHEN_SHORT_FORM.put("偏财", "");
SHEN_SHORT_FORM.put("正财", "");
SHEN_SHORT_FORM.put("偏印", "");
SHEN_SHORT_FORM.put("正印", "");
SHEN_SHORT_FORM.put("七杀", "");
SHEN_SHORT_FORM.put("正官", "");
}
/**
* 根据十神全称获取简称
*
* @param fullName 十神全称(如"比肩"
* @return 十神简称(如"比"未找到时返回null
*/
public static String getAbbreviation(String fullName) {
return SHEN_SHORT_FORM.get(fullName);
}
// 天干阴阳属性映射
private static final Map<String, String> stemYinYang = new HashMap<>();
static {
// 阳干:甲、丙、戊、庚、壬
// 阴干:乙、丁、己、辛、癸
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
stemYinYang.put("", "");
}
// 十神映射表
private static final Map<String, ShiShen> SHI_SHEN_MAP = new HashMap<>();
static {
// 生克关系 + 阴阳组合 -> 十神对象
SHI_SHEN_MAP.put("同阳", new ShiShen("比肩", "", "同我", "阳同阳"));
SHI_SHEN_MAP.put("同阴", new ShiShen("比肩", "", "同我", "阴同阴"));
SHI_SHEN_MAP.put("同阴阳", new ShiShen("劫财", "", "同我", "阴阳异"));
SHI_SHEN_MAP.put("生阳阳", new ShiShen("食神", "", "我生", "阳生阳"));
SHI_SHEN_MAP.put("生阳阴", new ShiShen("伤官", "", "我生", "阳生阴"));
SHI_SHEN_MAP.put("生阴阳", new ShiShen("伤官", "", "我生", "阴生阳"));
SHI_SHEN_MAP.put("生阴阴", new ShiShen("食神", "", "我生", "阴生阴"));
SHI_SHEN_MAP.put("克阳阳", new ShiShen("偏财", "", "我克", "阳克阳"));
SHI_SHEN_MAP.put("克阳阴", new ShiShen("正财", "", "我克", "阳克阴"));
SHI_SHEN_MAP.put("克阴阳", new ShiShen("正财", "", "我克", "阴克阳"));
SHI_SHEN_MAP.put("克阴阴", new ShiShen("偏财", "", "我克", "阴克阴"));
SHI_SHEN_MAP.put("被生阳阳", new ShiShen("偏印", "", "生我", "阳生阳"));
SHI_SHEN_MAP.put("被生阳阴", new ShiShen("正印", "", "生我", "阴生阳"));
SHI_SHEN_MAP.put("被生阴阳", new ShiShen("正印", "", "生我", "阳生阴"));
SHI_SHEN_MAP.put("被生阴阴", new ShiShen("偏印", "", "生我", "阴生阴"));
SHI_SHEN_MAP.put("被克阳阳", new ShiShen("七杀", "", "克我", "阳克阳"));
SHI_SHEN_MAP.put("被克阳阴", new ShiShen("正官", "", "克我", "阴克阳"));
SHI_SHEN_MAP.put("被克阴阳", new ShiShen("正官", "", "克我", "阳克阴"));
SHI_SHEN_MAP.put("被克阴阴", new ShiShen("七杀", "", "克我", "阴克阴"));
}
/**
* 计算十神关系
*
* @param dayStem 日干(如"己"
* @param targetStem 目标天干(如"癸"
* @return 十神对象如果输入无效返回null
*/
public static ShiShen calculate(String dayStem, String targetStem) {
// 验证输入
if (!isValidStem(dayStem) || !isValidStem(targetStem)) {
return null;
}
// 1. 获取五行属性
String dayElement = FiveElementsHelper.getElementInfo(dayStem).get("element");
String targetElement = FiveElementsHelper.getElementInfo(targetStem).get("element");
// 2. 获取阴阳属性
String dayYY = stemYinYang.get(dayStem);
String targetYY = stemYinYang.get(targetStem);
// 3. 确定生克关系
String relationKey = getElementRelation(dayElement, targetElement);
String yyKey = dayYY + targetYY;
// 4. 组合最终key
String finalKey = relationKey + yyKey;
// 特殊处理同五行情况
if ("".equals(relationKey)) {
if (dayYY.equals(targetYY)) {
finalKey = "" + dayYY; // 同阳或同阴
} else {
finalKey = "同阴阳";
}
}
return SHI_SHEN_MAP.get(finalKey);
}
/**
* 判断是否为有效天干
*/
private static boolean isValidStem(String stem) {
return stemYinYang.containsKey(stem);
}
/**
* 获取五行生克关系
*/
private static String getElementRelation(String e1, String e2) {
if (e1.equals(e2)) return "";
// 五行生克规则
Map<String, String> sheng = new HashMap<>();
sheng.put("", "");
sheng.put("", "");
sheng.put("", "");
sheng.put("", "");
sheng.put("", "");
Map<String, String> ke = new HashMap<>();
ke.put("", "");
ke.put("", "");
ke.put("", "");
ke.put("", "");
ke.put("", "");
if (sheng.get(e1).equals(e2)) return "";
if (ke.get(e1).equals(e2)) return "";
if (sheng.get(e2).equals(e1)) return "被生";
if (ke.get(e2).equals(e1)) return "被克";
return null; // 理论上不会发生
}
}

View File

@@ -0,0 +1,85 @@
package com.ckkj.water.utils.manager;
import android.app.Activity;
import java.util.HashMap;
import java.util.Map;
/**
* depictionactivity管理工具类
*/
public class ActivityManager {
/**
* 存放Activity的map
*/
private static Map<String, Activity> activitys = new HashMap<>();
/**
* 获取管理类中注册的所有Activity的map
* @return
*/
public static Map<String, Activity> getActivitys()
{
return activitys;
}
/**
* 根据键值取对应的Activity
* @param key 键值
* @return 键值对应的Activity
*/
public static Activity getActivity(String key)
{
return activitys.get(key);
}
/**
* 注册Activity
* @param value
* @param key
*/
public static void addActivity(Activity value,String key)
{
activitys.put(key, value);
}
/**
* 将key对应的Activity移除掉
* @param key
*/
public static void removeActivity(String key)
{
activitys.remove(key);
}
/**
* finish掉所有的Activity移除所有的Activity
*/
public static void removeAllActivity()
{
for (Activity activity : activitys.values()) {
activity.finish();
}
activitys.clear();
}
/**
* 结束所有Activity但保留MainActivity
*/
public static void removeAllActivityExceptMain()
{
Map<String, Activity> tempMap = new HashMap<>(activitys);
for (Map.Entry<String, Activity> entry : tempMap.entrySet()) {
Activity activity = entry.getValue();
String key = entry.getKey();
// 检查是否为MainActivity如果不是则结束
if (!key.contains("MainActivity")) {
activity.finish();
activitys.remove(key);
}
}
}
}

View File

@@ -0,0 +1,74 @@
package com.ckkj.water.utils.manager;
import android.content.Context;
import android.media.MediaRecorder;
import java.io.File;
import java.io.IOException;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-17-2025 周四 15:21
*/
public class AudioRecordManager {
private MediaRecorder mediaRecorder;
private String audioPath;
private long startTime;
public void startRecord(Context context) {
try {
audioPath = context.getExternalCacheDir().getAbsolutePath() + "/" + System.currentTimeMillis() + ".m4a";
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setOutputFile(audioPath);
mediaRecorder.prepare();
mediaRecorder.start();
startTime = System.currentTimeMillis();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopRecord() {
try {
if (mediaRecorder != null) {
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder = null;
}
} catch (RuntimeException e) {
e.printStackTrace();
// 可能 stop 出错
}
}
public void cancelRecord() {
try {
if (mediaRecorder != null) {
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder = null;
}
} catch (RuntimeException e) {
e.printStackTrace();
}
if (audioPath != null) {
new File(audioPath).delete();
}
}
public String getAudioPath() {
return audioPath;
}
public int getRecordDuration() {
return (int) ((System.currentTimeMillis() - startTime) / 1000); // 秒
}
}

View File

@@ -0,0 +1,39 @@
package com.ckkj.water.utils.manager;
import android.graphics.Color;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-22-2025 周二 15:48
*/
public class ColorManage {
private static ColorManage instance;
private ColorManage() {
// 私有构造方法,防止外部直接创建实例
}
public static ColorManage getInstance() {
if (instance == null) {
synchronized (ColorManage.class) {
if (instance == null) {
instance = new ColorManage();
}
}
}
return instance;
}
public boolean isParsableColor(String color) {
try {
Color.parseColor(color);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}

View File

@@ -0,0 +1,45 @@
package com.ckkj.water.utils.manager;
import android.content.Context;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
/**
* @author fengxiaoyang
* @date 2025/5/21
* @description TODO: 描述该类的作用
*/
public class DingDingNotificationManage {
private static DingDingNotificationManage instance;
private DingDingNotificationManage() {
// 私有构造方法,防止外部直接创建实例
}
public static DingDingNotificationManage getInstance() {
if (instance == null) {
synchronized (DingDingNotificationManage.class) {
if (instance == null) {
instance = new DingDingNotificationManage();
}
}
}
return instance;
}
public void playNotificationSound(Context context) {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone ringtone = RingtoneManager.getRingtone(context, notification);
if (ringtone != null) {
ringtone.play();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,70 @@
package com.ckkj.water.utils.manager;
import android.content.Context;
import com.ckkj.water.AppConfig;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.base.entity.UserInfoEntity;
import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-07-2025 周一 12:51
*/
public class MingDengUserInfoManager {
private static MingDengUserInfoManager instance;
private LoginEntity entity;
private UserInfoEntity userInfo;
private MingDengUserInfoManager() {
// 私有构造方法,防止外部直接创建实例
}
public static MingDengUserInfoManager getInstance() {
if (instance == null) {
synchronized (MingDengUserInfoManager.class) {
if (instance == null) {
instance = new MingDengUserInfoManager();
}
}
}
return instance;
}
public LoginEntity getEntity() {
return entity;
}
public void setEntity(LoginEntity entity) {
this.entity = entity;
}
public UserInfoEntity getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfoEntity userInfo) {
this.userInfo = userInfo;
}
// 清空用户数据
public void clearUser(Context mContext) {
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_LOGIN,false);
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_TOKEN,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_ID,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_RONGCLOUD_ID,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_RONGCLOUD_TOKEN,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_INFO_AVATAR,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_NICKNAME,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_INFO_JSON_CONTENT,"");
AppConfig.USER_LOGIN = false;
AppConfig.USER_TOKEN = "";
AppConfig.RONG_CLOUD_TALK_TOKEN = "";
AppConfig.USER_ID = "";
AppConfig.USER_RONGCLOUD_ID = "";
}
}

View File

@@ -0,0 +1,563 @@
/*
* Copyright (C) 2013 readyState Software Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ckkj.water.utils.manager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout.LayoutParams;
import java.lang.reflect.Method;
/**
* Class to manage status and navigation bar tint effects when using KitKat
* translucent system UI modes.
*/
public class SystemBarTintManager {
static {
// Android allows a system property to override the presence of the navigation bar.
// Used by the emulator.
// See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Class c = Class.forName("android.os.SystemProperties");
Method m = c.getDeclaredMethod("get", String.class);
m.setAccessible(true);
sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
} catch (Throwable e) {
sNavBarOverride = null;
}
}
}
/**
* The default system bar tint color value.
*/
public static final int DEFAULT_TINT_COLOR = 0x99000000;
private static String sNavBarOverride;
private final SystemBarConfig mConfig;
private boolean mStatusBarAvailable;
private boolean mNavBarAvailable;
private boolean mStatusBarTintEnabled;
private boolean mNavBarTintEnabled;
private View mStatusBarTintView;
private View mNavBarTintView;
/**
* Constructor. Call this in the host activity onCreate method after its
* content view has been set. You should always create new instances when
* the host activity is recreated.
*
* @param activity The host activity.
*/
@TargetApi(19)
public SystemBarTintManager(Activity activity) {
Window win = activity.getWindow();
ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// check theme attrs
int[] attrs = {android.R.attr.windowTranslucentStatus,
android.R.attr.windowTranslucentNavigation};
TypedArray a = activity.obtainStyledAttributes(attrs);
try {
mStatusBarAvailable = a.getBoolean(0, false);
mNavBarAvailable = a.getBoolean(0, false);
} finally {
a.recycle();
}
// check window flags
WindowManager.LayoutParams winParams = win.getAttributes();
int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if ((winParams.flags & bits) != 0) {
mStatusBarAvailable = true;
}
bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
if ((winParams.flags & bits) != 0) {
mNavBarAvailable = true;
}
}
mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
// device might not have virtual navigation keys
if (!mConfig.hasNavigtionBar()) {
mNavBarAvailable = false;
}
if (mStatusBarAvailable) {
setupStatusBarView(activity, decorViewGroup);
}
if (mNavBarAvailable) {
setupNavBarView(activity, decorViewGroup);
}
}
/**
* Enable tinting of the system status bar.
* <p/>
* If the platform is running Jelly Bean or earlier, or translucent system
* UI modes have not been enabled in either the theme or via window flags,
* then this method does nothing.
*
* @param enabled True to enable tinting, false to disable it (default).
*/
public void setStatusBarTintEnabled(boolean enabled) {
mStatusBarTintEnabled = enabled;
if (mStatusBarAvailable) {
mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
}
/**
* Enable tinting of the system navigation bar.
* <p/>
* If the platform does not have soft navigation keys, is running Jelly Bean
* or earlier, or translucent system UI modes have not been enabled in either
* the theme or via window flags, then this method does nothing.
*
* @param enabled True to enable tinting, false to disable it (default).
*/
public void setNavigationBarTintEnabled(boolean enabled) {
mNavBarTintEnabled = enabled;
if (mNavBarAvailable) {
mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
}
/**
* Apply the specified color tint to all system UI bars.
*
* @param color The color of the background tint.
*/
public void setTintColor(int color) {
setStatusBarTintColor(color);
setNavigationBarTintColor(color);
}
/**
* Apply the specified drawable or color resource to all system UI bars.
*
* @param res The identifier of the resource.
*/
public void setTintResource(int res) {
setStatusBarTintResource(res);
setNavigationBarTintResource(res);
}
/**
* Apply the specified drawable to all system UI bars.
*
* @param drawable The drawable to use as the background, or null to remove it.
*/
public void setTintDrawable(Drawable drawable) {
setStatusBarTintDrawable(drawable);
setNavigationBarTintDrawable(drawable);
}
/**
* Apply the specified alpha to all system UI bars.
*
* @param alpha The alpha to use
*/
public void setTintAlpha(float alpha) {
setStatusBarAlpha(alpha);
setNavigationBarAlpha(alpha);
}
/**
* Apply the specified color tint to the system status bar.
*
* @param color The color of the background tint.
*/
public void setStatusBarTintColor(int color) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundColor(color);
}
}
/**
* Apply the specified drawable or color resource to the system status bar.
*
* @param res The identifier of the resource.
*/
public void setStatusBarTintResource(int res) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundResource(res);
}
}
/**
* Apply the specified drawable to the system status bar.
*
* @param drawable The drawable to use as the background, or null to remove it.
*/
@SuppressWarnings("deprecation")
public void setStatusBarTintDrawable(Drawable drawable) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundDrawable(drawable);
}
}
/**
* Apply the specified alpha to the system status bar.
*
* @param alpha The alpha to use
*/
@TargetApi(11)
public void setStatusBarAlpha(float alpha) {
if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mStatusBarTintView.setAlpha(alpha);
}
}
/**
* Apply the specified color tint to the system navigation bar.
*
* @param color The color of the background tint.
*/
public void setNavigationBarTintColor(int color) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundColor(color);
}
}
/**
* Apply the specified drawable or color resource to the system navigation bar.
*
* @param res The identifier of the resource.
*/
public void setNavigationBarTintResource(int res) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundResource(res);
}
}
/**
* Apply the specified drawable to the system navigation bar.
*
* @param drawable The drawable to use as the background, or null to remove it.
*/
@SuppressWarnings("deprecation")
public void setNavigationBarTintDrawable(Drawable drawable) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundDrawable(drawable);
}
}
/**
* Apply the specified alpha to the system navigation bar.
*
* @param alpha The alpha to use
*/
@TargetApi(11)
public void setNavigationBarAlpha(float alpha) {
if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mNavBarTintView.setAlpha(alpha);
}
}
/**
* Get the system bar configuration.
*
* @return The system bar configuration for the current device configuration.
*/
public SystemBarConfig getConfig() {
return mConfig;
}
/**
* Is tinting enabled for the system status bar?
*
* @return True if enabled, False otherwise.
*/
public boolean isStatusBarTintEnabled() {
return mStatusBarTintEnabled;
}
/**
* Is tinting enabled for the system navigation bar?
*
* @return True if enabled, False otherwise.
*/
public boolean isNavBarTintEnabled() {
return mNavBarTintEnabled;
}
private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
mStatusBarTintView = new View(context);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
params.gravity = Gravity.TOP;
if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
params.rightMargin = mConfig.getNavigationBarWidth();
}
mStatusBarTintView.setLayoutParams(params);
mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
mStatusBarTintView.setVisibility(View.GONE);
decorViewGroup.addView(mStatusBarTintView);
}
private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
mNavBarTintView = new View(context);
LayoutParams params;
if (mConfig.isNavigationAtBottom()) {
params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
params.gravity = Gravity.BOTTOM;
} else {
params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
params.gravity = Gravity.RIGHT;
}
mNavBarTintView.setLayoutParams(params);
mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
mNavBarTintView.setVisibility(View.GONE);
decorViewGroup.addView(mNavBarTintView);
}
/**
* Class which describes system bar sizing and other characteristics for the current
* device configuration.
*/
public static class SystemBarConfig {
private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
private final boolean mTranslucentStatusBar;
private final boolean mTranslucentNavBar;
private final int mStatusBarHeight;
private final int mActionBarHeight;
private final boolean mHasNavigationBar;
private final int mNavigationBarHeight;
private final int mNavigationBarWidth;
private final boolean mInPortrait;
private final float mSmallestWidthDp;
private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
Resources res = activity.getResources();
mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
mSmallestWidthDp = getSmallestWidthDp(activity);
mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
mActionBarHeight = getActionBarHeight(activity);
mNavigationBarHeight = getNavigationBarHeight(activity);
mNavigationBarWidth = getNavigationBarWidth(activity);
mHasNavigationBar = (mNavigationBarHeight > 0);
mTranslucentStatusBar = translucentStatusBar;
mTranslucentNavBar = traslucentNavBar;
}
@TargetApi(14)
private int getActionBarHeight(Context context) {
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
}
return result;
}
@TargetApi(14)
private int getNavigationBarHeight(Context context) {
Resources res = context.getResources();
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (hasNavBar(context)) {
String key;
if (mInPortrait) {
key = NAV_BAR_HEIGHT_RES_NAME;
} else {
key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
}
return getInternalDimensionSize(res, key);
}
}
return result;
}
@TargetApi(14)
private int getNavigationBarWidth(Context context) {
Resources res = context.getResources();
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (hasNavBar(context)) {
return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
}
}
return result;
}
@TargetApi(14)
private boolean hasNavBar(Context context) {
Resources res = context.getResources();
int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
if (resourceId != 0) {
boolean hasNav = res.getBoolean(resourceId);
// check override flag (see static block)
if ("1".equals(sNavBarOverride)) {
hasNav = false;
} else if ("0".equals(sNavBarOverride)) {
hasNav = true;
}
return hasNav;
} else { // fallback
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
}
private int getInternalDimensionSize(Resources res, String key) {
int result = 0;
int resourceId = res.getIdentifier(key, "dimen", "android");
if (resourceId > 0) {
result = res.getDimensionPixelSize(resourceId);
}
return result;
}
@SuppressLint("NewApi")
private float getSmallestWidthDp(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
} else {
// TODO this is not correct, but we don't really care pre-kitkat
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
}
float widthDp = metrics.widthPixels / metrics.density;
float heightDp = metrics.heightPixels / metrics.density;
return Math.min(widthDp, heightDp);
}
/**
* Should a navigation bar appear at the bottom of the screen in the current
* device configuration? A navigation bar may appear on the right side of
* the screen in certain configurations.
*
* @return True if navigation should appear at the bottom of the screen, False otherwise.
*/
public boolean isNavigationAtBottom() {
return (mSmallestWidthDp >= 600 || mInPortrait);
}
/**
* Get the height of the system status bar.
*
* @return The height of the status bar (in pixels).
*/
public int getStatusBarHeight() {
return mStatusBarHeight;
}
/**
* Get the height of the action bar.
*
* @return The height of the action bar (in pixels).
*/
public int getActionBarHeight() {
return mActionBarHeight;
}
/**
* Does this device have a system navigation bar?
*
* @return True if this device uses soft key navigation, False otherwise.
*/
public boolean hasNavigtionBar() {
return mHasNavigationBar;
}
/**
* Get the height of the system navigation bar.
*
* @return The height of the navigation bar (in pixels). If the device does not have
* soft navigation keys, this will always return 0.
*/
public int getNavigationBarHeight() {
return mNavigationBarHeight;
}
/**
* Get the width of the system navigation bar when it is placed vertically on the screen.
*
* @return The width of the navigation bar (in pixels). If the device does not have
* soft navigation keys, this will always return 0.
*/
public int getNavigationBarWidth() {
return mNavigationBarWidth;
}
/**
* Get the layout inset for any system UI that appears at the top of the screen.
*
* @param withActionBar True to include the height of the action bar, False otherwise.
* @return The layout inset (in pixels).
*/
public int getPixelInsetTop(boolean withActionBar) {
return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
}
/**
* Get the layout inset for any system UI that appears at the bottom of the screen.
*
* @return The layout inset (in pixels).
*/
public int getPixelInsetBottom() {
if (mTranslucentNavBar && isNavigationAtBottom()) {
return mNavigationBarHeight;
} else {
return 0;
}
}
/**
* Get the layout inset for any system UI that appears at the right of the screen.
*
* @return The layout inset (in pixels).
*/
public int getPixelInsetRight() {
if (mTranslucentNavBar && !isNavigationAtBottom()) {
return mNavigationBarWidth;
} else {
return 0;
}
}
}
}

View File

@@ -0,0 +1,125 @@
package com.ckkj.water.utils.number;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.DigitsKeyListener;
import java.math.BigDecimal;
/**
* @author: dz
* @date: 2022/5/9
* 描述:
*/
public class NumberDecimalFilter extends DigitsKeyListener {
public NumberDecimalFilter() {
super(false, true);
}
/**
* 默认保留 2 位置小数点
*/
private int digits = 2;
public NumberDecimalFilter setDigits(int d) {
digits = d;
return this;
}
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
CharSequence out = super.filter(source, start, end, dest, dstart, dend);
if (out != null) {
source = out;
start = 0;
end = out.length();
}
int len = end - start;
if (len == 0) {
return source;
}
//以点开始的时候自动在前面添加0
if (source.toString().equals(".") && dstart == 0) {
return "0.";
}
//如果起始位置为0,且第二位跟的不是".",则无法后续输入
if (!source.toString().equals(".") && dest.toString().equals("0")) {
return "";
}
int dlen = dest.length();
for (int i = 0; i < dstart; i++) {
if (dest.charAt(i) == '.') {
return (dlen - (i + 1) + len > digits) ? "" : new SpannableStringBuilder(source, start, end);
}
}
for (int i = start; i < end; ++i) {
if (source.charAt(i) == '.') {
if ((dlen - dend) + (end - (i + 1)) > digits)
return "";
else
break;
}
}
return new SpannableStringBuilder(source, start, end);
}
public static double roundToTwoDecimalPlaces(double value) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP); // 四舍五入保留两位
return bd.doubleValue();
}
public static String truncateToTwoDecimal(double value) {
String str = String.valueOf(value);
int index = str.indexOf(".");
if (index != -1 && str.length() > index + 2) {
return str.substring(0, index + 3); // 截取小数点后两位
} else {
return str; // 没有超过两位,不截取
}
}
}

View File

@@ -0,0 +1,85 @@
package com.ckkj.water.utils.number;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.util.Patterns;
import android.view.View;
import androidx.annotation.NonNull;
import com.ckkj.water.R;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-04-2025 周五 17:06
*/
public class PhoneNumberUtils {
public static boolean checkPhoneNum(String num){
String regex = "^1[3-9]\\d{9}$";
boolean isValid = Pattern.matches(regex, num);
return isValid;
}
public static String hidePhoneNumber(String phone) {
if (phone == null || phone.length() != 11) {
return phone; // 长度不对直接返回原字符串
}
return phone.substring(0, 3) + "****" + phone.substring(7);
}
public static SpannableString getClickablePhoneText(Context context, String messageText) {
SpannableString spannable = new SpannableString(messageText);
Pattern phonePattern = Pattern.compile("\\b1[3-9]\\d{9}\\b");
Matcher matcher = phonePattern.matcher(messageText);
while (matcher.find()) {
final String phone = matcher.group();
int start = matcher.start();
int end = matcher.end();
// 设置蓝色文字和点击事件
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone));
context.startActivity(intent);
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(context.getColor(R.color.color_zhu)); // 蓝色
ds.setUnderlineText(false); // 不下划线
}
};
spannable.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return spannable;
}
// 校验邮箱
public static boolean checkEmail(String email) {
if (TextUtils.isEmpty(email)) {
return false;
}
return Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
}

View File

@@ -0,0 +1,255 @@
package com.ckkj.water.utils.oss;
import android.content.Context;
import android.util.Log;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSAuthCredentialsProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.ckkj.water.AppConfig;
import com.ckkj.water.base.inter.UploadCallback;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-07-2025 周一 18:12
*/
public class OssUploadHelper {
private Context mContext;
public static String ALIYUN_ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";
private String accessKeyId = "LTAI5tEytdKbh9sYtcANcPW3";
private String accessKeySecret = "3jz6F07bERFSsNtrpCjRo2ZaygsvuE";
public OssUploadHelper(Context context) {
this.mContext = context;
}
public OSS getOSSClient() {
OSSAuthCredentialsProvider authCredentialsProvider =
new OSSAuthCredentialsProvider("https://gw.dingdingche.net/mine/api/sts-token");
OSS oss = new OSSClient(mContext, AppConfig.ALIYUN_ENDPOINT, authCredentialsProvider);
return oss;
}
/**
* 上传方法(支持单图和多图)
*
* @param uploadCode 上传类型
* @param objectKey 标识(文件名基准,可以不带后缀)
* @param imagePaths 图片路径集合
* @param callback 上传回调
* @return 如果是单图,返回该图片的外网访问路径;多图时返回第一张的路径
*/
public String upload(int uploadCode, String objectKey, List<String> imagePaths, UploadCallback callback) {
if (imagePaths == null || imagePaths.isEmpty()) {
if (callback != null) {
callback.onFailure(new ClientException("没有可上传的文件"), null);
}
return null;
}
// 用固定的 AccessKeyId + AccessKeySecret 创建凭证
OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(accessKeyId, accessKeySecret);
OSS client = new OSSClient(mContext, ALIYUN_ENDPOINT, credentialProvider);
String uploadFolder = getUploadPath(uploadCode);
List<String> uploadedUrls = new ArrayList<>();
AtomicInteger counter = new AtomicInteger(0);
// 遍历图片上传
for (int i = 0; i < imagePaths.size(); i++) {
String imagePath = imagePaths.get(i);
String newObjectKey = "";
if(uploadCode == AppConfig.UPLOAD_TYPE_100){
// 每张图片命名用户ID
newObjectKey = renameWithSameExtension(objectKey,
AppConfig.USER_ID);
}else{
newObjectKey = renameWithSameExtension(objectKey,
String.valueOf(System.currentTimeMillis()));
}
newObjectKey = uploadFolder + newObjectKey;
PutObjectRequest request = new PutObjectRequest(AppConfig.ALIYUN_BUCKETNAME, newObjectKey, imagePath);
String finalObjectKey = newObjectKey;
client.asyncPutObject(request, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
@Override
public void onSuccess(PutObjectRequest request, PutObjectResult result) {
String imageUrl = AppConfig.ALI_OSS_CAR_BRAND_LOGO + finalObjectKey;
uploadedUrls.add(imageUrl);
if (counter.incrementAndGet() == imagePaths.size()) {
// 所有文件都上传完成
if (callback != null) {
callback.onSuccess(uploadedUrls);
}
}
}
@Override
public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
if (callback != null) {
callback.onFailure(clientExcepion, serviceException);
}
}
});
}
// 返回第一张图片的预签名 URL单图就是这张多图仅做参考
try {
String firstObjectKey = uploadFolder + renameWithSameExtension(objectKey,
AppConfig.USER_ID + "_" + System.currentTimeMillis() + "_0");
String url = client.presignConstrainedObjectURL(AppConfig.ALIYUN_BUCKETNAME, firstObjectKey,
3600L * 1000 * 24 * 365);
Log.e("oss==zhs", String.format("PublicObjectURL:%s", url));
return url;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// public String upload(int uploadCode, String objectKey, List<String> imagePaths, UploadCallback callback) {
// if (imagePaths == null || imagePaths.isEmpty()) {
// if (callback != null) {
// callback.onFailure(new ClientException("没有可上传的文件"), null);
// }
// return null;
// }
//
// OSS client = getOSSClient();
// String uploadFolder = getUploadPath(uploadCode);
// List<String> uploadedUrls = new ArrayList<>();
// AtomicInteger counter = new AtomicInteger(0);
//
// for (int i = 0; i < imagePaths.size(); i++) {
// String imagePath = imagePaths.get(i);
//
// // 每张图片的文件名都加时间戳和序号,避免覆盖
// String newObjectKey = renameWithSameExtension(objectKey, AppConfig.USER_ID + "_" + System.currentTimeMillis() + "_" + i);
// newObjectKey = uploadFolder + newObjectKey;
//
// PutObjectRequest request = new PutObjectRequest(AppConfig.ALIYUN_BUCKETNAME, newObjectKey, imagePath);
// String finalObjectKey = newObjectKey;
//
// client.asyncPutObject(request, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
// @Override
// public void onSuccess(PutObjectRequest request, PutObjectResult result) {
// String imageUrl = AppConfig.ALI_OSS_CAR_BRAND_LOGO + finalObjectKey;
// uploadedUrls.add(imageUrl);
//
// if (counter.incrementAndGet() == imagePaths.size()) {
// // 所有文件都上传完成
// if (callback != null) {
// callback.onSuccess(uploadedUrls);
// }
// }
// }
//
// @Override
// public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
// if (callback != null) {
// callback.onFailure(clientExcepion, serviceException);
// }
// }
// });
// }
//
// // 返回第一张图片的预签名 URL单图就是这张多图仅做参考
// try {
// String firstObjectKey = uploadFolder + renameWithSameExtension(objectKey, AppConfig.USER_ID + "_" + System.currentTimeMillis() + "_0");
// String url = client.presignConstrainedObjectURL(AppConfig.ALIYUN_BUCKETNAME, firstObjectKey, 3600L * 1000 * 24 * 365);
// Log.e("oss==zhs", String.format("PublicObjectURL:%s", url));
// return url;
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// }
// public void uploadImages(int uploadCode, List<String> imagePaths, OSS ossClient, UploadCallback callback) {
// String uploadFolder = getUploadPath(uploadCode);
// List<String> uploadedUrls = new ArrayList<>();
// AtomicInteger counter = new AtomicInteger(0);
//
// for (String imagePath : imagePaths) {
// // 自己定义objectKey比如可以是时间戳+随机数
// String objectKey = uploadFolder + System.currentTimeMillis() + "_" + new File(imagePath).getName();
//
// PutObjectRequest put = new PutObjectRequest(AppConfig.ALIYUN_BUCKETNAME, objectKey, imagePath);
//
// ossClient.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
// @Override
// public void onSuccess(PutObjectRequest request, PutObjectResult result) {
// String imageUrl = AppConfig.ALI_OSS_CAR_BRAND_LOGO + objectKey;
//// String imageUrl = ossClient.presignConstrainedObjectURL(AppConfig.ALIYUN_BUCKETNAME, objectKey, 3600L * 1000 * 24 * 365);
// uploadedUrls.add(imageUrl);
// if (counter.incrementAndGet() == imagePaths.size()) {
// // 全部上传完成
// callback.onSuccess(uploadedUrls);
// }
// }
//
// @Override
// public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
// callback.onFailure(clientExcepion, serviceException);
// }
// });
// }
// }
private String getUploadPath(int uploadType){
String folder = "";
switch (uploadType){
case AppConfig.UPLOAD_TYPE_100:
folder = "headShot/";
break;
case AppConfig.UPLOAD_TYPE_200:
folder = "CarRimPicture/";
break;
case AppConfig.UPLOAD_TYPE_300:
folder = "SocialCircle/";
break;
case AppConfig.UPLOAD_TYPE_400:
folder = "Feedback/";
break;
}
return folder;
}
public static String renameWithSameExtension(String originalName, String newBaseName) {
int dotIndex = originalName.lastIndexOf('.');
if (dotIndex != -1 && dotIndex < originalName.length() - 1) {
String extension = originalName.substring(dotIndex); // 包含 . 比如 ".jpg"
return newBaseName + extension;
} else {
// 没有后缀的情况
return newBaseName;
}
}
}

View File

@@ -0,0 +1,44 @@
package com.ckkj.water.utils.permissions;
import android.app.AlertDialog;
import android.content.DialogInterface;
import androidx.appcompat.app.AppCompatActivity;
/**
* <pre>
* .----.
* _.'__ `.
* .--(Q)(OK)---/$\
* .' @ /$$$\
* : , $$$$$
* `-..__.-' _.-\$$$/
* `;_: `"'
* .'"""""`.
* /, FLY ,\
* // \\
* `-._______.-'
* ___`. | .'___
* (______|______)
* </pre>
* 包 名 : com.fly.fengtaobao.utils
* 作 者 : FLY
* 创建时间 : 2017/8/4
* <p>
* 描述: Dialog工具类
*/
public class LibDialogUtils {
public static void showPermissionTipsDialog(final AppCompatActivity activity){
new AlertDialog.Builder(activity)
.setTitle("需要申请权限")
.setMessage("是否接受权限申请")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PermissionUtils.startAppSettings(activity);
}
}).show();
}
}

View File

@@ -0,0 +1,284 @@
package com.ckkj.water.utils.permissions;
/**
* @author: dz
* @date: 2024/1/4
* 描述:
*/
import com.hjq.toast.Toaster;
import com.ckkj.water.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hjq.permissions.IPermissionInterceptor;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.OnPermissionPageCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.PermissionFragment;
import com.hjq.permissions.XXPermissions;
import java.util.ArrayList;
import java.util.List;
/**
* Created on 2022/9/15 16:05
* 权限申请拦截器
* @author Gong Youqiang
*/
public final class PermissionInterceptor implements IPermissionInterceptor {
public static final Handler HANDLER = new Handler(Looper.getMainLooper());
/** 权限申请标记 */
private boolean mRequestFlag;
/** 权限申请说明 Popup */
private PopupWindow mPermissionPopup;
@Override
public void launchPermissionRequest(@NonNull Activity activity, @NonNull List<String> allPermissions, @Nullable OnPermissionCallback callback) {
mRequestFlag = true;
List<String> deniedPermissions = XXPermissions.getDenied(activity, allPermissions);
String message = activity.getString(R.string.common_permission_message, PermissionNameConvert.getPermissionString(activity, deniedPermissions));
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
int activityOrientation = activity.getResources().getConfiguration().orientation;
boolean showPopupWindow = activityOrientation == Configuration.ORIENTATION_PORTRAIT;
for (String permission : allPermissions) {
if (!XXPermissions.isSpecial(permission)) {
continue;
}
if (XXPermissions.isGranted(activity, permission)) {
continue;
}
if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R &&
TextUtils.equals(Permission.MANAGE_EXTERNAL_STORAGE, permission)) {
continue;
}
// 如果申请的权限带有特殊权限,并且还没有授予的话
// 就不用 PopupWindow 对话框来显示,而是用 Dialog 来显示
showPopupWindow = false;
break;
}
showPopupWindow = false;
if (showPopupWindow) {
PermissionFragment.launch(activity, new ArrayList<>(allPermissions), this, callback);
// 延迟 300 毫秒是为了避免出现 PopupWindow 显示然后立马消失的情况
// 因为框架没有办法在还没有申请权限的情况下,去判断权限是否永久拒绝了,必须要在发起权限申请之后
// 所以只能通过延迟显示 PopupWindow 来做这件事,如果 300 毫秒内权限申请没有结束,证明本次申请的权限没有永久拒绝
HANDLER.postDelayed(() -> {
if (!mRequestFlag) {
return;
}
if (activity.isFinishing() ||
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
showPopupWindow(activity, decorView, message);
}, 300);
} else {
// 注意:这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期
new AlertDialog.Builder(activity)
.setTitle(R.string.common_permission_description)
.setMessage(message)
.setCancelable(false)
.setPositiveButton(R.string.common_permission_granted, (dialog, which) -> {
dialog.dismiss();
PermissionFragment.launch(activity, new ArrayList<>(allPermissions),
PermissionInterceptor.this, callback);
})
.setNegativeButton(R.string.common_permission_denied, (dialog, which) -> {
dialog.dismiss();
if (callback == null) {
return;
}
callback.onDenied(deniedPermissions, false);
})
.show();
}
}
@Override
public void grantedPermissionRequest(@NonNull Activity activity, @NonNull List<String> allPermissions,
@NonNull List<String> grantedPermissions, boolean allGranted,
@Nullable OnPermissionCallback callback) {
if (callback == null) {
return;
}
callback.onGranted(grantedPermissions, allGranted);
}
@Override
public void deniedPermissionRequest(@NonNull Activity activity, @NonNull List<String> allPermissions,
@NonNull List<String> deniedPermissions, boolean doNotAskAgain,
@Nullable OnPermissionCallback callback) {
if (callback != null) {
callback.onDenied(deniedPermissions, doNotAskAgain);
}
if (doNotAskAgain) {
if (deniedPermissions.size() == 1 && Permission.ACCESS_MEDIA_LOCATION.equals(deniedPermissions.get(0))) {
Toaster.show(R.string.common_permission_media_location_hint_fail);
return;
}
showPermissionSettingDialog(activity, allPermissions, deniedPermissions, callback);
return;
}
if (deniedPermissions.size() == 1) {
String deniedPermission = deniedPermissions.get(0);
String backgroundPermissionOptionLabel = getBackgroundPermissionOptionLabel(activity);
if (Permission.ACCESS_BACKGROUND_LOCATION.equals(deniedPermission)) {
Toaster.show(activity.getString(R.string.common_permission_background_location_fail_hint, backgroundPermissionOptionLabel));
return;
}
if (Permission.BODY_SENSORS_BACKGROUND.equals(deniedPermission)) {
Toaster.show(activity.getString(R.string.common_permission_background_sensors_fail_hint, backgroundPermissionOptionLabel));
return;
}
}
final String message;
List<String> permissionNames = PermissionNameConvert.permissionsToNames(activity, deniedPermissions);
if (!permissionNames.isEmpty()) {
message = activity.getString(R.string.common_permission_fail_assign_hint,
PermissionNameConvert.listToString(activity, permissionNames));
} else {
message = activity.getString(R.string.common_permission_fail_hint);
}
// Toaster.show(message);
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
}
@Override
public void finishPermissionRequest(@NonNull Activity activity, @NonNull List<String> allPermissions,
boolean skipRequest, @Nullable OnPermissionCallback callback) {
mRequestFlag = false;
dismissPopupWindow();
}
private void showPopupWindow(Activity activity, ViewGroup decorView, String message) {
if (mPermissionPopup == null) {
View contentView = LayoutInflater.from(activity)
.inflate(R.layout.permission_description_popup, decorView, false);
mPermissionPopup = new PopupWindow(activity);
mPermissionPopup.setContentView(contentView);
mPermissionPopup.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
mPermissionPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
mPermissionPopup.setAnimationStyle(android.R.style.Animation_Dialog);
mPermissionPopup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mPermissionPopup.setTouchable(true);
mPermissionPopup.setOutsideTouchable(true);
}
TextView messageView = mPermissionPopup.getContentView().findViewById(R.id.tv_permission_description_message);
messageView.setText(message);
// 注意:这里的 PopupWindow 只是示例,没有监听 Activity onDestroy 来处理 PopupWindow 生命周期
mPermissionPopup.showAtLocation(decorView, Gravity.TOP, 0, 0);
}
private void dismissPopupWindow() {
if (mPermissionPopup == null) {
return;
}
if (!mPermissionPopup.isShowing()) {
return;
}
mPermissionPopup.dismiss();
}
private void showPermissionSettingDialog(Activity activity, List<String> allPermissions,
List<String> deniedPermissions, OnPermissionCallback callback) {
if (activity == null || activity.isFinishing() ||
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
String message = null;
List<String> permissionNames = PermissionNameConvert.permissionsToNames(activity, deniedPermissions);
if (!permissionNames.isEmpty()) {
if (deniedPermissions.size() == 1) {
String deniedPermission = deniedPermissions.get(0);
if (Permission.ACCESS_BACKGROUND_LOCATION.equals(deniedPermission)) {
message = activity.getString(R.string.common_permission_manual_assign_fail_background_location_hint, getBackgroundPermissionOptionLabel(activity));
} else if (Permission.BODY_SENSORS_BACKGROUND.equals(deniedPermission)) {
message = activity.getString(R.string.common_permission_manual_assign_fail_background_sensors_hint, getBackgroundPermissionOptionLabel(activity));
}
}
if (TextUtils.isEmpty(message)) {
message = activity.getString(R.string.common_permission_manual_assign_fail_hint,
PermissionNameConvert.listToString(activity, permissionNames));
}
} else {
message = activity.getString(R.string.common_permission_manual_fail_hint);
}
// 这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期
new AlertDialog.Builder(activity)
.setTitle(R.string.common_permission_alert)
.setMessage(message)
.setPositiveButton(R.string.common_permission_goto_setting_page, (dialog, which) -> {
dialog.dismiss();
XXPermissions.startPermissionActivity(activity,
deniedPermissions, new OnPermissionPageCallback() {
@Override
public void onGranted() {
if (callback == null) {
return;
}
callback.onGranted(allPermissions, true);
}
@Override
public void onDenied() {
showPermissionSettingDialog(activity, allPermissions,
XXPermissions.getDenied(activity, allPermissions), callback);
}
});
})
.show();
}
/**
* 获取后台权限的《始终允许》选项的文案
*/
@NonNull
private String getBackgroundPermissionOptionLabel(Context context) {
String backgroundPermissionOptionLabel = "";
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
backgroundPermissionOptionLabel = String.valueOf(context.getPackageManager().getBackgroundPermissionOptionLabel());
}
if (TextUtils.isEmpty(backgroundPermissionOptionLabel)) {
backgroundPermissionOptionLabel = context.getString(R.string.common_permission_background_default_option_label);
}
return backgroundPermissionOptionLabel;
}
}

View File

@@ -0,0 +1,338 @@
package com.ckkj.water.utils.permissions;
/**
* @author: dz
* @date: 2024/1/4
* 描述:
*/
import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull;
import com.hjq.permissions.Permission;
import com.ckkj.water.R;
import java.util.ArrayList;
import java.util.List;
/**
* Created on 2022/9/15 16:07
* 权限名称转换器
* @author Gong Youqiang
*/
public final class PermissionNameConvert {
/**
* 获取权限名称
*/
public static String getPermissionString(Context context, List<String> permissions) {
return listToString(context, permissionsToNames(context, permissions));
}
/**
* String 列表拼接成一个字符串
*/
public static String listToString(Context context, List<String> hints) {
if (hints == null || hints.isEmpty()) {
return context.getString(R.string.common_permission_unknown);
}
StringBuilder builder = new StringBuilder();
for (String text : hints) {
if (builder.length() == 0) {
builder.append(text);
} else {
builder.append("")
.append(text);
}
}
return builder.toString();
}
/**
* 将权限列表转换成对应名称列表
*/
@NonNull
public static List<String> permissionsToNames(Context context, List<String> permissions) {
List<String> permissionNames = new ArrayList<>();
if (context == null) {
return permissionNames;
}
if (permissions == null) {
return permissionNames;
}
for (String permission : permissions) {
switch (permission) {
case Permission.READ_EXTERNAL_STORAGE:
case Permission.WRITE_EXTERNAL_STORAGE: {
String hint = context.getString(R.string.common_permission_storage);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_MEDIA_IMAGES:
case Permission.READ_MEDIA_VIDEO:
case Permission.READ_MEDIA_VISUAL_USER_SELECTED:{
if (Build.VERSION.SDK_INT >= 33) {
String hint = context.getString(R.string.common_permission_image_and_video);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.READ_MEDIA_AUDIO: {
if (Build.VERSION.SDK_INT >=33) {
String hint = context.getString(R.string.common_permission_music_and_audio);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.CAMERA: {
String hint = context.getString(R.string.common_permission_camera);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.RECORD_AUDIO: {
String hint = context.getString(R.string.common_permission_microphone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_FINE_LOCATION:
case Permission.ACCESS_COARSE_LOCATION:
case Permission.ACCESS_BACKGROUND_LOCATION: {
String hint;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
!permissions.contains(Permission.ACCESS_FINE_LOCATION) &&
!permissions.contains(Permission.ACCESS_COARSE_LOCATION)) {
hint = context.getString(R.string.common_permission_location_background);
} else {
hint = context.getString(R.string.common_permission_location);
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BODY_SENSORS:
case Permission.BODY_SENSORS_BACKGROUND: {
String hint;
if (Build.VERSION.SDK_INT >= 33 &&
!permissions.contains(Permission.BODY_SENSORS)) {
hint = context.getString(R.string.common_permission_body_sensors_background);
} else {
hint = context.getString(R.string.common_permission_body_sensors);
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BLUETOOTH_SCAN:
case Permission.BLUETOOTH_CONNECT:
case Permission.BLUETOOTH_ADVERTISE: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String hint = context.getString(R.string.common_permission_nearby_devices);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.NEARBY_WIFI_DEVICES: {
if (Build.VERSION.SDK_INT >= 33) {
String hint = context.getString(R.string.common_permission_nearby_devices);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.READ_PHONE_STATE:
case Permission.CALL_PHONE:
case Permission.ADD_VOICEMAIL:
case Permission.USE_SIP:
case Permission.READ_PHONE_NUMBERS:
case Permission.ANSWER_PHONE_CALLS: {
String hint = context.getString(R.string.common_permission_phone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.GET_ACCOUNTS:
case Permission.READ_CONTACTS:
case Permission.WRITE_CONTACTS: {
String hint = context.getString(R.string.common_permission_contacts);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_CALENDAR:
case Permission.WRITE_CALENDAR: {
String hint = context.getString(R.string.common_permission_calendar);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_CALL_LOG:
case Permission.WRITE_CALL_LOG:
case Permission.PROCESS_OUTGOING_CALLS: {
String hint = context.getString(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
R.string.common_permission_call_logs :
R.string.common_permission_phone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACTIVITY_RECOGNITION: {
String hint = context.getString(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ?
R.string.common_permission_activity_recognition_api30 :
R.string.common_permission_activity_recognition_api29);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_MEDIA_LOCATION: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
String hint = context.getString(R.string.common_permission_access_media_location);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.SEND_SMS:
case Permission.RECEIVE_SMS:
case Permission.READ_SMS:
case Permission.RECEIVE_WAP_PUSH:
case Permission.RECEIVE_MMS: {
String hint = context.getString(R.string.common_permission_sms);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.MANAGE_EXTERNAL_STORAGE: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
String hint = context.getString(R.string.common_permission_all_file_access);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.REQUEST_INSTALL_PACKAGES: {
String hint = context.getString(R.string.common_permission_install_unknown_apps);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.SYSTEM_ALERT_WINDOW: {
String hint = context.getString(R.string.common_permission_display_over_other_apps);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.WRITE_SETTINGS: {
String hint = context.getString(R.string.common_permission_modify_system_settings);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.NOTIFICATION_SERVICE: {
String hint = context.getString(R.string.common_permission_allow_notifications);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.POST_NOTIFICATIONS: {
if (Build.VERSION.SDK_INT >= 33) {
String hint = context.getString(R.string.common_permission_post_notifications);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.BIND_NOTIFICATION_LISTENER_SERVICE: {
String hint = context.getString(R.string.common_permission_allow_notifications_access);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.PACKAGE_USAGE_STATS: {
String hint = context.getString(R.string.common_permission_apps_with_usage_access);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.SCHEDULE_EXACT_ALARM: {
String hint = context.getString(R.string.common_permission_alarms_reminders);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_NOTIFICATION_POLICY: {
String hint = context.getString(R.string.common_permission_do_not_disturb_access);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS: {
String hint = context.getString(R.string.common_permission_ignore_battery_optimize);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BIND_VPN_SERVICE: {
String hint = context.getString(R.string.common_permission_vpn);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.PICTURE_IN_PICTURE: {
String hint = context.getString(R.string.common_permission_picture_in_picture);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.GET_INSTALLED_APPS: {
String hint = context.getString(R.string.common_permission_get_installed_apps);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
default:
break;
}
}
return permissionNames;
}
}

View File

@@ -0,0 +1,106 @@
package com.ckkj.water.utils.permissions;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
/**
* <pre>
* .----.
* _.'__ `.
* .--(Q)(OK)---/$\
* .' @ /$$$\
* : , $$$$$
* `-..__.-' _.-\$$$/
* `;_: `"'
* .'"""""`.
* /, FLY ,\
* // \\
* `-._______.-'
* ___`. | .'___
* (______|______)
* </pre>
* 包 名 : com.fly.fengtaobao.utils
* 作 者 : FLY
* 创建时间 : 2017/8/3
* <p>
* 描述: 动态获取权限
*/
public class PermissionUtils {
public static final int SETTING_REQUEST_CODE = 1111;
/**
* 获取请求权限中需要授权的权限
*
* @param permissions 一个或多个权限
*/
public static List<String> getDeniedPermissions(Context context, String... permissions) {
List<String> deniedPermissions = new ArrayList<String>();
for (String permission : permissions) {
//判断权限是否授予
if (ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_DENIED) {
deniedPermissions.add(permission);
}
}
return deniedPermissions;
}
/**
* 授权权限
*/
@TargetApi(Build.VERSION_CODES.M)
public static boolean isPermissionsGranted(AppCompatActivity activity,
int permission_request_code, String... permissions) {
List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(activity, permissions);
if (deniedPermissions != null && deniedPermissions.size() > 0) {
activity.requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]),
permission_request_code);
//授权Activity回调
} else {
//权限通过
return true;
}
return false;
}
/**
* 验证所有权限是否都已经授权
*/
public static boolean verifyPermissions(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
return false;
}
}
return true;
}
/**
* 显示提示对话框
*/
public static void showTipsDialog(AppCompatActivity context) {
LibDialogUtils.showPermissionTipsDialog(context);
}
public static void startAppSettings(AppCompatActivity context) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
//得到新打开Activity关闭后返回的数据
//第二个参数为请求码,可以根据业务需求自己编号
context.startActivityForResult(intent, SETTING_REQUEST_CODE);
context.startActivity(intent);
}
}

View File

@@ -0,0 +1,221 @@
package com.ckkj.water.utils.show;
import android.util.Log;
import com.ckkj.water.utils.CalendarUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by “AriaLyy@outlook.com” on 2015/4/1.
* 写入文件的log由于使用到反射和文件流的操作建议在需要的地方才去使用
*/
public class FL {
public static boolean isDebug = true;// 是否需要打印bug可以在application的onCreate函数里面初始化
public static String PATH = "/GameBar2/log/AriaFrameLog__"; //log路径
static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
static int JSON_INDENT = 4;
private static String printLine(String tag, boolean isTop) {
String top =
"╔══════════════════════════════════════════ JSON ═══════════════════════════════════════";
String bottom =
"╚═══════════════════════════════════════════════════════════════════════════════════════";
if (isTop) {
Log.d(tag, top);
return top;
} else {
Log.d(tag, bottom);
return bottom;
}
}
/**
* 打印JSON
*/
public static void j(String tag, String jsonStr) {
if (isDebug) {
String message;
try {
if (jsonStr.startsWith("{")) {
JSONObject jsonObject = new JSONObject(jsonStr);
message = jsonObject.toString(JSON_INDENT); //这个是核心方法
} else if (jsonStr.startsWith("[")) {
JSONArray jsonArray = new JSONArray(jsonStr);
message = jsonArray.toString(JSON_INDENT);
} else {
message = jsonStr;
}
} catch (JSONException e) {
message = jsonStr;
}
message = LINE_SEPARATOR + message;
String temp = "\n" + printLine(tag, true) + "\n";
String[] lines = message.split(LINE_SEPARATOR);
for (String line : lines) {
temp += "" + line + "\n";
Log.d(tag, "" + line);
}
temp += printLine(tag, false);
writeLogToFile(tag, temp);
}
}
// 下面四个是默认tag的函数
public static void i(Object obj, String msg) {
String TAG = getTag(obj);
if (isDebug) {
Log.i(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void d(Object obj, String msg) {
String TAG = getTag(obj);
if (isDebug) {
Log.d(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void e(Object obj, String msg) {
String TAG = getTag(obj);
if (isDebug) {
Log.e(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void v(Object obj, String msg) {
String TAG = getTag(obj);
if (isDebug) {
Log.v(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void i(String TAG, String msg) {
if (isDebug) {
Log.i(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void d(String TAG, String msg) {
if (isDebug) {
Log.d(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void e(String TAG, String msg) {
if (isDebug) {
Log.e(TAG, msg);
writeLogToFile(TAG, msg);
}
}
public static void v(String TAG, String msg) {
if (isDebug) {
Log.v(TAG, msg);
writeLogToFile(TAG, msg);
}
}
/**
* 获取类名
*/
private static String getTag(Object object) {
Class<?> cls = object.getClass();
String tag = cls.getName();
String arrays[] = tag.split("\\.");
tag = arrays[arrays.length - 1];
return tag;
}
/**
* 返回日志路径
*/
public static String getLogPath() {
String path = android.os.Environment.getExternalStorageDirectory().getPath()
+ File.separator
+ PATH
+ CalendarUtils.getData()
+ ".log";
File log = new File(path);
if (!log.getParentFile().exists()) {
log.getParentFile().mkdirs();
}
if (!log.exists()) {
try {
log.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return path;
}
/**
* 把日志记录到文件
*/
private static int writeLogToFile(String tag, String message) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(CalendarUtils.getNowDataTime());
stringBuffer.append(" ");
stringBuffer.append(tag);
stringBuffer.append(" ");
stringBuffer.append(message);
stringBuffer.append("\n");
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(getLogPath(), true));
writer.append(stringBuffer);
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
return 0;
}
/**
* 将异常信息转换为字符串
*/
public static String getExceptionString(Throwable ex) {
StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n");
err.append(ex.toString());
err.append("\n");
StackTraceElement[] stack = ex.getStackTrace();
for (StackTraceElement stackTraceElement : stack) {
err.append(stackTraceElement.toString()).append("\n");
}
Throwable cause = ex.getCause();
if (cause != null) {
err.append("【Caused by】: ");
err.append(cause.toString());
err.append("\n");
StackTraceElement[] stackTrace = cause.getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
err.append(stackTraceElement.toString()).append("\n");
}
}
err.append("===================================================");
return err.toString();
}
}

View File

@@ -0,0 +1,263 @@
package com.ckkj.water.utils.show;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Map;
import java.util.Set;
/**
* Created by “AriaLyy@outlook.com” on 2015/4/1.
* 普通的Log管理类
*/
public class L {
/**
* Drawing toolbox
*/
private static final char TOP_LEFT_CORNER = '╔';
private static final char BOTTOM_LEFT_CORNER = '╚';
private static final char MIDDLE_CORNER = '╟';
private static final char HORIZONTAL_DOUBLE_LINE = '║';
private static final String DOUBLE_DIVIDER =
"════════════════════════════════════════════";
private static final String SINGLE_DIVIDER =
"────────────────────────────────────────────";
private static final String TOP_BORDER =
TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
private static final String BOTTOM_BORDER =
BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
private static final String MIDDLE_BORDER =
MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;
private static final char I = 'I', W = 'W', D = 'D', E = 'E', V = 'V', A =
'A', M = 'M';
private static final String TAG = "lyy";
static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
static int JSON_INDENT = 4;
private L() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* map to str
*/
public static String m2s(Map map) {
if (FL.isDebug) {
if (map == null) {
return "";
}
StringBuilder sb = new StringBuilder();
Set set = map.entrySet();
for (Object aSet : set) {
Map.Entry entry = (Map.Entry) aSet;
sb.append(entry.getValue());
}
return sb.toString();
}
return "";
}
/**
* 打印MAp
*/
public static void m(Map map) {
if (FL.isDebug) {
Set set = map.entrySet();
if (set.size() < 1) {
printLog(D, "[]");
return;
}
int i = 0;
String[] s = new String[set.size()];
for (Object aSet : set) {
Map.Entry entry = (Map.Entry) aSet;
s[i] = entry.getKey() + " = " + entry.getValue() + ",\n";
i++;
}
printLog(V, s);
}
}
/**
* 打印JSON
*/
public static void j(String jsonStr) {
if (FL.isDebug) {
String message;
try {
if (jsonStr.startsWith("{")) {
JSONObject jsonObject = new JSONObject(jsonStr);
message = jsonObject.toString(JSON_INDENT); //这个是核心方法
} else if (jsonStr.startsWith("[")) {
JSONArray jsonArray = new JSONArray(jsonStr);
message = jsonArray.toString(JSON_INDENT);
} else {
message = jsonStr;
}
} catch (JSONException e) {
message = jsonStr;
}
message = LINE_SEPARATOR + message;
String[] lines = message.split(LINE_SEPARATOR);
printLog(D, lines);
}
}
// 下面四个是默认tag的函数
public static void i(String... msg) {
if (FL.isDebug) printLog(I, msg);
}
public static void d(String... msg) {
if (FL.isDebug) printLog(D, msg);
}
public static void w(String... msg) {
if (FL.isDebug) printLog(W, msg);
}
public static void e(String... msg) {
if (FL.isDebug) printLog(E, msg);
}
public static void v(String... msg) {
if (FL.isDebug) printLog(V, msg);
}
// 下面是传入自定义tag的函数
public static void i(String tag, String msg) {
if (FL.isDebug) Log.i(tag, msg);
}
public static void d(String tag, String msg) {
if (FL.isDebug) Log.d(tag, msg);
}
public static void w(String tag, String msg) {
if (FL.isDebug) Log.w(tag, msg);
}
public static void e(String tag, String msg) {
if (FL.isDebug) Log.e(tag, msg);
}
public static void v(String tag, String msg) {
if (FL.isDebug) Log.v(tag, msg);
}
//带异常的
public static void i(String tag, String msg, Throwable tr) {
if (FL.isDebug) Log.i(tag, msg, tr);
}
public static void d(String tag, String msg, Throwable tr) {
if (FL.isDebug) Log.d(tag, msg, tr);
}
public static void w(String tag, String msg, Throwable tr) {
if (FL.isDebug) Log.w(tag, msg, tr);
}
public static void e(String tag, String msg, Throwable tr) {
if (FL.isDebug) Log.e(tag, msg, tr);
}
public static void v(String tag, String msg, Throwable tr) {
if (FL.isDebug) Log.v(tag, msg, tr);
}
/**
* 同意打印
*/
private static void printHunk(char type, String str) {
switch (type) {
case I:
Log.i(TAG, str);
break;
case D:
Log.d(TAG, str);
break;
case E:
Log.e(TAG, str);
break;
case V:
Log.v(TAG, str);
break;
case A:
Log.wtf(TAG, str);
break;
case W:
Log.w(TAG, str);
break;
}
}
/**
* 打印头部信息
*/
private static void printHead(char type) {
printHunk(type, TOP_BORDER);
printHunk(type, HORIZONTAL_DOUBLE_LINE + " Thread:");
printHunk(type, HORIZONTAL_DOUBLE_LINE + " " + Thread.currentThread().getName());
printHunk(type, MIDDLE_BORDER);
}
/**
* 打印Log被调用的位置
*/
private static void printLocation(char type, String... msg) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
int i = 0;
for (StackTraceElement e : stack) {
String name = e.getClassName();
if (!name.equals(L.class.getName())) {
i++;
} else {
break;
}
}
i += 3;
String className = stack[i].getFileName();
String methodName = stack[i].getMethodName();
int lineNumber = stack[i].getLineNumber();
StringBuilder sb = new StringBuilder();
printHunk(type, HORIZONTAL_DOUBLE_LINE + " Location:");
sb.append(HORIZONTAL_DOUBLE_LINE)
.append(" (")
.append(className)
.append(":")
.append(lineNumber)
.append(")# ")
.append(methodName);
printHunk(type, sb.toString());
printHunk(type, msg == null || msg.length == 0 ? BOTTOM_BORDER : MIDDLE_BORDER);
}
/**
* 打印消息
*/
private static void printMsg(char type, String... msg) {
printHunk(type, HORIZONTAL_DOUBLE_LINE + " msg:");
for (String str : msg) {
printHunk(type, HORIZONTAL_DOUBLE_LINE + " " + str);
}
printHunk(type, BOTTOM_BORDER);
}
/**
* 打印log
*/
private static void printLog(char type, String... msg) {
printHead(type);
printLocation(type, msg);
if (msg == null || msg.length == 0) {
return;
}
printMsg(type, msg);
}
}

View File

@@ -0,0 +1,101 @@
package com.ckkj.water.utils.show;
import android.content.Context;
import android.widget.Toast;
/**
* Created by “AriaLyy@outlook.com” on 2015/4/1.
* Toast统一管理类
*/
public class ToastUtil {
/**
* 是否显示Tost
*/
public static boolean isShow = true;
private static Toast mToast;
private ToastUtil() {
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 短时间显示Toast
*/
public static void showShort(Context context, CharSequence message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}
/**
* 短时间显示Toast
*/
public static void showShort(Context context, int message) {
if (mToast == null) {
mToast = Toast.makeText(context, message+"", Toast.LENGTH_SHORT);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}
/**
* 长时间显示Toast
*/
public static void showLong(Context context, CharSequence message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_LONG);
}
mToast.show();
}
/**
* 长时间显示Toast
*/
public static void showLong(Context context, int message) {
if (mToast == null) {
mToast = Toast.makeText(context, message+"", Toast.LENGTH_LONG);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_LONG);
}
mToast.show();
}
/**
* 自定义显示Toast时间
*/
public static void show(Context context, CharSequence message, int duration) {
if (mToast == null) {
mToast = Toast.makeText(context, message, duration);
} else {
mToast.setText(message);
mToast.setDuration(duration);
}
mToast.show();
}
/**
* 自定义显示Toast时间
*/
public static void show(Context context, int message, int duration) {
if (mToast == null) {
mToast = Toast.makeText(context, message+"", duration);
} else {
mToast.setText(message);
mToast.setDuration(duration);
}
mToast.show();
}
}

View File

@@ -0,0 +1,81 @@
package com.ckkj.water.utils.stream;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.Spanned;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import io.noties.markwon.Markwon;
public class MarkdownStreamer {
private final TextView textView;
private final RecyclerView scrollView;
private final Spanned spannedText;
private final Handler handler = new Handler(Looper.getMainLooper());
private int index = 0;
private final long delay = 20;
private boolean isStopped = false; // 控制是否继续流式输出
private OnStreamingCompleteListener onCompleteListener;
public interface OnStreamingCompleteListener {
void onComplete();
void onStop();
}
public void setOnStreamingCompleteListener(OnStreamingCompleteListener listener) {
this.onCompleteListener = listener;
}
public MarkdownStreamer(TextView textView, RecyclerView scrollView, String markdown, Context context) {
this.textView = textView;
this.scrollView = scrollView;
Markwon markwon = Markwon.create(context);
this.spannedText = markwon.toMarkdown(markdown);
}
public void startStreaming() {
textView.setText("");
index = 0;
isStopped = false;
handler.post(streamRunnable);
}
public void stopStreaming() {
if (!isStopped) {
isStopped = true;
handler.removeCallbacks(streamRunnable);
if (onCompleteListener != null) {
onCompleteListener.onStop();
}
}
}
private final Runnable streamRunnable = new Runnable() {
@Override
public void run() {
if (isStopped) return;
if (index <= spannedText.length()) {
CharSequence sub = spannedText.subSequence(0, index);
textView.setText(sub);
// 自动滑动到底部
// scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));
index++;
handler.postDelayed(this, delay);
}else{
// 已经输出完毕
if (onCompleteListener != null) {
onCompleteListener.onComplete();
}
}
}
};
}

View File

@@ -0,0 +1,63 @@
package com.ckkj.water.utils.stream;
import android.content.Context;
import android.text.Spanned;
import android.view.View;
import android.widget.TextView;
import androidx.core.widget.NestedScrollView;
import io.noties.markwon.Markwon;
public class RealTimeMarkdownStreamer {
private final TextView textView;
private final NestedScrollView scrollView;
private final Context context;
private final Markwon markwon;
private StringBuilder contentBuffer = new StringBuilder();
private boolean isProcessing = false;
public RealTimeMarkdownStreamer(TextView textView, NestedScrollView scrollView, Context context) {
this.textView = textView;
this.scrollView = scrollView;
this.context = context;
this.markwon = Markwon.create(context);
}
/**
* 更新流式内容
* @param newContent 新到达的内容
*/
public void updateContent(String newContent) {
if (isProcessing) return;
isProcessing = true;
// 累积内容
contentBuffer.setLength(0);
contentBuffer.append(newContent);
// 尝试解析 Markdown
try {
Spanned spanned = markwon.toMarkdown(contentBuffer.toString());
textView.setText(spanned);
// 自动滚动到底部
scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));
} catch (Exception e) {
// 如果 Markdown 解析失败,显示原始文本
textView.setText(contentBuffer.toString());
}
isProcessing = false;
}
/**
* 清空内容
*/
public void clear() {
contentBuffer.setLength(0);
textView.setText("");
}
}

View File

@@ -0,0 +1,42 @@
package com.ckkj.water.utils.text;
import android.app.Activity;
import android.content.Context;
import android.os.IBinder;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
/**
* Created by 莫超 on 2019/1/25.
* 描述:隐藏键盘
*/
public class TextUtil {
public static void hideKeyboard(MotionEvent event, View view,
Activity activity) {
try {
if (view != null && view instanceof EditText) {
int[] location = { 0, 0 };
view.getLocationInWindow(location);
int left = location[0], top = location[1], right = left
+ view.getWidth(), bottom = top + view.getHeight();
// 判断焦点位置坐标是否在空间内,如果位置在控件外,则隐藏键盘
if (event.getRawX() < left || event.getRawX() > right
|| event.getY() < top || event.getRawY() > bottom) {
// 隐藏键盘
IBinder token = view.getWindowToken();
InputMethodManager inputMethodManager = (InputMethodManager) activity
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(token,
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,107 @@
package com.ckkj.water.utils.time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* author: 张耀
* time: 2019/4/28 17:17
* desc: 时间格式转换工具
* version: 1.0.0
*/
public class DateFormatUtils {
private static final String DATE_FORMAT_PATTERN_YMD = "yyyy-MM-dd";
private static final String DATE_FORMAT_PATTERN_YMD_HM = "yyyy-MM-dd HH:mm";
/**
* 时间戳转字符串
*
* @param timestamp 时间戳
* @param isPreciseTime 是否包含时分
* @return 格式化的日期字符串
*/
public static String long2Str(long timestamp, boolean isPreciseTime) {
return long2Str(timestamp, getFormatPattern(isPreciseTime));
}
public static String long2Str(long timestamp, String pattern) {
return new SimpleDateFormat(pattern, Locale.CHINA).format(new Date(timestamp));
}
/**
* 字符串转时间戳
*
* @param dateStr 日期字符串
* @param isPreciseTime 是否包含时分
* @return 时间戳
*/
public static long str2Long(String dateStr, boolean isPreciseTime) {
return str2Long(dateStr, getFormatPattern(isPreciseTime));
}
/*
* 将时间转换为时间戳
*/
public static String dateToStamp(String s) throws ParseException{
String res;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(s);
long ts = date.getTime();
res = String.valueOf(ts);
return res;
}
private static long str2Long(String dateStr, String pattern) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
Date date = simpleDateFormat.parse(dateStr);
long ts = date.getTime();
return ts;
// return new SimpleDateFormat(pattern, Locale.CHINA).parse(dateStr).getTime();
} catch (Throwable ignored) {
}
return 0;
}
private static String getFormatPattern(boolean showSpecificTime) {
if (showSpecificTime) {
return DATE_FORMAT_PATTERN_YMD_HM;
} else {
return DATE_FORMAT_PATTERN_YMD;
}
}
/**
* 根据指定格式解析时间
*
* @param pattern
* @param date
* @return
* @throws ParseException
*/
public static Date parseDate(String pattern, String date) {
SimpleDateFormat temp = new SimpleDateFormat(pattern, Locale.CANADA);
try {
return temp.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据指定格式格式化时间
*
* @param pattern
* @param date
* @return
*/
public static String formatDate(String pattern, Date date) {
SimpleDateFormat temp = new SimpleDateFormat(pattern, Locale.CANADA);
return temp.format(date);
}
}

View File

@@ -0,0 +1,566 @@
package com.ckkj.water.utils.time;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class DateUtils {
public static String getTodayDateTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
Locale.getDefault());
return format.format(new Date());
}
public static String dateToString(Date date,String timeFormat){
// 定义日期格式
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormat);
// 将 Date 转换为指定格式的 String
String formattedDate = dateFormat.format(date);
return formattedDate;
}
public static String getTodayDateTime1() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd",
Locale.getDefault());
return format.format(new Date());
}
public static String getTodayPlusDay(String inputTime){
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
// 延迟一天并设置时间为 0 点 0 分 0 秒
LocalDateTime startOfTomorrow = now.plusDays(1).toLocalDate().atStartOfDay();
// 格式化输出
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDate = startOfTomorrow.format(formatter);
return formattedDate;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return inputTime;
}
/**
* 掉此方法输入所要转换的时间输入例如("2014年06月14日16时09分00秒")返回时间戳
*
* @param time
* @return
*/
public String data(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒",
Locale.CHINA);
Date date;
String times = null;
try {
date = sdr.parse(time);
long l = date.getTime();
String stf = String.valueOf(l);
times = stf.substring(0, 10);
} catch (Exception e) {
e.printStackTrace();
}
return times;
}
public static String getTodayDateTimes() {
SimpleDateFormat format = new SimpleDateFormat("MM月dd日",
Locale.getDefault());
return format.format(new Date());
}
/**
* 获取当前时间
*
* @return
*/
public static String getCurrentTime_Today() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return sdf.format(new Date());
}
/**
* 调此方法输入所要转换的时间输入例如("2014-06-14-16-09-00")返回时间戳
*
* @param time
* @return
*/
public static String dataOne(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss",
Locale.CHINA);
Date date;
String times = null;
try {
date = sdr.parse(time);
long l = date.getTime();
String stf = String.valueOf(l);
times = stf.substring(0, 10);
} catch (Exception e) {
e.printStackTrace();
}
return times;
}
public static String getTimestamp(String time, String type) {
SimpleDateFormat sdr = new SimpleDateFormat(type, Locale.CHINA);
Date date;
String times = null;
try {
date = sdr.parse(time);
long l = date.getTime();
String stf = String.valueOf(l);
times = stf.substring(0, 10);
} catch (Exception e) {
e.printStackTrace();
}
return times;
}
/**
* 调用此方法输入所要转换的时间戳输入例如1402733340输出"2014年06月14日16时09分00秒"
*
* @param time
* @return
*/
public static String times(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
/**
* 调用此方法输入所要转换的时间戳输入例如1402733340输出"2014-06-14 16:09:00"
*
* @param time
* @return
*/
public static String timedate(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
/**
* 调用此方法输入所要转换的时间戳输入例如1402733340输出"2014年06月14日16:09"
*
* @param time
* @return
*/
public static String timet(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
/**
* @param
* @return
*/
public static String timeslash(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy/MM/dd,HH:mm");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
/**
* @param
* @return
*/
public static String timeslashData(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy/MM/dd");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
// int i = Integer.parseInt(time);
String times = sdr.format(new Date(lcc * 1000L));
return times;
}
/**
* @param
* @return
*/
public static String timeMinute(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("HH:mm");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
public static String tim(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyyMMdd HH:mm");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
public static String time(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd HH:mm");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
// 调用此方法输入所要转换的时间戳例如1402733340输出"2014年06月14日16时09分00秒"
public static String times(long timeStamp) {
SimpleDateFormat sdr = new SimpleDateFormat("MM月dd日 # HH:mm");
return sdr.format(new Date(timeStamp)).replaceAll("#",
getWeek(timeStamp));
}
private static String getWeek(long timeStamp) {
int mydate = 0;
String week = null;
Calendar cd = Calendar.getInstance();
cd.setTime(new Date(timeStamp));
mydate = cd.get(Calendar.DAY_OF_WEEK);
// 获取指定日期转换成星期几
if (mydate == 1) {
week = "周日";
} else if (mydate == 2) {
week = "周一";
} else if (mydate == 3) {
week = "周二";
} else if (mydate == 4) {
week = "周三";
} else if (mydate == 5) {
week = "周四";
} else if (mydate == 6) {
week = "周五";
} else if (mydate == 7) {
week = "周六";
}
return week;
}
// 并用分割符把时间分成时间数组
/**
* 调用此方法输入所要转换的时间戳输入例如1402733340输出"2014-06-14-16-09-00"
*
* @param time
* @return
*/
public String timesOne(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
public static String timesTwo(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
return times;
}
/**
* 并用分割符把时间分成时间数组
*
* @param time
* @return
*/
public static String[] timestamp(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
@SuppressWarnings("unused")
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
String[] fenge = times.split("[年月日时分秒]");
return fenge;
}
/**
* 根据传递的类型格式化时间
*
* @param str
* @param type 例如yy-MM-dd
* @return
*/
public static String getDateTimeByMillisecond(String str, String type) {
Date date = new Date(Long.valueOf(str));
SimpleDateFormat format = new SimpleDateFormat(type);
String time = format.format(date);
return time;
}
/**
* 分割符把时间分成时间数组
*
* @param time
* @return
*/
public String[] division(String time) {
String[] fenge = time.split("[年月日时分秒]");
return fenge;
}
/**
* 输入时间戳变星期
*
* @param time
* @return
*/
public static String changeweek(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
Date date = null;
int mydate = 0;
String week = null;
try {
date = sdr.parse(times);
Calendar cd = Calendar.getInstance();
cd.setTime(date);
mydate = cd.get(Calendar.DAY_OF_WEEK);
// 获取指定日期转换成星期几
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mydate == 1) {
week = "星期日";
} else if (mydate == 2) {
week = "星期一";
} else if (mydate == 3) {
week = "星期二";
} else if (mydate == 4) {
week = "星期三";
} else if (mydate == 5) {
week = "星期四";
} else if (mydate == 6) {
week = "星期五";
} else if (mydate == 7) {
week = "星期六";
}
return week;
}
/**
* 获取日期和星期 例如:2014-11-13 11:00 星期一
*
* @param time
* @param type
* @return
*/
public static String getDateAndWeek(String time, String type) {
return getDateTimeByMillisecond(time + "000", type) + " "
+ changeweekOne(time);
}
/**
* 输入时间戳变星期
*
* @param time
* @return
*/
public static String changeweekOne(String time) {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
long lcc = Long.valueOf(time);
int i = Integer.parseInt(time);
String times = sdr.format(new Date(i * 1000L));
Date date = null;
int mydate = 0;
String week = null;
try {
date = sdr.parse(times);
Calendar cd = Calendar.getInstance();
cd.setTime(date);
mydate = cd.get(Calendar.DAY_OF_WEEK);
// 获取指定日期转换成星期几
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mydate == 1) {
week = "星期日";
} else if (mydate == 2) {
week = "星期一";
} else if (mydate == 3) {
week = "星期二";
} else if (mydate == 4) {
week = "星期三";
} else if (mydate == 5) {
week = "星期四";
} else if (mydate == 6) {
week = "星期五";
} else if (mydate == 7) {
week = "星期六";
}
return week;
}
/**
* 获取当前时间
*
* @return
*/
public static String getCurrentTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
/**
* 输入日期如2014年06月14日16时09分00秒返回星期数
*
* @param time
* @return
*/
public String week(String time) {
Date date = null;
SimpleDateFormat sdr = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
int mydate = 0;
String week = null;
try {
date = sdr.parse(time);
Calendar cd = Calendar.getInstance();
cd.setTime(date);
mydate = cd.get(Calendar.DAY_OF_WEEK);
// 获取指定日期转换成星期几
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mydate == 1) {
week = "星期日";
} else if (mydate == 2) {
week = "星期一";
} else if (mydate == 3) {
week = "星期二";
} else if (mydate == 4) {
week = "星期三";
} else if (mydate == 5) {
week = "星期四";
} else if (mydate == 6) {
week = "星期五";
} else if (mydate == 7) {
week = "星期六";
}
return week;
}
/**
* 输入日期如2014-06-14-16-09-00返回星期数
*
* @param time
* @return
*/
public String weekOne(String time) {
Date date = null;
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
int mydate = 0;
String week = null;
try {
date = sdr.parse(time);
Calendar cd = Calendar.getInstance();
cd.setTime(date);
mydate = cd.get(Calendar.DAY_OF_WEEK);
// 获取指定日期转换成星期几
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mydate == 1) {
week = "星期日";
} else if (mydate == 2) {
week = "星期一";
} else if (mydate == 3) {
week = "星期二";
} else if (mydate == 4) {
week = "星期三";
} else if (mydate == 5) {
week = "星期四";
} else if (mydate == 6) {
week = "星期五";
} else if (mydate == 7) {
week = "星期六";
}
return week;
}
/**
* <pre>
* 判断date和当前日期是否在同一周内
* 注:
* Calendar类提供了一个获取日期在所属年份中是第几周的方法对于上一年末的某一天
* 和新年初的某一天在同一周内也一样可以处理例如2012-12-31和2013-01-01虽然在
* 不同的年份中,但是使用此方法依然判断二者属于同一周内
* </pre>
*
* @param date
* @return
*/
public static boolean isSameWeekWithToday(Date date) {
if (date == null) {
return false;
}
// 0.先把Date类型的对象转换Calendar类型的对象
Calendar todayCal = Calendar.getInstance();
Calendar dateCal = Calendar.getInstance();
todayCal.setTime(new Date());
dateCal.setTime(date);
todayCal.setFirstDayOfWeek( Calendar.MONDAY);
dateCal.setFirstDayOfWeek( Calendar.MONDAY);
// 1.比较当前日期在年份中的周数是否相同
if (todayCal.get(Calendar.WEEK_OF_YEAR) == dateCal.get(Calendar.WEEK_OF_YEAR)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,205 @@
package com.ckkj.water.utils.time;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
/**
* @Description: 时间工具
* @Version 1.0
* @Author 李白
* @Date 2023/7/11 星期二 16:25
*/
public class TimeTools {
/**-------------------------字符串时间与Date类型转换-------------------------**/
/**
* 字符串时间转Date类型
* @param timeStr 时间字符串
* @return
*/
public static Date String2Date(String timeStr){
Date date;
try {
//默认转换前的字符串格式如下 年月日空格分秒: 2023-07-05 12:30:25
date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(timeStr);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return date;
}
/**
* 字符串时间转Date类型,指定输入的字符串时间格式
* @param timeStr
* @param timePattern 按照传入的规则输入时间字符串
* @return
*/
public static Date String2Date(String timeStr, String timePattern){
Date date;
try {
date = new SimpleDateFormat(timePattern).parse(timeStr);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return date;
}
/**
* Date转字符串
* @param date 日期
* @return
*/
public static String Date2String(Date date){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStr = sdf.format(date);
return timeStr;
}
/**
* Date转字符串指定格式
* @param date 日期
* @param pattern 日期格式 yyyy-MM-dd hh:mm:ss
* @return
*/
public static String Date2String(Date date, String pattern){
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
String timeStr = sdf.format(date);
return timeStr;
}
/**-------------------------Date日期与毫秒值ms的转换-------------------------**/
/**
* 毫秒值转为对应的日期
* @param ms 时间毫秒值
* @return
*/
public static Date ms2Date(long ms){
// Date date = new Date(ms);
Date date = new Date();
date.setTime(ms);
System.out.println(date);
return date;
}
/**
* 日期转毫秒值
* @param date
* @return
*/
public static long date2Ms(Date date){
long dateTime = date.getTime();
System.out.println(dateTime);
return dateTime;
}
/**
* 指定日期转为毫秒值
* @param y 年
* @param m 月
* @param d 日
* @return
*/
public static long date2Ms(int y,int m, int d){
Calendar calendar = Calendar.getInstance();
calendar.set(y,m,d);
Date date = calendar.getTime();
long dateTime = date.getTime();
System.out.println(dateTime);
return dateTime;
}
/**
* 指定日期转为毫秒值
* @param y 年
* @param m 月
* @param d 日
* @param h 时
* @param mm 分
* @param s 秒
* @return
*/
public static long date2Ms(int y,int m, int d, int h, int mm, int s){
Calendar calendar = Calendar.getInstance();
calendar.set(y,m,d,h,mm,s);
Date date = calendar.getTime();
long dateTime = date.getTime();
System.out.println(dateTime);
return dateTime;
}
/**
* 指定日期字符串转为毫秒值
* @param dateStr 指定格式输入日期字符串 如 2023-07-07 08:20:38
* @return
* @throws ParseException
*/
public static long date2Ms(String dateStr) throws ParseException {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = df.parse(dateStr);
long dateTime = date.getTime();
System.out.println(dateTime);
return dateTime;
}
/**
* 指定日期字符串转为毫秒值
* @param dateStr 指定格式输入日期字符串 如 2023-07-07 08:20:38
* @param timePattern 字符串日期格式 如 yyyy-MM-dd hh:mm:ss
* @return
* @throws ParseException
*/
public static long date2Ms(String dateStr, String timePattern) throws ParseException {
DateFormat df = new SimpleDateFormat(timePattern);
Date date = df.parse(dateStr);
long dateTime = date.getTime();
System.out.println(dateTime);
return dateTime;
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static long getNextMonthFirstDay() {
try {
// 获取当前时间
LocalDateTime now = LocalDateTime.now();
// 获取下个月的1号
LocalDateTime nextMonthFirstDay = now.plusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
// 转换为时间戳
return ZonedDateTime.of(nextMonthFirstDay, ZoneId.systemDefault()).toInstant().toEpochMilli();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getNextMonth() {
// 获取当前时间
Calendar calendar = Calendar.getInstance();
// 设置为下个月的1号
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
// 设置时间为零点零分零秒
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// 格式化为指定字符串格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = dateFormat.format(calendar.getTime());
return formattedDate;
}
}

View File

@@ -0,0 +1,977 @@
package com.ckkj.water.utils.time;
import android.content.Context;
import android.text.TextUtils;
import android.widget.TextView;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/**
* 创建者:张耀
*
* @author: 1
* @date: 2021/6/11
*/
public class ZYTimeUtils {
/**
* 输入2035-02-04 08:31:04 专为 2/4 节气日期处使用。
* @param dateTimeStr
* @return
*/
public static String formatToMonthDay(String dateTimeStr) {
try {
// 原始格式
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 目标格式(不补零)
SimpleDateFormat outputFormat = new SimpleDateFormat("M/d");
// 解析成 Date
Date date = inputFormat.parse(dateTimeStr);
// 格式化输出
return outputFormat.format(date);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* 将日期字符串格式化为中文日期格式:
* - 若包含时间,返回 yyyy年MM月dd日 HH:mm
* - 若仅包含日期,返回 yyyy年MM月dd日
* @param input 输入字符串,可能是 "yyyy-MM-dd" 或 "yyyy-MM-dd HH:mm"
* @return 中文格式的日期字符串
*/
public static String formatToChineseDate(String input) {
// 尝试解析完整日期时间(优先)
try {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(input, dateTimeFormatter);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");
return dateTime.format(outputFormatter);
} catch (DateTimeParseException e) {
// 忽略,继续尝试解析为日期
}
// 尝试解析仅包含日期
try {
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(input, dateFormatter);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
return date.format(outputFormatter);
} catch (DateTimeParseException e) {
// 忽略
}
// 若两种格式都不匹配,原样返回
return input;
}
/**
* 将日期字符串(如"2000-10-01-9-1"或"2000-10-3")格式化为中文格式。
* @param input 日期字符串,格式可能为"yyyy-MM-dd-HH-mm" 或 "yyyy-MM-dd"
* @return 格式化后的字符串,带时分为"yyyy年MM月dd日 HH:mm",否则为"yyyy年MM月dd日"
*/
public static String formatDateString(String input) {
if (input == null || input.isEmpty()) {
return "";
}
String[] parts = input.split("-");
try {
int year = Integer.parseInt(parts[0]);
int month = Integer.parseInt(parts[1]);
int day = Integer.parseInt(parts[2]);
String formattedDate = String.format("%04d年%02d月%02d日", year, month, day);
if (parts.length >= 5) {
int hour = Integer.parseInt(parts[3]);
int minute = Integer.parseInt(parts[4]);
return formattedDate + String.format(" %02d:%02d", hour, minute);
} else {
return formattedDate;
}
} catch (Exception e) {
e.printStackTrace();
return input; // 如果出错,就返回原始字符串
}
}
/**
* 将 Date 转为 "MM 月 dd 日",若超过一年则返回 "一年前"
*/
public static String formatDateOrOneYearAgo(Date inputDate) {
if (inputDate == null) return "";
Date now = new Date();
long diffInMillis = now.getTime() - inputDate.getTime();
// 超过 365 天视为一年(不考虑闰年等情况)
long daysDiff = TimeUnit.MILLISECONDS.toDays(diffInMillis);
if (daysDiff >= 365) {
return "一年前";
}
// 格式化为 MM 月 dd 日
SimpleDateFormat sdf = new SimpleDateFormat("MM 月 dd 日");
return sdf.format(inputDate);
}
//字符串转时间戳
public static String getTime(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
return sdf.format(new Date(timeString));
}
public static String getTimeFen(Long timeString){
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
return sdf.format(new Date(timeString));
}
public static String getTimeFens(Long timeString){
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
return sdf.format(new Date(timeString));
}
public static String get_Time(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date(timeString));
}
public static String get_Time_year(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
return sdf.format(new Date(timeString));
}
public static String get_Time_year_moon(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
return sdf.format(new Date(timeString));
}
public static String get_Time_year_moon_notext(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
return sdf.format(new Date(timeString));
}
public static String get_Time3(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd HH:mm");
return sdf.format(new Date(timeString));
}
public static String get_Time1(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date(timeString));
}
public static String get_Time2(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date(timeString));
}
public static String get_Time4(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
return sdf.format(new Date(timeString));
}
public static String get_Time5(Long timeString) {
String timeStamp = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
return sdf.format(new Date(timeString));
}
//时间戳转字符串
public static String getStrTime(String timeStamp) {
String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
long l = Long.valueOf(timeStamp);
timeString = sdf.format(new Date(l));//单位秒
return timeString;
}
//字符串转yyyy-MM-dd
public static String getStrTimeDay(String timeStamp) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date time = sdf.parse(timeStamp);
return new SimpleDateFormat("yyyy.MM.dd").format(time);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
//
public static String getStrTimeData(Date date) {
String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
timeString = sdf.format(new Date());//单位秒
return timeString;
}
public static String getStrTimeData_H_M(Date date) {
String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
timeString = sdf.format(date);//单位秒
return timeString;
}
public static String getStrTimeData_YYYY_MM_dd(Date date) {
String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
timeString = sdf.format(date);//单位秒
return timeString;
}
public static String getStrTimeDataStrToTime(String time) {
try {
// 去掉微秒部分,保留到毫秒(例如: .760
String trimmed = time.substring(0, 23); // "2025-05-14T10:36:03.760"
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault());
Date date = parser.parse(trimmed);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
return formatter.format(date);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
public static String getDateToTimeNomills(String inputDate) {
try {
// 定义输入格式ISO 8601带 "T"
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
// 解析字符串为 Date 对象
Date date = inputFormat.parse(inputDate);
// 定义输出格式yyyy-MM-dd
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
// 格式化为目标字符串
String outputDate = outputFormat.format(date);
return outputDate;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
// 将字符串转为时间戳
public static String getTimeNoHMD(String user_time) {
String re_time = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d;
try {
d = sdf.parse(user_time);
long l = d.getTime();
String str = String.valueOf(l);
re_time = str.substring(0, 10);
} catch (ParseException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
return re_time;
}
// 比较俩个时间大小
public static boolean getDateTime(Long time1, Long time2) {
boolean index = false;
Date date1 = new Date(time1);
Date date2 = new Date(time2);
if (date1.before(date2) || date1.equals(date2)) {
index = true;
}
return index;
}
/**
* 获取某个日期前后N天的日期
*
* @param beginDate
* @param distanceDay 前后几天 如获取前7天日期则传-7即可如果后7天则传7
* @param format 日期格式,默认"yyyy-MM-dd"
* @return
*/
public static String getOldDateByDay(Date beginDate, int distanceDay, String format) {
if (format == null || format.isEmpty()) {
format = "yyyy-MM-dd";
}
SimpleDateFormat dft = new SimpleDateFormat(format);
Calendar date = Calendar.getInstance();
date.setTime(beginDate);
date.set(Calendar.DATE, date.get(Calendar.DATE) + distanceDay);
Date endDate = null;
try {
endDate = dft.parse(dft.format(date.getTime()));
} catch (Exception e) {
e.printStackTrace();
}
return dft.format(endDate);
}
// ///s 代表Simple日期格式yyyy-MM-dd
// ///f 代表Full日期格式yyyy-MM-dd hh:mm:ss
public static final SimpleDateFormat ss_format = new SimpleDateFormat("MM-dd");
public static final SimpleDateFormat yyMM_format = new SimpleDateFormat("yyyy-MM");
public static final SimpleDateFormat s_format = new SimpleDateFormat("yyyy-MM-dd");
public static final SimpleDateFormat f_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static final SimpleDateFormat sdfNearby = new SimpleDateFormat("MM-dd HH:mm");
public static final SimpleDateFormat sk_format_1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public static SimpleDateFormat friendly_format1 = new SimpleDateFormat("HH:mm");
public static SimpleDateFormat friendly_format2 = new SimpleDateFormat("MM-dd HH:mm");
private static SimpleDateFormat hm_formater = new SimpleDateFormat("HH:mm");
public static long s_str_2_long(String dateString) {
try {
Date d = s_format.parse(dateString);
return d.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static long yyMM_2_long(String dateString) {
try {
Date d = yyMM_format.parse(dateString);
return d.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static long f_str_2_long(String dateString) {
try {
Date d = f_format.parse(dateString);
return d.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static String ss_long_2_str(long timestamp) {
return ss_format.format(new Date(timestamp));
}
public static String s_long_2_str(long timestamp) {
return s_format.format(new Date(timestamp));
}
public static String f_long_2_str(long timestamp) {
return f_format.format(new Date(timestamp));
}
/**
* 获取字符串时间的年份
*
* @param dateString 格式为yyyy-MM-ss或者yyyy-MM-dd HH:mm:ss
* @return
*/
public static int getYear(String dateString) {
try {
Date d = s_format.parse(dateString);
return d.getYear() + 1900;// 年份是基于格林威治时间所以加上1900
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
/**
* 获取字符串时间的月份
*
* @param dateString 格式为yyyy-MM-ss或者yyyy-MM-dd hh:mm:ss
* @return
*/
public static int getMonth(String dateString) {
try {
Date d = s_format.parse(dateString);
return d.getMonth();// 月份从0-11
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
// /////////////////////以上是通用的,下面为特殊需求的////////////////////////
// /**
// * 时间戳转换日期格式
// *
// * @param timestamp
// * 单位秒
// * @return
// */
// public static String getCurrentTime(long timestamp) {
// SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// return f.format(new Date(timestamp * 1000));
// }
/**
* 获取字符串时间的天
*
* @param dateString 格式为yyyy-MM-ss或者yyyy-MM-dd hh:mm:ss
* @return
*/
public static int getDayOfMonth(String dateString) {
try {
Date d = s_format.parse(dateString);
return d.getDate();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
public static int getHours(String timeString) {
SimpleDateFormat formart = new SimpleDateFormat("HH:mm:ss");
try {
Date date = formart.parse(timeString);
return date.getHours();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
public static int getMinutes(String timeString) {
SimpleDateFormat formart = new SimpleDateFormat("HH:mm:ss");
try {
Date date = formart.parse(timeString);
return date.getMinutes();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
public static int getSeconds(String timeString) {
SimpleDateFormat formart = new SimpleDateFormat("HH:mm:ss");
try {
Date date = formart.parse(timeString);
return date.getSeconds();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
public static String getCurrentTime() {
return f_format.format(new Date(System.currentTimeMillis()));
}
/**
* 在当前时间上加上多少毫秒,返回这个时间
*
* @param mask
* @return
*/
public static String getCurrentTimeMask(long mask) {
return f_format.format(new Date(System.currentTimeMillis() + mask));
}
/**
* 获取精简的日期
*
* @param time
* @return
*/
public static String getSimpleDate(String time) {
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
/**
* @param time
* @return
*/
public static String getSimpleDateTime(String time) {
SimpleDateFormat formater = new SimpleDateFormat("yy-MM-dd HH:mm");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
/**
* @param time
* @return
*/
public static String getSimpleDateTime1(String time) {
SimpleDateFormat formater = new SimpleDateFormat("MM/dd HH:mm");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
public static String getSimpleTime(String time) {
SimpleDateFormat formater = new SimpleDateFormat("HH:mm");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
public static String getChatSimpleDate(String time) {
SimpleDateFormat formater = new SimpleDateFormat("yy-MM-dd");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
public static String getTimeHM(String time) {
SimpleDateFormat formater = new SimpleDateFormat("HH:mm");
Date date = null;
try {
date = f_format.parse(time);
return formater.format(date);
} catch (ParseException e) {
e.printStackTrace();
return "";
}
}
public static String getTimeMMdd(long time) {
SimpleDateFormat formater = new SimpleDateFormat("MM-dd");
return formater.format(time * 1000);
}
/**
* 获取好友的时间显示
*
* @param time 秒级别的时间戳
* @return
*/
public static String getFriendlyTimeDescs(Context context, long time) {
String desc = "";
if (time == 0) {
return desc;
}
Date timeDate = new Date(time * 1000L);
Date nowDate = new Date();
Calendar calendar;
long delaySeconds = nowDate.getTime() / 1000 - time;// 相差的秒数
if (delaySeconds < 60 * 60 * 24) {// 小于1天之内
if (nowDate.getDay() - timeDate.getDay() == 0) {// 同一天
desc = friendly_format1.format(timeDate);
} else {// 前一天
if (DateUtils.isSameWeekWithToday(timeDate)) {
desc = DateUtils.changeweekOne(time + "") + " " + friendly_format1.format(timeDate);
}
}
} else if (delaySeconds < 60 * 60 * 24 * 7) {// 小于7天
if (DateUtils.isSameWeekWithToday(timeDate)) {
// desc = DateUtils.changeweekOne(time + "") + " " + friendly_format1.format(timeDate);
desc = DateUtils.changeweekOne(time + "") ;
}else {
if (nowDate.getYear() - timeDate.getYear() == 0) {// 同一年
desc = friendly_format2.format(timeDate);
}
}
} else {
if (nowDate.getYear() - timeDate.getYear() == 0) {// 同一年
desc = friendly_format2.format(timeDate);
}
}
if (TextUtils.isEmpty(desc)) {
desc = sk_format_1.format(timeDate);
}
// if (TextUtils.isEmpty(desc)) {
// desc = friendly_format2.format(timeDate);
// }
return desc;
}
/**
* 获取好友的时间显示
*
* @param time 秒级别的时间戳
* @return
*/
public static String getFriendlyTimeDescsTime(Context context, long time) {
String desc = "";
if (time == 0) {
return desc;
}
Date timeDate = new Date(time * 1000L);
Date nowDate = new Date();
Calendar calendar;
long delaySeconds = nowDate.getTime() / 1000 - time;// 相差的秒数
if (delaySeconds < 60 * 60 * 24) {// 小于1天之内
if (nowDate.getDay() - timeDate.getDay() == 0) {// 同一天
desc = friendly_format1.format(timeDate);
} else {// 前一天
if (DateUtils.isSameWeekWithToday(timeDate)) {
desc = DateUtils.changeweekOne(time + "") + " " + friendly_format1.format(timeDate);
}
}
} else if (delaySeconds < 60 * 60 * 24 * 7) {// 小于7天
if (DateUtils.isSameWeekWithToday(timeDate)) {
// desc = DateUtils.changeweekOne(time + "") + " " + friendly_format1.format(timeDate);
desc = DateUtils.changeweekOne(time + "") + " " + friendly_format1.format(timeDate);
}else {
if (nowDate.getYear() - timeDate.getYear() == 0) {// 同一年
desc = friendly_format2.format(timeDate);
}
}
} else {
if (nowDate.getYear() - timeDate.getYear() == 0) {// 同一年
desc = friendly_format2.format(timeDate);
}
}
if (TextUtils.isEmpty(desc)) {
desc = sk_format_1.format(timeDate);
}
// if (TextUtils.isEmpty(desc)) {
// desc = friendly_format2.format(timeDate);
// }
return desc;
}
public static String sk_time_friendly_format2(long time) {
return friendly_format2.format(new Date(time * 1000));
}
public static String sk_time_s_long_2_str(long time) {
return s_long_2_str(time * 1000);
}
public static String skNearbyTimeString(long timestamp) {
return sdfNearby.format(new Date(timestamp * 1000));
}
public static String sk_time_ss_long_2_str(long time) {
return ss_long_2_str(time * 1000);
}
public static long sk_time_s_str_2_long(String dateString) {
return s_str_2_long(dateString) / 1000;
}
public static String sk_time_long_to_hm_str(long time) {
try {
return hm_formater.format(new Date(time * 1000));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static String sk_time_long_to_chat_time_str(long time) {
String date1 = sk_time_s_long_2_str(time);
String date2 = sk_time_s_long_2_str(System.currentTimeMillis() / 1000);
if (date1.compareToIgnoreCase(date2) == 0) {// 是同一天
return sk_time_long_to_hm_str(time);
} else {
return long_to_yMdHm_str(time * 1000);
}
}
// 日期加小时的字符串
public static String long_to_yMdHm_str(long time) {
return sk_format_1.format(new Date(time));
}
public static long sk_time_yMdHm_str_to_long(String time) {
try {
return sk_format_1.parse(time).getTime() / 1000;
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static int yMdHm_getYear(String dateString) {
try {
Date d = sk_format_1.parse(dateString);
return d.getYear() + 1900;// 年份是基于格林威治时间所以加上1900
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static int yMdHm_getMonth(String dateString) {
try {
Date d = sk_format_1.parse(dateString);
return d.getMonth();// 月份从0-11
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static int yMdHm_getDayOfMonth(String dateString) {
try {
Date d = sk_format_1.parse(dateString);
return d.getDate();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static int yMdHm_getHours(String timeString) {
try {
Date date = sk_format_1.parse(timeString);
return date.getHours();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
public static int yMdHm_getMinutes(String timeString) {
try {
Date date = sk_format_1.parse(timeString);
return date.getMinutes();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
/**
* 判断当前时间是否在指定出生日期之前
* @param birthTimeStr 出生日期字符串格式2025-08-15 10:00:00
* @return true: 当前时间在出生日期之前false: 当前时间在出生日期之后或等于
*/
public static boolean isCurrentTimeBeforeBirthTime(String birthTimeStr) {
if (birthTimeStr == null || birthTimeStr.trim().isEmpty()) {
return false;
}
try {
// 解析出生日期字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
Date birthDate = sdf.parse(birthTimeStr);
if (birthDate == null) {
return false;
}
// 获取当前时间
Date currentDate = new Date();
// 比较时间如果当前时间在出生时间之前返回true
return currentDate.before(birthDate);
} catch (ParseException e) {
e.printStackTrace();
return false;
}
}
/**
* 判断当前时间是否在指定出生日期之前(重载方法,支持不同格式)
* @param birthTimeStr 出生日期字符串
* @param format 日期格式,如:"yyyy-MM-dd HH:mm:ss"
* @return true: 当前时间在出生日期之前false: 当前时间在出生日期之后或等于
*/
public static boolean isCurrentTimeBeforeBirthTime(String birthTimeStr, String format) {
if (birthTimeStr == null || birthTimeStr.trim().isEmpty() || format == null) {
return false;
}
try {
// 解析出生日期字符串
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
Date birthDate = sdf.parse(birthTimeStr);
if (birthDate == null) {
return false;
}
// 获取当前时间
Date currentDate = new Date();
// 比较时间如果当前时间在出生时间之前返回true
return currentDate.before(birthDate);
} catch (ParseException e) {
e.printStackTrace();
return false;
}
}
/**
* @param textView
* @param time 时间戳/1000
* @return
*/
public static long getSpecialBeginTime(TextView textView, long time) {
long currentTime = System.currentTimeMillis() / 1000;
if (time > currentTime) {
time = currentTime;
}
textView.setText(sk_time_s_long_2_str(time));
return time;
}
public static int sk_time_age(long birthday) {
int age = (new Date().getYear()) - (new Date(birthday * 1000).getYear());
if (age < 0 || age > 100) {
return 25;
}
return age;
}
public static String formatTime(long timestamp) {
// 当前时间
Calendar now = Calendar.getInstance();
// 消息时间
Calendar msgTime = Calendar.getInstance();
msgTime.setTimeInMillis(timestamp);
// 判断是否是同一天
if (isSameDay(now, msgTime)) {
// 今天
return new SimpleDateFormat("HH:mm", Locale.getDefault()).format(msgTime.getTime());
}
// 判断是否是昨天
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DAY_OF_YEAR, -1);
if (isSameDay(yesterday, msgTime)) {
return "昨天";
}
// 更早的时间
return new SimpleDateFormat("MM-dd", Locale.getDefault()).format(msgTime.getTime());
}
private static boolean isSameDay(Calendar c1, Calendar c2) {
return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
&& c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
}
public static String carCircleTimeShow(long timestampMillis) {
long now = System.currentTimeMillis();
long diff = now - timestampMillis;
if (diff < TimeUnit.MINUTES.toMillis(1)) {
return "刚刚";
} else if (diff < TimeUnit.HOURS.toMillis(1)) {
long minutes = TimeUnit.MILLISECONDS.toMinutes(diff);
return minutes + "分钟前";
} else if (diff < TimeUnit.DAYS.toMillis(1)) {
long hours = TimeUnit.MILLISECONDS.toHours(diff);
return hours + "小时前";
} else if (diff < TimeUnit.DAYS.toMillis(3)) {
long days = TimeUnit.MILLISECONDS.toDays(diff);
return days + "天前";
} else {
// 超过三天,按 yyyy-MM-dd 显示
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date(timestampMillis));
}
}
public static List<String> initHourMinDatas(int type){
int count = 0;
if(type == 100){
count = 24;
}else{
count = 60;
}
List list = new ArrayList();
for(int i=0; i < count; i++){
if(i<10){
list.add("0" + i);
}else{
list.add(String.valueOf(i));
}
}
list.add(0,"未知");
return list;
}
/**
* 比较结束时间是否在开始时间之后
* @param startTime 开始时间格式yyyy-MM-dd
* @param endTime 结束时间格式yyyy-MM-dd
* @return true: 结束时间在开始时间之后符合条件false: 结束时间早于或等于开始时间(不符合条件)
*/
public static boolean isEndTimeAfterStartTime(String startTime, String endTime) {
if (TextUtils.isEmpty(startTime) || TextUtils.isEmpty(endTime)) {
return false;
}
try {
Date startDate = s_format.parse(startTime);
Date endDate = s_format.parse(endTime);
return endDate.after(startDate);
} catch (ParseException e) {
e.printStackTrace();
return false;
}
}
}

View File

@@ -0,0 +1,685 @@
package com.ckkj.water.utils.ui;
import android.app.Dialog;
import android.content.Context;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.ckkj.water.R;
import com.ckkj.water.utils.time.DateFormatUtils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* 说明:自定义时间选择器
* 作者liuwan1992
* 添加时间2016/9/28
* 修改人liuwan1992
* 修改时间2018/12/21
* github: https://github.com/liuwan1992/CustomDatePicker
*/
public class CustomDatePicker implements View.OnClickListener, PickerView.OnSelectListener {
private Context mContext;
private Callback mCallback;
private Calendar mBeginTime, mEndTime, mSelectedTime;
private boolean mCanDialogShow;
private Dialog mPickerDialog;
private PickerView mDpvYear, mDpvMonth, mDpvDay, mDpvHour, mDpvMinute;
private TextView mTvHourUnit, mTvMinuteUnit,tv_nian,tv_yue,tv_ri;
private int mBeginYear, mBeginMonth, mBeginDay, mBeginHour, mBeginMinute,
mEndYear, mEndMonth, mEndDay, mEndHour, mEndMinute;
private List<String> mYearUnits = new ArrayList<>(), mMonthUnits = new ArrayList<>(), mDayUnits = new ArrayList<>(),
mHourUnits = new ArrayList<>(), mMinuteUnits = new ArrayList<>();
private DecimalFormat mDecimalFormat = new DecimalFormat("00");
private boolean mCanShowPreciseTime;
private int mScrollUnits = SCROLL_UNIT_HOUR + SCROLL_UNIT_MINUTE;
/**
* 时间单位:时、分
*/
private static final int SCROLL_UNIT_HOUR = 0b1;
private static final int SCROLL_UNIT_MINUTE = 0b10;
/**
* 时间单位的最大显示值
*/
private static final int MAX_MINUTE_UNIT = 59;
private static final int MAX_HOUR_UNIT = 23;
private static final int MAX_MONTH_UNIT = 12;
/**
* 级联滚动延迟时间
*/
private static final long LINKAGE_DELAY_DEFAULT = 100L;
/**
* 时间选择结果回调接口
*/
public interface Callback {
void onTimeSelected(long timestamp);
}
//是否显示时分秒
boolean isShiFen;
/**
* 通过日期字符串初始换时间选择器
*
* @param context Activity Context
* @param callback 选择结果回调
* @param beginDateStr 日期字符串,格式为 yyyy-MM-dd HH:mm
* @param endDateStr 日期字符串,格式为 yyyy-MM-dd HH:mm
*/
public CustomDatePicker(Context context, Callback callback, String beginDateStr, String endDateStr) {
this(context, callback, DateFormatUtils.str2Long(beginDateStr, true),
DateFormatUtils.str2Long(endDateStr, true));
}
/**
* 通过时间戳初始换时间选择器,毫秒级别
*
* @param context Activity Context
* @param callback 选择结果回调
* @param beginTimestamp 毫秒级时间戳
* @param endTimestamp 毫秒级时间戳
*/
public CustomDatePicker(Context context, Callback callback, long beginTimestamp, long endTimestamp) {
// if (context == null || callback == null || beginTimestamp <= 0 || beginTimestamp >= endTimestamp) {
// mCanDialogShow = false;
// return;
// }
if (context == null || callback == null) {
mCanDialogShow = false;
return;
}
mContext = context;
mCallback = callback;
mBeginTime = Calendar.getInstance();
mBeginTime.setTimeInMillis(beginTimestamp);
mEndTime = Calendar.getInstance();
mEndTime.setTimeInMillis(endTimestamp);
mSelectedTime = Calendar.getInstance();
initView();
initData();
mCanDialogShow = true;
}
private void initView() {
mPickerDialog = new Dialog(mContext, R.style.loadingDialog);
mPickerDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mPickerDialog.setContentView(R.layout.dialog_date_picker);
Window window = mPickerDialog.getWindow();
if (window != null) {
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM;
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
}
mPickerDialog.findViewById(R.id.tv_cancel).setOnClickListener(this);
mPickerDialog.findViewById(R.id.tv_confirm).setOnClickListener(this);
mTvHourUnit = mPickerDialog.findViewById(R.id.tv_hour_unit);
tv_nian = mPickerDialog.findViewById(R.id.tv_nian);
tv_yue = mPickerDialog.findViewById(R.id.tv_yue);
tv_ri = mPickerDialog.findViewById(R.id.tv_ri);
mTvMinuteUnit = mPickerDialog.findViewById(R.id.tv_minute_unit);
mDpvYear = mPickerDialog.findViewById(R.id.dpv_year);
mDpvYear.setOnSelectListener(this);
mDpvMonth = mPickerDialog.findViewById(R.id.dpv_month);
mDpvMonth.setOnSelectListener(this);
mDpvDay = mPickerDialog.findViewById(R.id.dpv_day);
mDpvDay.setOnSelectListener(this);
mDpvHour = mPickerDialog.findViewById(R.id.dpv_hour);
mDpvHour.setOnSelectListener(this);
mDpvMinute = mPickerDialog.findViewById(R.id.dpv_minute);
mDpvMinute.setOnSelectListener(this);
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.tv_confirm) {
if (mCallback != null) {
mCallback.onTimeSelected(mSelectedTime.getTimeInMillis());
}
}
if (mPickerDialog != null && mPickerDialog.isShowing()) {
mPickerDialog.dismiss();
}
}
@Override
public void onSelect(View view, String selected) {
if (view == null || TextUtils.isEmpty(selected)) return;
int timeUnit;
try {
timeUnit = Integer.parseInt(selected);
} catch (Throwable ignored) {
return;
}
int i = view.getId();
if (i == R.id.dpv_year) {
mSelectedTime.set(Calendar.YEAR, timeUnit);
linkageMonthUnit(true, LINKAGE_DELAY_DEFAULT);
} else if (i == R.id.dpv_month) {// 防止类似 2018/12/31 滚动到11月时因溢出变成 2018/12/01
int lastSelectedMonth = mSelectedTime.get(Calendar.MONTH) + 1;
mSelectedTime.add(Calendar.MONTH, timeUnit - lastSelectedMonth);
linkageDayUnit(true, LINKAGE_DELAY_DEFAULT);
} else if (i == R.id.dpv_day) {
mSelectedTime.set(Calendar.DAY_OF_MONTH, timeUnit);
linkageHourUnit(true, LINKAGE_DELAY_DEFAULT);
} else if (i == R.id.dpv_hour) {
mSelectedTime.set(Calendar.HOUR_OF_DAY, timeUnit);
linkageMinuteUnit(true);
} else if (i == R.id.dpv_minute) {
mSelectedTime.set(Calendar.MINUTE, timeUnit);
}
}
private void initData() {
mSelectedTime.setTimeInMillis(mBeginTime.getTimeInMillis());
mBeginYear = mBeginTime.get(Calendar.YEAR);
// Calendar.MONTH 值为 0-11
mBeginMonth = mBeginTime.get(Calendar.MONTH) + 1;
mBeginDay = mBeginTime.get(Calendar.DAY_OF_MONTH);
mBeginHour = mBeginTime.get(Calendar.HOUR_OF_DAY);
mBeginMinute = mBeginTime.get(Calendar.MINUTE);
mEndYear = mEndTime.get(Calendar.YEAR);
mEndMonth = mEndTime.get(Calendar.MONTH) + 1;
mEndDay = mEndTime.get(Calendar.DAY_OF_MONTH);
mEndHour = mEndTime.get(Calendar.HOUR_OF_DAY);
mEndMinute = mEndTime.get(Calendar.MINUTE);
boolean canSpanYear = mBeginYear != mEndYear;
boolean canSpanMon = !canSpanYear && mBeginMonth != mEndMonth;
boolean canSpanDay = !canSpanMon && mBeginDay != mEndDay;
boolean canSpanHour = !canSpanDay && mBeginHour != mEndHour;
boolean canSpanMinute = !canSpanHour && mBeginMinute != mEndMinute;
if (canSpanYear) {
initDateUnits(MAX_MONTH_UNIT, mBeginTime.getActualMaximum(Calendar.DAY_OF_MONTH), MAX_HOUR_UNIT, MAX_MINUTE_UNIT);
} else if (canSpanMon) {
initDateUnits(mEndMonth, mBeginTime.getActualMaximum(Calendar.DAY_OF_MONTH), MAX_HOUR_UNIT, MAX_MINUTE_UNIT);
} else if (canSpanDay) {
initDateUnits(mEndMonth, mEndDay, MAX_HOUR_UNIT, MAX_MINUTE_UNIT);
} else if (canSpanHour) {
initDateUnits(mEndMonth, mEndDay, mEndHour, MAX_MINUTE_UNIT);
} else if (canSpanMinute) {
initDateUnits(mEndMonth, mEndDay, mEndHour, mEndMinute);
}
}
private void initDateUnits(int endMonth, int endDay, int endHour, int endMinute) {
for (int i = mBeginYear; i <= mEndYear; i++) {
mYearUnits.add(String.valueOf(i));
}
for (int i = mBeginMonth; i <= endMonth; i++) {
mMonthUnits.add(mDecimalFormat.format(i));
}
for (int i = mBeginDay; i <= endDay; i++) {
mDayUnits.add(mDecimalFormat.format(i));
}
if ((mScrollUnits & SCROLL_UNIT_HOUR) != SCROLL_UNIT_HOUR) {
mHourUnits.add(mDecimalFormat.format(mBeginHour));
} else {
for (int i = mBeginHour; i <= endHour; i++) {
mHourUnits.add(mDecimalFormat.format(i));
}
}
if ((mScrollUnits & SCROLL_UNIT_MINUTE) != SCROLL_UNIT_MINUTE) {
mMinuteUnits.add(mDecimalFormat.format(mBeginMinute));
} else {
for (int i = mBeginMinute; i <= endMinute; i++) {
mMinuteUnits.add(mDecimalFormat.format(i));
}
}
mDpvYear.setDataList(mYearUnits);
mDpvYear.setSelected(0);
mDpvMonth.setDataList(mMonthUnits);
mDpvMonth.setSelected(0);
mDpvDay.setDataList(mDayUnits);
mDpvDay.setSelected(0);
mDpvHour.setDataList(mHourUnits);
mDpvHour.setSelected(0);
mDpvMinute.setDataList(mMinuteUnits);
mDpvMinute.setSelected(0);
setCanScroll();
}
private void setCanScroll() {
mDpvYear.setCanScroll(mYearUnits.size() > 1);
mDpvMonth.setCanScroll(mMonthUnits.size() > 1);
mDpvDay.setCanScroll(mDayUnits.size() > 1);
mDpvHour.setCanScroll(mHourUnits.size() > 1 && (mScrollUnits & SCROLL_UNIT_HOUR) == SCROLL_UNIT_HOUR);
mDpvMinute.setCanScroll(mMinuteUnits.size() > 1 && (mScrollUnits & SCROLL_UNIT_MINUTE) == SCROLL_UNIT_MINUTE);
}
/**
* 联动“月”变化
*
* @param showAnim 是否展示滚动动画
* @param delay 联动下一级延迟时间
*/
private void linkageMonthUnit(final boolean showAnim, final long delay) {
int minMonth;
int maxMonth;
int selectedYear = mSelectedTime.get(Calendar.YEAR);
if (mBeginYear == mEndYear) {
minMonth = mBeginMonth;
maxMonth = mEndMonth;
} else if (selectedYear == mBeginYear) {
minMonth = mBeginMonth;
maxMonth = MAX_MONTH_UNIT;
} else if (selectedYear == mEndYear) {
minMonth = 1;
maxMonth = mEndMonth;
} else {
minMonth = 1;
maxMonth = MAX_MONTH_UNIT;
}
// 重新初始化时间单元容器
mMonthUnits.clear();
for (int i = minMonth; i <= maxMonth; i++) {
mMonthUnits.add(mDecimalFormat.format(i));
}
mDpvMonth.setDataList(mMonthUnits);
// 确保联动时不会溢出或改变关联选中值
int selectedMonth = getValueInRange(mSelectedTime.get(Calendar.MONTH) + 1, minMonth, maxMonth);
mSelectedTime.set(Calendar.MONTH, selectedMonth - 1);
mDpvMonth.setSelected(selectedMonth - minMonth);
if (showAnim) {
mDpvMonth.startAnim();
}
// 联动“日”变化
mDpvMonth.postDelayed(() -> linkageDayUnit(showAnim, delay), delay);
}
/**
* 联动“日”变化
*
* @param showAnim 是否展示滚动动画
* @param delay 联动下一级延迟时间
*/
private void linkageDayUnit(final boolean showAnim, final long delay) {
int minDay;
int maxDay;
int selectedYear = mSelectedTime.get(Calendar.YEAR);
int selectedMonth = mSelectedTime.get(Calendar.MONTH) + 1;
if (mBeginYear == mEndYear && mBeginMonth == mEndMonth) {
minDay = mBeginDay;
maxDay = mEndDay;
} else if (selectedYear == mBeginYear && selectedMonth == mBeginMonth) {
minDay = mBeginDay;
maxDay = mSelectedTime.getActualMaximum(Calendar.DAY_OF_MONTH);
} else if (selectedYear == mEndYear && selectedMonth == mEndMonth) {
minDay = 1;
maxDay = mEndDay;
} else {
minDay = 1;
maxDay = mSelectedTime.getActualMaximum(Calendar.DAY_OF_MONTH);
}
mDayUnits.clear();
for (int i = minDay; i <= maxDay; i++) {
mDayUnits.add(mDecimalFormat.format(i));
}
mDpvDay.setDataList(mDayUnits);
int selectedDay = getValueInRange(mSelectedTime.get(Calendar.DAY_OF_MONTH), minDay, maxDay);
mSelectedTime.set(Calendar.DAY_OF_MONTH, selectedDay);
mDpvDay.setSelected(selectedDay - minDay);
if (showAnim) {
mDpvDay.startAnim();
}
mDpvDay.postDelayed(() -> linkageHourUnit(showAnim, delay), delay);
}
/**
* 联动“时”变化
*
* @param showAnim 是否展示滚动动画
* @param delay 联动下一级延迟时间
*/
private void linkageHourUnit(final boolean showAnim, final long delay) {
if ((mScrollUnits & SCROLL_UNIT_HOUR) == SCROLL_UNIT_HOUR) {
int minHour;
int maxHour;
int selectedYear = mSelectedTime.get(Calendar.YEAR);
int selectedMonth = mSelectedTime.get(Calendar.MONTH) + 1;
int selectedDay = mSelectedTime.get(Calendar.DAY_OF_MONTH);
if (mBeginYear == mEndYear && mBeginMonth == mEndMonth && mBeginDay == mEndDay) {
minHour = mBeginHour;
maxHour = mEndHour;
} else if (selectedYear == mBeginYear && selectedMonth == mBeginMonth && selectedDay == mBeginDay) {
minHour = mBeginHour;
maxHour = MAX_HOUR_UNIT;
} else if (selectedYear == mEndYear && selectedMonth == mEndMonth && selectedDay == mEndDay) {
minHour = 0;
maxHour = mEndHour;
} else {
minHour = 0;
maxHour = MAX_HOUR_UNIT;
}
mHourUnits.clear();
for (int i = minHour; i <= maxHour; i++) {
mHourUnits.add(mDecimalFormat.format(i));
}
mDpvHour.setDataList(mHourUnits);
int selectedHour = getValueInRange(mSelectedTime.get(Calendar.HOUR_OF_DAY), minHour, maxHour);
mSelectedTime.set(Calendar.HOUR_OF_DAY, selectedHour);
mDpvHour.setSelected(selectedHour - minHour);
if (showAnim) {
mDpvHour.startAnim();
}
}
mDpvHour.postDelayed(() -> linkageMinuteUnit(showAnim), delay);
}
/**
* 联动“分”变化
*
* @param showAnim 是否展示滚动动画
*/
private void linkageMinuteUnit(final boolean showAnim) {
if ((mScrollUnits & SCROLL_UNIT_MINUTE) == SCROLL_UNIT_MINUTE) {
int minMinute;
int maxMinute;
int selectedYear = mSelectedTime.get(Calendar.YEAR);
int selectedMonth = mSelectedTime.get(Calendar.MONTH) + 1;
int selectedDay = mSelectedTime.get(Calendar.DAY_OF_MONTH);
int selectedHour = mSelectedTime.get(Calendar.HOUR_OF_DAY);
if (mBeginYear == mEndYear && mBeginMonth == mEndMonth && mBeginDay == mEndDay && mBeginHour == mEndHour) {
minMinute = mBeginMinute;
maxMinute = mEndMinute;
} else if (selectedYear == mBeginYear && selectedMonth == mBeginMonth && selectedDay == mBeginDay && selectedHour == mBeginHour) {
minMinute = mBeginMinute;
maxMinute = MAX_MINUTE_UNIT;
} else if (selectedYear == mEndYear && selectedMonth == mEndMonth && selectedDay == mEndDay && selectedHour == mEndHour) {
minMinute = 0;
maxMinute = mEndMinute;
} else {
minMinute = 0;
maxMinute = MAX_MINUTE_UNIT;
}
mMinuteUnits.clear();
for (int i = minMinute; i <= maxMinute; i++) {
mMinuteUnits.add(mDecimalFormat.format(i));
}
mDpvMinute.setDataList(mMinuteUnits);
int selectedMinute = getValueInRange(mSelectedTime.get(Calendar.MINUTE), minMinute, maxMinute);
mSelectedTime.set(Calendar.MINUTE, selectedMinute);
mDpvMinute.setSelected(selectedMinute - minMinute);
if (showAnim) {
mDpvMinute.startAnim();
}
}
setCanScroll();
}
private int getValueInRange(int value, int minValue, int maxValue) {
if (value < minValue) {
return minValue;
} else if (value > maxValue) {
return maxValue;
} else {
return value;
}
}
/**
* 展示时间选择器
*
* @param dateStr 日期字符串,格式为 yyyy-MM-dd 或 yyyy-MM-dd HH:mm
*/
public void show(String dateStr) {
if (!canShow() || TextUtils.isEmpty(dateStr)) return;
// 弹窗时,考虑用户体验,不展示滚动动画
if (setSelectedTime(dateStr, false)) {
mPickerDialog.show();
}
}
private boolean canShow() {
return mCanDialogShow && mPickerDialog != null;
}
/**
* 设置日期选择器的选中时间
*
* @param dateStr 日期字符串
* @param showAnim 是否展示动画
* @return 是否设置成功
*/
public boolean setSelectedTime(String dateStr, boolean showAnim) {
return canShow() && !TextUtils.isEmpty(dateStr)
&& setSelectedTime(DateFormatUtils.str2Long(dateStr, mCanShowPreciseTime), showAnim);
}
/**
* 展示时间选择器
*
* @param timestamp 时间戳,毫秒级别
*/
public void show(long timestamp) {
if (!canShow()) return;
if (setSelectedTime(timestamp, false)) {
mPickerDialog.show();
}
}
/**
* 设置日期选择器的选中时间
*
* @param timestamp 毫秒级时间戳
* @param showAnim 是否展示动画
* @return 是否设置成功
*/
public boolean setSelectedTime(long timestamp, boolean showAnim) {
if (!canShow()) return false;
if (timestamp < mBeginTime.getTimeInMillis()) {
timestamp = mBeginTime.getTimeInMillis();
} else if (timestamp > mEndTime.getTimeInMillis()) {
timestamp = mEndTime.getTimeInMillis();
}
mSelectedTime.setTimeInMillis(timestamp);
mYearUnits.clear();
for (int i = mBeginYear; i <= mEndYear; i++) {
mYearUnits.add(String.valueOf(i));
}
mDpvYear.setDataList(mYearUnits);
mDpvYear.setSelected(mSelectedTime.get(Calendar.YEAR) - mBeginYear);
linkageMonthUnit(showAnim, showAnim ? LINKAGE_DELAY_DEFAULT : 0);
return true;
}
/**
* 设置是否允许点击屏幕或物理返回键关闭
*/
public void setCancelable(boolean cancelable) {
if (!canShow()) return;
mPickerDialog.setCancelable(cancelable);
}
/**
* 设置日期控件是否显示时和分
*/
public void setCanShowPreciseTime(Boolean canShowPreciseTime) {
if (!canShow()) return;
if (canShowPreciseTime) {
initScrollUnit();
mDpvHour.setVisibility(View.VISIBLE);
mTvHourUnit.setVisibility(View.VISIBLE);
mDpvMinute.setVisibility(View.VISIBLE);
mTvMinuteUnit.setVisibility(View.VISIBLE);
} else {
initScrollUnit(SCROLL_UNIT_HOUR, SCROLL_UNIT_MINUTE);
mDpvHour.setVisibility(View.GONE);
mTvHourUnit.setVisibility(View.GONE);
mDpvMinute.setVisibility(View.GONE);
mTvMinuteUnit.setVisibility(View.GONE);
}
mCanShowPreciseTime = canShowPreciseTime;
}
/**
* 设置日期控件是否显示时和分
*/
public void setCanShowPreciseTime1(Boolean canShowPreciseTime) {
if (!canShow()) return;
if (canShowPreciseTime) {
initScrollUnit();
mDpvHour.setVisibility(View.VISIBLE);
mTvHourUnit.setVisibility(View.VISIBLE);
mDpvMinute.setVisibility(View.VISIBLE);
mTvMinuteUnit.setVisibility(View.VISIBLE);
mDpvYear.setVisibility(View.GONE);
mDpvDay.setVisibility(View.GONE);
mDpvMonth.setVisibility(View.GONE);
tv_nian.setVisibility(View.GONE);
tv_yue.setVisibility(View.GONE);
tv_ri.setVisibility(View.GONE);
}
mCanShowPreciseTime = canShowPreciseTime;
}
/**
* 设置日期控件是否显示时和分
*/
public void setCanShowPreciseTimeYear(Boolean canShowPreciseTime) {
if (!canShow()) return;
if (canShowPreciseTime) {
initScrollUnit();
mDpvHour.setVisibility(View.GONE);
mTvHourUnit.setVisibility(View.GONE);
mDpvMinute.setVisibility(View.GONE);
mTvMinuteUnit.setVisibility(View.GONE);
mDpvYear.setVisibility(View.VISIBLE);
mDpvDay.setVisibility(View.GONE);
mDpvMonth.setVisibility(View.GONE);
tv_nian.setVisibility(View.VISIBLE);
tv_yue.setVisibility(View.GONE);
tv_ri.setVisibility(View.GONE);
}
mCanShowPreciseTime = canShowPreciseTime;
}
/**
* 设置日期控件是否显示时和分
*/
public void setCanShowPreciseTimeYearMoon(Boolean canShowPreciseTime) {
if (!canShow()) return;
if (canShowPreciseTime) {
initScrollUnit();
mDpvHour.setVisibility(View.GONE);
mTvHourUnit.setVisibility(View.GONE);
mDpvMinute.setVisibility(View.GONE);
mTvMinuteUnit.setVisibility(View.GONE);
mDpvYear.setVisibility(View.VISIBLE);
mDpvDay.setVisibility(View.GONE);
mDpvMonth.setVisibility(View.VISIBLE);
tv_nian.setVisibility(View.VISIBLE);
tv_yue.setVisibility(View.VISIBLE);
tv_ri.setVisibility(View.GONE);
}
mCanShowPreciseTime = canShowPreciseTime;
}
private void initScrollUnit(Integer... units) {
if (units == null || units.length == 0) {
mScrollUnits = SCROLL_UNIT_HOUR + SCROLL_UNIT_MINUTE;
} else {
for (int unit : units) {
mScrollUnits ^= unit;
}
}
}
/**
* 设置日期控件是否可以循环滚动
*/
public void setScrollLoop(boolean canLoop) {
if (!canShow()) return;
mDpvYear.setCanScrollLoop(canLoop);
mDpvMonth.setCanScrollLoop(canLoop);
mDpvDay.setCanScrollLoop(canLoop);
mDpvHour.setCanScrollLoop(canLoop);
mDpvMinute.setCanScrollLoop(canLoop);
}
/**
* 设置日期控件是否展示滚动动画
*/
public void setCanShowAnim(boolean canShowAnim) {
if (!canShow()) return;
mDpvYear.setCanShowAnim(canShowAnim);
mDpvMonth.setCanShowAnim(canShowAnim);
mDpvDay.setCanShowAnim(canShowAnim);
mDpvHour.setCanShowAnim(canShowAnim);
mDpvMinute.setCanShowAnim(canShowAnim);
}
/**
* 销毁弹窗
*/
public void onDestroy() {
if (mPickerDialog != null) {
mPickerDialog.dismiss();
mPickerDialog = null;
mDpvYear.onDestroy();
mDpvMonth.onDestroy();
mDpvDay.onDestroy();
mDpvHour.onDestroy();
mDpvMinute.onDestroy();
}
}
}

View File

@@ -0,0 +1,154 @@
package com.ckkj.water.utils.ui;
import android.content.Context;
import android.text.TextUtils;
import com.ckkj.water.utils.time.DateFormatUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* author:
* desc:
* version: 1.0.0
*/
public class CustomDatePickerUtil {
/**
* @param startTime eg."2014-05-06"
* @param endTime eg."2019-05-01"
*/
public static void initDatePicker(Boolean isShiFen, Context context, String startTime, String endTime, String zhidingTime, CustomDatePicker.Callback callback) {
CustomDatePicker datePicker;
// long beginTimestamp = DateFormatUtils.str2Long(startTime, false);
//
// long endTimestamp = DateFormatUtils.str2Long(endTime, false);
long beginTimestamp = DateFormatUtils.str2Long(startTime, isShiFen);
long endTimestamp = DateFormatUtils.str2Long(endTime, isShiFen);
// 通过时间戳初始化日期,毫秒级别
datePicker = new CustomDatePicker(context, callback, beginTimestamp, endTimestamp);
// 不允许点击屏幕或物理返回键关闭
datePicker.setCancelable(false);
// 不显示时和分
datePicker.setCanShowPreciseTime(isShiFen);
// 不允许循环滚动
datePicker.setScrollLoop(false);
// 不允许滚动动画
datePicker.setCanShowAnim(false);
SimpleDateFormat simpleDateFormat;
// 1990-01-01
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");// HH:mm:ss
//获取当前时间
Date date = new Date(System.currentTimeMillis());
// time1.setText("Date获取当前日期时间"+simpleDateFormat.format(date));
//显示当前时间
// datePicker.show(simpleDateFormat.format(date));
if (zhidingTime.equals("")) {
datePicker.show(simpleDateFormat.format(date));
} else {
if (zhidingTime.length() == 18) {
datePicker.show(zhidingTime.substring(0, zhidingTime.length() - 3));
} else {
datePicker.show(zhidingTime);
}
}
}
/**
* @param startTime eg."2014-05-06"
* @param endTime eg."2019-05-01" 只显示年
*/
public static void initDatePickerYear(Boolean isShiFen, Context context, String startTime, String endTime, String zhidingTime, CustomDatePicker.Callback callback) {
CustomDatePicker datePicker;
String replaceTimeStart = startTime.replace(".","-");
String replaceTimeEnd = endTime.replace(".","-");
long beginTimestamp = DateFormatUtils.str2Long(replaceTimeStart, false);
long endTimestamp = DateFormatUtils.str2Long(replaceTimeEnd, false);
// 通过时间戳初始化日期,毫秒级别
datePicker = new CustomDatePicker(context, callback, beginTimestamp, endTimestamp);
// 不允许点击屏幕或物理返回键关闭
datePicker.setCancelable(true);
// 不显示时和分
datePicker.setCanShowPreciseTimeYear(isShiFen);
// 不允许循环滚动
datePicker.setScrollLoop(false);
// 不允许滚动动画
datePicker.setCanShowAnim(true);
SimpleDateFormat simpleDateFormat;
// 1990-01-01
simpleDateFormat = new SimpleDateFormat("yyyy");// HH:mm:ss
//获取当前时间
Date date = new Date(System.currentTimeMillis());
// time1.setText("Date获取当前日期时间"+simpleDateFormat.format(date));
//显示当前时间
// datePicker.show(simpleDateFormat.format(date));
if(TextUtils.isEmpty(zhidingTime)){
zhidingTime = "";
}
zhidingTime = zhidingTime.replace(".","-");
if (zhidingTime.equals("")) {
datePicker.show(simpleDateFormat.format(date));
} else {
if (zhidingTime.length() == 18) {
datePicker.show(zhidingTime.substring(0, zhidingTime.length() - 3));
} else {
datePicker.show(zhidingTime);
}
}
}
/**
* @param startTime eg."2014-05-06"
* @param endTime eg."2019-05-01" 只显示年
*/
public static void initDatePickerYearMoon(Boolean showMoon, Context context, String startTime, String endTime, String zhidingTime, CustomDatePicker.Callback callback) {
CustomDatePicker datePicker;
String replaceTimeStart = startTime.replace(".","-");
String replaceTimeEnd = endTime.replace(".","-");
long beginTimestamp = DateFormatUtils.str2Long(replaceTimeStart, false);
long endTimestamp = DateFormatUtils.str2Long(replaceTimeEnd, false);
// 通过时间戳初始化日期,毫秒级别
datePicker = new CustomDatePicker(context, callback, beginTimestamp, endTimestamp);
// 不允许点击屏幕或物理返回键关闭
datePicker.setCancelable(true);
// 不显示时和分
datePicker.setCanShowPreciseTimeYearMoon(showMoon);
// 不允许循环滚动
datePicker.setScrollLoop(false);
// 不允许滚动动画
datePicker.setCanShowAnim(true);
SimpleDateFormat simpleDateFormat;
// 1990-01-01
simpleDateFormat = new SimpleDateFormat("yyyy");// HH:mm:ss
//获取当前时间
Date date = new Date(System.currentTimeMillis());
// time1.setText("Date获取当前日期时间"+simpleDateFormat.format(date));
//显示当前时间
// datePicker.show(simpleDateFormat.format(date));
if(TextUtils.isEmpty(zhidingTime)){
zhidingTime = "";
}
zhidingTime = zhidingTime.replace(".","-");
if (zhidingTime.equals("")) {
datePicker.show(simpleDateFormat.format(date));
} else {
if (zhidingTime.length() == 18) {
datePicker.show(zhidingTime.substring(0, zhidingTime.length() - 3));
} else {
datePicker.show(zhidingTime);
}
}
}
}

View File

@@ -0,0 +1,23 @@
package com.ckkj.water.utils.ui;
import org.json.JSONArray;
import org.json.JSONObject;
public class JsonValidator {
public static boolean isValidJson(String str) {
try {
// 尝试解析为 JSONObject
new JSONObject(str);
return true;
} catch (Exception e) {
try {
// 尝试解析为 JSONArray
new JSONArray(str);
return true;
} catch (Exception ex) {
return false;
}
}
}
}

View File

@@ -0,0 +1,393 @@
package com.ckkj.water.utils.ui;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.core.content.ContextCompat;
import com.ckkj.water.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* 说明:内容选择器,例如年月日、省市区等
* 作者liuwan1992
* 添加时间2016/9/28
* 修改人liuwan1992
* 修改时间2018/12/21
* github: https://github.com/liuwan1992/CustomDatePicker
*/
public class PickerView extends View {
private Context mContext;
private Paint mPaint;
private int mActiveColor, mDarkColor;
private float mHalfWidth, mHalfHeight, mQuarterHeight;
private float mMinTextSize, mTextSizeRange;
private float mTextSpacing, mHalfTextSpacing;
private float mScrollDistance;
private float mLastTouchY;
private List<String> mDataList = new ArrayList<>();
private int mSelectedIndex;
private boolean mCanScroll = true;
private boolean mCanScrollLoop = true;
private OnSelectListener mOnSelectListener;
private ObjectAnimator mScrollAnim;
private boolean mCanShowAnim = true;
private Timer mTimer = new Timer();
private TimerTask mTimerTask;
private Handler mHandler = new ScrollHandler(this);
/**
* 自动回滚到中间的速度
*/
private static final float AUTO_SCROLL_SPEED = 10;
/**
* 透明度:最小 120最大 255极差 135
*/
private static final int TEXT_ALPHA_MIN = 120;
private static final int TEXT_ALPHA_RANGE = 135;
/**
* 选择结果回调接口
*/
public interface OnSelectListener {
void onSelect(View view, String selected);
}
private static class ScrollTimerTask extends TimerTask {
private WeakReference<Handler> mWeakHandler;
private ScrollTimerTask(Handler handler) {
mWeakHandler = new WeakReference<>(handler);
}
@Override
public void run() {
Handler handler = mWeakHandler.get();
if (handler == null) return;
handler.sendEmptyMessage(0);
}
}
private static class ScrollHandler extends Handler {
private WeakReference<PickerView> mWeakView;
private ScrollHandler(PickerView view) {
mWeakView = new WeakReference<>(view);
}
@Override
public void handleMessage(Message msg) {
PickerView view = mWeakView.get();
if (view == null) return;
view.keepScrolling();
}
}
public PickerView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initPaint();
}
private void initPaint() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Style.FILL);
mPaint.setTextAlign(Align.CENTER);
mActiveColor = ContextCompat.getColor(mContext, R.color.color_zhu);
mDarkColor = ContextCompat.getColor(mContext, R.color.color_333333);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mHalfWidth = getMeasuredWidth() / 2f;
int height = getMeasuredHeight();
mHalfHeight = height / 2f;
mQuarterHeight = height / 4f;
float maxTextSize = height / 8f;
mMinTextSize = maxTextSize / 1.2f;
mTextSizeRange = maxTextSize - mMinTextSize;
mTextSpacing = mMinTextSize * 2.8f;
mHalfTextSpacing = mTextSpacing / 2f;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mSelectedIndex >= mDataList.size()) return;
// 绘制选中的 text
drawText(canvas, mActiveColor, mScrollDistance, mDataList.get(mSelectedIndex));
// 绘制选中上方的 text
for (int i = 1; i <= mSelectedIndex; i++) {
drawText(canvas, mDarkColor, mScrollDistance - i * mTextSpacing,
mDataList.get(mSelectedIndex - i));
}
// 绘制选中下方的 text
int size = mDataList.size() - mSelectedIndex;
for (int i = 1; i < size; i++) {
drawText(canvas, mDarkColor, mScrollDistance + i * mTextSpacing,
mDataList.get(mSelectedIndex + i));
}
}
private void drawText(Canvas canvas, int textColor, float offsetY, String text) {
if (TextUtils.isEmpty(text)) return;
float scale = 1 - (float) Math.pow(offsetY / mQuarterHeight, 2);
scale = scale < 0 ? 0 : scale;
mPaint.setTextSize(mMinTextSize + mTextSizeRange * scale);
mPaint.setColor(textColor);
mPaint.setAlpha(TEXT_ALPHA_MIN + (int) (TEXT_ALPHA_RANGE * scale));
// text 居中绘制mHalfHeight + offsetY 是 text 的中心坐标
Paint.FontMetrics fm = mPaint.getFontMetrics();
float baseline = mHalfHeight + offsetY - (fm.top + fm.bottom) / 2f;
canvas.drawText(text, mHalfWidth, baseline, mPaint);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return mCanScroll && super.dispatchTouchEvent(event);
}
@Override
@SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
cancelTimerTask();
mLastTouchY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float offsetY = event.getY();
mScrollDistance += offsetY - mLastTouchY;
if (mScrollDistance > mHalfTextSpacing) {
if (!mCanScrollLoop) {
if (mSelectedIndex == 0) {
mLastTouchY = offsetY;
invalidate();
break;
} else {
mSelectedIndex--;
}
} else {
// 往下滑超过离开距离,将末尾元素移到首位
moveTailToHead();
}
mScrollDistance -= mTextSpacing;
} else if (mScrollDistance < -mHalfTextSpacing) {
if (!mCanScrollLoop) {
if (mSelectedIndex == mDataList.size() - 1) {
mLastTouchY = offsetY;
invalidate();
break;
} else {
mSelectedIndex++;
}
} else {
// 往上滑超过离开距离,将首位元素移到末尾
moveHeadToTail();
}
mScrollDistance += mTextSpacing;
}
mLastTouchY = offsetY;
invalidate();
break;
case MotionEvent.ACTION_UP:
// 抬起手后 mSelectedIndex 由当前位置滚动到中间选中位置
if (Math.abs(mScrollDistance) < 0.01) {
mScrollDistance = 0;
break;
}
cancelTimerTask();
mTimerTask = new ScrollTimerTask(mHandler);
mTimer.schedule(mTimerTask, 0, 10);
break;
}
return true;
}
private void cancelTimerTask() {
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
if (mTimer != null) {
mTimer.purge();
}
}
private void moveTailToHead() {
if (!mCanScrollLoop || mDataList.isEmpty()) return;
String tail = mDataList.get(mDataList.size() - 1);
mDataList.remove(mDataList.size() - 1);
mDataList.add(0, tail);
}
private void moveHeadToTail() {
if (!mCanScrollLoop || mDataList.isEmpty()) return;
String head = mDataList.get(0);
mDataList.remove(0);
mDataList.add(head);
}
private void keepScrolling() {
if (Math.abs(mScrollDistance) < AUTO_SCROLL_SPEED) {
mScrollDistance = 0;
if (mTimerTask != null) {
cancelTimerTask();
if (mOnSelectListener != null && mSelectedIndex < mDataList.size()) {
mOnSelectListener.onSelect(this, mDataList.get(mSelectedIndex));
}
}
} else if (mScrollDistance > 0) {
// 向下滚动
mScrollDistance -= AUTO_SCROLL_SPEED;
} else {
// 向上滚动
mScrollDistance += AUTO_SCROLL_SPEED;
}
invalidate();
}
public int getSelectedIndex() {
return mSelectedIndex;
}
/**
* 设置数据
*/
public void setDataList(List<String> list) {
if (list == null || list.isEmpty()) return;
mDataList = list;
// 重置 mSelectedIndex防止溢出
mSelectedIndex = 0;
invalidate();
}
/**
* 选择选中项
*/
public void setSelected(int index) {
if (index >= mDataList.size()) return;
mSelectedIndex = index;
if (mCanScrollLoop) {
// 可循环滚动时mSelectedIndex 值固定为 mDataList / 2
int position = mDataList.size() / 2 - mSelectedIndex;
if (position < 0) {
for (int i = 0; i < -position; i++) {
moveHeadToTail();
mSelectedIndex--;
}
} else if (position > 0) {
for (int i = 0; i < position; i++) {
moveTailToHead();
mSelectedIndex++;
}
}
}
invalidate();
}
/**
* 设置选择结果监听
*/
public void setOnSelectListener(OnSelectListener listener) {
mOnSelectListener = listener;
}
/**
* 是否允许滚动
*/
public void setCanScroll(boolean canScroll) {
mCanScroll = canScroll;
}
/**
* 是否允许循环滚动
*/
public void setCanScrollLoop(boolean canLoop) {
mCanScrollLoop = canLoop;
}
/**
* 执行滚动动画
*/
public void startAnim() {
if (!mCanShowAnim) return;
if (mScrollAnim == null) {
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.3f, 1f);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.3f, 1f);
mScrollAnim = ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY).setDuration(200);
}
if (!mScrollAnim.isRunning()) {
mScrollAnim.start();
}
}
/**
* 是否允许滚动动画
*/
public void setCanShowAnim(boolean canShowAnim) {
mCanShowAnim = canShowAnim;
}
/**
* 销毁资源
*/
public void onDestroy() {
mOnSelectListener = null;
mHandler.removeCallbacksAndMessages(null);
if (mScrollAnim != null && mScrollAnim.isRunning()) {
mScrollAnim.cancel();
}
cancelTimerTask();
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
}

View File

@@ -0,0 +1,170 @@
package com.ckkj.water.utils.ui;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.DrawableRes;
import com.ckkj.water.utils.OSUtil;
import com.ckkj.water.utils.manager.SystemBarTintManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class StatusBarUtil {
/**
* 设置状态栏为透明
*/
@TargetApi(19)
public static void setTranslucentStatus(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = activity.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
/**
* 修改状态栏颜色支持4.4以上版本 * @param activity * @param colorId
*/
public static void setStatusBarColor(Activity activity, int colorId) {
//Android6.0API 23以上系统方法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.setStatusBarColor(activity.getResources().getColor(colorId));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明
setTranslucentStatus(activity);
//设置状态栏颜色
SystemBarTintManager tintManager = new SystemBarTintManager(activity);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(colorId);
}
}
/**
* 设置状态栏模式
*/
public static void setStatusBarMode(Activity activity, boolean isTextDark, int colorId) {
if (!isTextDark) {
//文字、图标颜色不变,只修改状态栏颜色
setStatusBarColor(activity, colorId);
} else {
//修改状态栏颜色和文字图标颜色
setStatusBarColor(activity, colorId);
//4.4以上才可以改文字图标颜色
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (OSUtil.isMIUI()) {
//小米MIUI系统
setMIUIStatusBarTextMode(activity, isTextDark);
} else if (OSUtil.isFlyme()) {
//魅族flyme系统
setFlymeStatusBarTextMode(activity, isTextDark);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//6.0以上,调用系统方法
Window window = activity.getWindow();
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
} else {
//4.4以上6.0以下的其他系统,暂时没有修改状态栏的文字图标颜色的方法,有可以加上
}
}
}
}
/**
* 设置Flyme系统状态栏的文字图标颜色
*/
public static boolean setFlymeStatusBarTextMode(Activity activity, boolean isDark) {
Window window = activity.getWindow();
boolean result = false;
if (window != null) {
try {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (isDark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
result = true;
} catch (Exception e) {
}
}
return result;
}
/**
* 设置MIUI系统状态栏的文字图标颜色MIUIV6以上
*/
public static boolean setMIUIStatusBarTextMode(Activity activity, boolean isDark) {
boolean result = false;
Window window = activity.getWindow();
if (window != null) {
Class clazz = window.getClass();
try {
int darkModeFlag = 0;
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
if (isDark) {
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
//状态栏透明且黑色字体
} else {
extraFlagField.invoke(window, 0, darkModeFlag);
//清除黑色字体
}
result = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//开发版 7.7.13 及以后版本采用了系统API旧方法无效但不会报错所以两个方式都要加上
if (isDark) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
} catch (Exception e) {
}
}
return result;
}
/**
* 设置状态栏颜色背景图
* @param activity
* @param id
*/
public static void setStatusBarDrawable(Activity activity, @DrawableRes int id) {
//利用反射机制修改状态栏背景
int identifier = activity.getResources().getIdentifier("statusBarBackground", "id", "android");
View statusBarView = activity.getWindow().findViewById(identifier);
if (statusBarView != null) {
statusBarView.setBackgroundResource(id);
}
}
}