first
This commit is contained in:
60
app/src/main/java/com/ckkj/water/utils/AppInfoUtil.java
Normal file
60
app/src/main/java/com/ckkj/water/utils/AppInfoUtil.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
446
app/src/main/java/com/ckkj/water/utils/CalendarUtils.java
Normal file
446
app/src/main/java/com/ckkj/water/utils/CalendarUtils.java
Normal 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 小于0:srcData 小于 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;
|
||||
}
|
||||
}
|
||||
|
||||
30
app/src/main/java/com/ckkj/water/utils/ClickUtils.java
Normal file
30
app/src/main/java/com/ckkj/water/utils/ClickUtils.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
app/src/main/java/com/ckkj/water/utils/Cn2Spell.java
Normal file
77
app/src/main/java/com/ckkj/water/utils/Cn2Spell.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
254
app/src/main/java/com/ckkj/water/utils/DownFileUtil.java
Normal file
254
app/src/main/java/com/ckkj/water/utils/DownFileUtil.java
Normal 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,"图片已下载至手机");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
168
app/src/main/java/com/ckkj/water/utils/DownLoadApk.java
Normal file
168
app/src/main/java/com/ckkj/water/utils/DownLoadApk.java
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
app/src/main/java/com/ckkj/water/utils/Dp2PxUtils.java
Normal file
19
app/src/main/java/com/ckkj/water/utils/Dp2PxUtils.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
33
app/src/main/java/com/ckkj/water/utils/FileNameHelper.java
Normal file
33
app/src/main/java/com/ckkj/water/utils/FileNameHelper.java
Normal 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); // 提取扩展名
|
||||
}
|
||||
}
|
||||
196
app/src/main/java/com/ckkj/water/utils/IDCardValidate.java
Normal file
196
app/src/main/java/com/ckkj/water/utils/IDCardValidate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
100
app/src/main/java/com/ckkj/water/utils/LunarDataGenerator.java
Normal file
100
app/src/main/java/com/ckkj/water/utils/LunarDataGenerator.java
Normal 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();
|
||||
|
||||
// 添加 1800–1899 年农历数据
|
||||
for (int year = 1800; year < 1900; year++) {
|
||||
finalArray.put(generateYearJson(year));
|
||||
}
|
||||
|
||||
// 添加已有 1900–2099 数据
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
139
app/src/main/java/com/ckkj/water/utils/OSUtil.java
Normal file
139
app/src/main/java/com/ckkj/water/utils/OSUtil.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
100
app/src/main/java/com/ckkj/water/utils/OfficePreviewUtil.java
Normal file
100
app/src/main/java/com/ckkj/water/utils/OfficePreviewUtil.java
Normal 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 "*/*";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
50
app/src/main/java/com/ckkj/water/utils/PreviewFileUtil.java
Normal file
50
app/src/main/java/com/ckkj/water/utils/PreviewFileUtil.java
Normal 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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
26
app/src/main/java/com/ckkj/water/utils/StorageUtils.java
Normal file
26
app/src/main/java/com/ckkj/water/utils/StorageUtils.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
135
app/src/main/java/com/ckkj/water/utils/UtilApp.java
Normal file
135
app/src/main/java/com/ckkj/water/utils/UtilApp.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
18
app/src/main/java/com/ckkj/water/utils/WeatherIconUtil.java
Normal file
18
app/src/main/java/com/ckkj/water/utils/WeatherIconUtil.java
Normal 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); // 默认图标
|
||||
}
|
||||
}
|
||||
}
|
||||
171
app/src/main/java/com/ckkj/water/utils/YfjJsonHadnlerUtil.java
Normal file
171
app/src/main/java/com/ckkj/water/utils/YfjJsonHadnlerUtil.java
Normal 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;
|
||||
}
|
||||
}
|
||||
29
app/src/main/java/com/ckkj/water/utils/click/ClickUtil.java
Normal file
29
app/src/main/java/com/ckkj/water/utils/click/ClickUtil.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
44
app/src/main/java/com/ckkj/water/utils/click/HapticUtil.java
Normal file
44
app/src/main/java/com/ckkj/water/utils/click/HapticUtil.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 "星座";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
755
app/src/main/java/com/ckkj/water/utils/dataUtil/FileUtil.java
Normal file
755
app/src/main/java/com/ckkj/water/utils/dataUtil/FileUtil.java
Normal 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 "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
31
app/src/main/java/com/ckkj/water/utils/helper/ShiShen.java
Normal file
31
app/src/main/java/com/ckkj/water/utils/helper/ShiShen.java
Normal 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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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; // 理论上不会发生
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.ckkj.water.utils.manager;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* depiction:activity管理工具类
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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); // 秒
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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; // 没有超过两位,不截取
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
255
app/src/main/java/com/ckkj/water/utils/oss/OssUploadHelper.java
Normal file
255
app/src/main/java/com/ckkj/water/utils/oss/OssUploadHelper.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
221
app/src/main/java/com/ckkj/water/utils/show/FL.java
Normal file
221
app/src/main/java/com/ckkj/water/utils/show/FL.java
Normal 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();
|
||||
}
|
||||
}
|
||||
263
app/src/main/java/com/ckkj/water/utils/show/L.java
Normal file
263
app/src/main/java/com/ckkj/water/utils/show/L.java
Normal 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);
|
||||
}
|
||||
}
|
||||
101
app/src/main/java/com/ckkj/water/utils/show/ToastUtil.java
Normal file
101
app/src/main/java/com/ckkj/water/utils/show/ToastUtil.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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("");
|
||||
}
|
||||
}
|
||||
42
app/src/main/java/com/ckkj/water/utils/text/TextUtil.java
Normal file
42
app/src/main/java/com/ckkj/water/utils/text/TextUtil.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
107
app/src/main/java/com/ckkj/water/utils/time/DateFormatUtils.java
Normal file
107
app/src/main/java/com/ckkj/water/utils/time/DateFormatUtils.java
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
566
app/src/main/java/com/ckkj/water/utils/time/DateUtils.java
Normal file
566
app/src/main/java/com/ckkj/water/utils/time/DateUtils.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
205
app/src/main/java/com/ckkj/water/utils/time/TimeTools.java
Normal file
205
app/src/main/java/com/ckkj/water/utils/time/TimeTools.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
977
app/src/main/java/com/ckkj/water/utils/time/ZYTimeUtils.java
Normal file
977
app/src/main/java/com/ckkj/water/utils/time/ZYTimeUtils.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
685
app/src/main/java/com/ckkj/water/utils/ui/CustomDatePicker.java
Normal file
685
app/src/main/java/com/ckkj/water/utils/ui/CustomDatePicker.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
app/src/main/java/com/ckkj/water/utils/ui/JsonValidator.java
Normal file
23
app/src/main/java/com/ckkj/water/utils/ui/JsonValidator.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
393
app/src/main/java/com/ckkj/water/utils/ui/PickerView.java
Normal file
393
app/src/main/java/com/ckkj/water/utils/ui/PickerView.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
170
app/src/main/java/com/ckkj/water/utils/ui/StatusBarUtil.java
Normal file
170
app/src/main/java/com/ckkj/water/utils/ui/StatusBarUtil.java
Normal 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.0(API 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user