diff --git a/app/build.gradle b/app/build.gradle
index ee3f2d8..4d23adb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,8 +16,8 @@ android {
minSdkVersion 24
targetSdkVersion 29
- versionCode 212
- versionName "2.1.2"
+ versionCode 214
+ versionName "2.1.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b067b5c..77ce8e9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -176,6 +176,7 @@
() {
- @Override
- public void onSubscribe(@NonNull Disposable d) {
- Log.e("checkContent", "onSubscribe: ");
- Toaster.show("正在上传");
- mViewDataBinding.tvAdd.setEnabled(false);
- }
-
- @Override
- public void onNext(@NonNull BaseResponse baseResponse) {
- Log.e("checkContent", "onNext: " + baseResponse);
- if (baseResponse.code == 200) {
- Toaster.show("编辑成功");
- mAlarmClockData.setEdited(false);
- AlarmUtils.getInstance().updateAlarmClock(mAlarmClockData);
- finish();
- } else {
- Toaster.show("编辑失败:" + baseResponse.msg);
- }
- }
-
- @Override
- public void onError(@NonNull Throwable e) {
- Log.e("checkContent", "onError: " + e.getMessage());
- mAlarmClockData.setEdited(true);
- AlarmUtils.getInstance().updateAlarmClock(mAlarmClockData);
- onComplete();
- }
-
- @Override
- public void onComplete() {
- Log.e("checkContent", "onComplete: ");
- mViewDataBinding.tvAdd.setEnabled(true);
- finish();
- }
- });
+ if (!TextUtils.isEmpty(mPictrueFilePath)) {
+ MultipartBody.Part body;
+ if (FileUtil.isLocalPath(mPictrueFilePath)) {
+ File picFile = new File(mPictrueFilePath);
+ MediaType mediaType = MediaType.Companion.parse("image/png");
+ RequestBody requestBody = RequestBody.Companion.create(picFile, mediaType);
+ body = MultipartBody.Part.createFormData("file", picFile.getName(), requestBody);
+ } else {
+ String fileName = Utils.getFileNamefromURL(mPictrueFilePath);
+ File picFile = new File(Utils.getDownLoadPath(this) + fileName);
+ MediaType mediaType = MediaType.Companion.parse("image/png");
+ RequestBody requestBody = RequestBody.Companion.create(picFile, mediaType);
+ body = MultipartBody.Part.createFormData("file", picFile.getName(), requestBody);
+ }
+ NetInterfaceManager.getInstance().getAlarmClockEditObservable(params, body)
+ .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY))
+ .subscribe(getAlarmClockEditObserver());
+ } else {
+ NetInterfaceManager.getInstance().getAlarmClockEditObservable(params)
+ .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY))
+ .subscribe(getAlarmClockEditObserver());
+ }
}
}
+ private Observer getAlarmClockEditObserver() {
+ return new Observer() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("checkContent", "onSubscribe: ");
+ Toaster.show("正在上传");
+ mViewDataBinding.tvAdd.setEnabled(false);
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse baseResponse) {
+ Log.e("checkContent", "onNext: " + baseResponse);
+ if (baseResponse.code == 200) {
+ Toaster.show("编辑成功");
+ mAlarmClockData.setEdited(false);
+ AlarmUtils.getInstance().updateAlarmClock(mAlarmClockData);
+ finish();
+ } else {
+ Toaster.show("编辑失败:" + baseResponse.msg);
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("checkContent", "onError: " + e.getMessage());
+ e.printStackTrace();
+ mAlarmClockData.setEdited(true);
+ AlarmUtils.getInstance().updateAlarmClock(mAlarmClockData);
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("checkContent", "onComplete: ");
+ mViewDataBinding.tvAdd.setEnabled(true);
+ finish();
+ }
+ };
+ }
+
private void openSelector() {
PictureSelector.create(AlarmEditActivity.this)
.openGallery(SelectMimeType.ofAll())
diff --git a/app/src/main/java/com/vscool/os/activity/alarm/list/AlarmListActivity.java b/app/src/main/java/com/vscool/os/activity/alarm/list/AlarmListActivity.java
index a19e372..bd50e02 100644
--- a/app/src/main/java/com/vscool/os/activity/alarm/list/AlarmListActivity.java
+++ b/app/src/main/java/com/vscool/os/activity/alarm/list/AlarmListActivity.java
@@ -4,7 +4,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.provider.Settings;
import android.util.Log;
import android.view.View;
@@ -79,9 +78,8 @@ public class AlarmListActivity extends BaseMvvmActivity() {
+ .observeSticky(this, new Observer() {
@Override
public void onChanged(@Nullable MapBean mapBean) {
+ Log.e(TAG, "observeSticky onChanged: ");
mMMKV.encode(CommonConfig.MANUALLY_SELECT_LOCATION_DISTRICT, mapBean.getDistrict());
mMMKV.encode(CommonConfig.MANUALLY_SELECT_LOCATION_TUDE, mapBean.getLongitude() + "," + mapBean.getLatitude());
// mViewDataBinding.tvLocation.setText(mapBean.getDistrict());
@@ -735,9 +733,6 @@ public class MainActivity extends BaseMvvmActivity hourlyBeanList) {
+// if (hourlyBeanList != null && !hourlyBeanList.isEmpty()) {
+// LiveEventBus
+// .get("getWeather24HourlyKey")
+// .post(hourlyBeanList.get(0));
+// }
+// }
+// });
+ weatherManager.getWeather7Day(false, location, new WeatherManager.WeatherDailyCallback() {
+ @Override
+ public void onWeatherDaily(List dailyBeanList) {
+ if (dailyBeanList != null && !dailyBeanList.isEmpty()) {
+ LiveEventBus
+ .get("getWeather7DKey")
+ .post(dailyBeanList.get(0));
+ }
+ }
+ });
+// getWeatherNow(location);
+// getWeather24Hourly(location);
+// getWeather7D(location);
}
+ @Deprecated
private MutableLiveData mNowBaseBeanData = new MutableLiveData<>();
-
public void getWeatherNow(String location) {
Log.e(TAG, "getWeatherNow: " + location);
/**
@@ -134,9 +164,9 @@ public class MainViewModel extends BaseViewModel mHourlyBeanData = new MutableLiveData<>();
-
public void getWeather24Hourly(String location) {
QWeather.getWeather24Hourly(getCtx(), location, new QWeather.OnResultWeatherHourlyListener() {
@Override
@@ -165,9 +195,9 @@ public class MainViewModel extends BaseViewModel DailyBeanData = new MutableLiveData<>();
-
public void getWeather7D(String location) {
QWeather.getWeather7D(getCtx(), location, new QWeather.OnResultWeatherDailyListener() {
@Override
@@ -180,7 +210,6 @@ public class MainViewModel extends BaseViewModel dailyBeans = weatherDailyBean.getDaily();
if (dailyBeans != null && dailyBeans.size() != 0) {
WeatherDailyBean.DailyBean dailyBean = weatherDailyBean.getDaily().get(0);
diff --git a/app/src/main/java/com/vscool/os/activity/setting/SettingActivity.java b/app/src/main/java/com/vscool/os/activity/setting/SettingActivity.java
index db33fbd..252eee3 100644
--- a/app/src/main/java/com/vscool/os/activity/setting/SettingActivity.java
+++ b/app/src/main/java/com/vscool/os/activity/setting/SettingActivity.java
@@ -31,10 +31,12 @@ import com.vscool.os.bean.SystemSettings;
import com.vscool.os.config.CommonConfig;
import com.vscool.os.databinding.ActivitySettingBinding;
import com.vscool.os.dialog.CustomDialog;
+import com.vscool.os.dialog.PermissionsDialog;
import com.vscool.os.service.WeAccessibilityService;
import com.vscool.os.service.main.MainService;
import com.vscool.os.utils.AccessibilityUtils;
import com.vscool.os.utils.ApkUtils;
+import com.vscool.os.utils.FloatingWindowUtils;
import com.vscool.os.view.ToggleButton;
import java.lang.reflect.Field;
@@ -164,14 +166,18 @@ public class SettingActivity extends BaseMvvmActivity>() {
+ @Override
+ public void onChanged(List dailyBeanList) {
+ mViewDataBinding.swipeRefreshLayout.setRefreshing(false);
+ if (dailyBeanList != null) {
+ mWeatherDayApdapter.setDailyBeans(dailyBeanList);
+ }
+ }
+ });
-
- getWeather();
+ getWeather(false);
}
- private void getWeather() {
+ private void getWeather(boolean refresh) {
String district = mMMKV.decodeString(CommonConfig.MANUALLY_SELECT_LOCATION_DISTRICT, CommonConfig.DEFAULT_LOCATION_DISTRICT);
String tude = mMMKV.decodeString(CommonConfig.MANUALLY_SELECT_LOCATION_TUDE, CommonConfig.DEFAULT_LOCATION_TUDE);
if (TextUtils.isEmpty(tude)) {
mViewModel.getLocation();
} else {
mViewDataBinding.tvLocation.setText(district);
- mViewModel.getWeather(tude);
+ mViewModel.getWeather(tude, refresh);
}
}
@@ -239,7 +247,7 @@ public class WeatherActivity extends BaseMvvmActivity() {
+ .observeSticky(this, new Observer() {
@Override
public void onChanged(@Nullable WeatherNowBean.NowBaseBean nowBaseBean) {
- mViewDataBinding.tvTemp.setText(nowBaseBean.getTemp() + "℃");
- if (DayUtils.isNight()) {
+ if (isAdded()) {
+ mViewDataBinding.tvTemp.setText(nowBaseBean.getTemp() + "℃");
+
+ if (DayUtils.isNight()) {
// mViewDataBinding.clWeather.setBackground(mContext.getDrawable(R.drawable.custom_bg_weather_night));
- } else {
- switch (nowBaseBean.getIcon()) {
- default:
- case "100":
- case "150":
- //晴
+ } else {
+ switch (nowBaseBean.getIcon()) {
+ default:
+ case "100":
+ case "150":
+ //晴
// mViewDataBinding.clWeather.setBackground(mContext.getDrawable(R.drawable.custom_bg_weather));
- break;
- case "102":
- case "152":
- //少云
+ break;
+ case "102":
+ case "152":
+ //少云
// mViewDataBinding.clWeather.setBackground(mContext.getDrawable(R.drawable.custom_bg_weather_rain));
- break;
+ break;
+ }
}
- }
// mViewDataBinding.tvWeather.setText(nowBaseBean.getText());
+ }
}
});
- LiveEventBus
- .get("getWeather24HourlyKey", WeatherHourlyBean.HourlyBean.class)
- .observe(this, new Observer() {
- @Override
- public void onChanged(@Nullable WeatherHourlyBean.HourlyBean hourlyBean) {
- String imageName = "he" + hourlyBean.getIcon();
- Log.e(TAG, "onSuccess: " + imageName);
- if (isAdded()) {
-// int resId = getResources().getIdentifier(imageName, "drawable", mContext.getPackageName());
-// Log.e(TAG, "onSuccess: " + resId);
-// if (resId == 0) {
-// mViewDataBinding.ivPic.setImageDrawable(mContext.getDrawable(R.drawable.he100));
-// } else {
-// mViewDataBinding.ivPic.setImageDrawable(mContext.getDrawable(resId));
-// }
- mViewDataBinding.tvTemp.setText(hourlyBean.getTemp() + "℃");
- }
- }
- });
+// LiveEventBus
+// .get("getWeather24HourlyKey", WeatherHourlyBean.HourlyBean.class)
+// .observeSticky(this, new Observer() {
+// @Override
+// public void onChanged(@Nullable WeatherHourlyBean.HourlyBean hourlyBean) {
+// String imageName = "he" + hourlyBean.getIcon();
+// Log.e(TAG, "onSuccess: " + imageName);
+// if (isAdded()) {
+//// int resId = getResources().getIdentifier(imageName, "drawable", mContext.getPackageName());
+//// Log.e(TAG, "onSuccess: " + resId);
+//// if (resId == 0) {
+//// mViewDataBinding.ivPic.setImageDrawable(mContext.getDrawable(R.drawable.he100));
+//// } else {
+//// mViewDataBinding.ivPic.setImageDrawable(mContext.getDrawable(resId));
+//// }
+// mViewDataBinding.tvTemp.setText(hourlyBean.getTemp() + "℃");
+// }
+// }
+// });
LiveEventBus
.get("getWeather7DKey", WeatherDailyBean.DailyBean.class)
- .observe(this, new Observer() {
+ .observeSticky(this, new Observer() {
@Override
public void onChanged(@Nullable WeatherDailyBean.DailyBean dailyBean) {
mViewDataBinding.tvWeather.setText(dailyBean.getTempMin() + "℃ - " + dailyBean.getTempMax() + "℃");
@@ -443,7 +445,7 @@ public class HomeFragment extends BaseMvvmFragment() {
+ .observeSticky(this, new Observer() {
@Override
public void onChanged(@Nullable MapBean mapBean) {
mViewDataBinding.tvLocation.setText(mapBean.getDistrict());
diff --git a/app/src/main/java/com/vscool/os/manager/WeatherManager.java b/app/src/main/java/com/vscool/os/manager/WeatherManager.java
new file mode 100644
index 0000000..e203f3d
--- /dev/null
+++ b/app/src/main/java/com/vscool/os/manager/WeatherManager.java
@@ -0,0 +1,215 @@
+package com.vscool.os.manager;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.qweather.sdk.bean.base.Code;
+import com.qweather.sdk.bean.base.Lang;
+import com.qweather.sdk.bean.base.Unit;
+import com.qweather.sdk.bean.weather.WeatherDailyBean;
+import com.qweather.sdk.bean.weather.WeatherHourlyBean;
+import com.qweather.sdk.bean.weather.WeatherNowBean;
+import com.qweather.sdk.view.QWeather;
+import com.tencent.mmkv.MMKV;
+import com.vscool.os.config.CommonConfig;
+import com.vscool.os.gson.GsonUtils;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+public class WeatherManager {
+ private static final String TAG = "WeatherManager";
+
+ private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
+
+ private Context mContext;
+ private Gson mGson;
+
+
+ /**
+ * 上次获取实时天气时间戳 3小时更新
+ */
+ private static final String GET_WEATHER_NOW_LAST_TIME_KEY = "get_weather_now_last_time_key";
+
+ /**
+ * 上次获取24小时天气时间戳 8小时更新
+ */
+ private static final String GET_WEATHER_24_HOURLY_LAST_TIME_KEY = "get_weather_24_hourly_last_time_key";
+
+ /**
+ * 上次获取7天天气时间戳 24小时更新
+ */
+ private static final String GET_WEATHER_7_DAY_LAST_TIME_KEY = "get_weather_7_day_last_time_key";
+
+ /*实时天气缓存*/
+ private static final String CACHE_WEATHER_NOW_BEAN_KEY = "cache_weather_now_bean_key";
+ /*24小时天气缓存*/
+ private static final String CACHE_WEATHER_HOURLY_BEAN_KEY = "cache_weather_hourly_bean_key";
+ /*7天天气缓存*/
+ private static final String CACHE_WEATHER_DAILY_BEAN_KEY = "cache_weather_daily_bean_key";
+
+ private static final long MINUTE_1_INTERVAL_MS = 60 * 1000; // 1分钟毫秒数
+ private static final long HOURLY_3_INTERVAL_MS = 3 * 60 * 60 * 1000; // 3小时毫秒数
+ private static final long HOURLY_8_INTERVAL_MS = 8 * 60 * 60 * 1000; // 8小时毫秒数
+ private static final long HOURLY_24_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24小时毫秒数
+
+ public WeatherManager(Context context) {
+ this.mContext = context;
+ mGson = new Gson();
+ }
+
+ public interface WeatherNowCallback {
+ void onWeatherNow(WeatherNowBean.NowBaseBean nowBaseBean);
+ }
+
+ public synchronized void getWeatherNow(String location, WeatherNowCallback weatherNowCallback) {
+ long lastTime = mMMKV.decodeLong(GET_WEATHER_NOW_LAST_TIME_KEY, 0);
+ Log.e(TAG, "getWeatherNow: lastTime = " + lastTime);
+ String jsonString = mMMKV.decodeString(CACHE_WEATHER_NOW_BEAN_KEY, "");
+ long time = System.currentTimeMillis();
+
+ if (lastTime == 0 || TextUtils.isEmpty(jsonString) || time - lastTime > HOURLY_3_INTERVAL_MS) {
+ Log.e(TAG, "getWeatherNow: get data");
+ QWeather.getWeatherNow(mContext, location, Lang.ZH_HANS, Unit.METRIC, new QWeather.OnResultWeatherNowListener() {
+ @Override
+ public void onError(Throwable e) {
+ mMMKV.encode(GET_WEATHER_NOW_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeatherNow", "onError: " + e);
+ }
+
+ @Override
+ public void onSuccess(WeatherNowBean weatherBean) {
+ mMMKV.encode(GET_WEATHER_NOW_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeatherNow", "onSuccess: ");
+
+ //先判断返回的status是否正确,当status正确时获取数据,若status不正确,可查看status对应的Code值找到原因
+ if (Code.OK == weatherBean.getCode()) {
+ WeatherNowBean.NowBaseBean now = weatherBean.getNow();
+ mMMKV.encode(CACHE_WEATHER_NOW_BEAN_KEY, GsonUtils.toJSONString(now));
+ if (weatherNowCallback != null) weatherNowCallback.onWeatherNow(now);
+ } else {
+ //在此查看返回数据失败的原因
+ Code code = weatherBean.getCode();
+ Log.d("getWeatherNow", "onSuccess: failed code: " + code);
+ }
+ }
+ });
+ } else {
+ Log.e(TAG, "getWeatherNow: get cache");
+ try {
+ WeatherNowBean.NowBaseBean now = GsonUtils.toJavaObject(jsonString, WeatherNowBean.NowBaseBean.class);
+ if (weatherNowCallback != null) weatherNowCallback.onWeatherNow(now);
+ } catch (Exception e) {
+ Log.e(TAG, "getWeatherNow: " + e.getMessage());
+ mMMKV.remove(CACHE_WEATHER_NOW_BEAN_KEY);
+ }
+ }
+
+ }
+
+ public interface WeatherHourlyCallback {
+ void onWeatherHourly(List hourlyBeanList);
+ }
+
+ public synchronized void getWeather24Hourly(String location, WeatherHourlyCallback weatherHourlyCallback) {
+ long lastTime = mMMKV.decodeLong(GET_WEATHER_24_HOURLY_LAST_TIME_KEY, 0);
+ Log.e(TAG, "getWeather24Hourly: lastTime = " + lastTime);
+ String jsonString = mMMKV.decodeString(CACHE_WEATHER_HOURLY_BEAN_KEY, "");
+ long time = System.currentTimeMillis();
+
+ if (lastTime == 0 || TextUtils.isEmpty(jsonString) || time - lastTime > HOURLY_8_INTERVAL_MS) {
+ Log.e(TAG, "getWeather24Hourly: get data");
+ QWeather.getWeather24Hourly(mContext, location, new QWeather.OnResultWeatherHourlyListener() {
+ @Override
+ public void onError(Throwable throwable) {
+ mMMKV.encode(GET_WEATHER_24_HOURLY_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeather24Hourly", "onError: " + throwable);
+ }
+
+ @Override
+ public void onSuccess(WeatherHourlyBean weatherHourlyBean) {
+ mMMKV.encode(GET_WEATHER_24_HOURLY_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeather24Hourly", "onSuccess: ");
+
+ if (Code.OK == weatherHourlyBean.getCode()) {
+ List hourly = weatherHourlyBean.getHourly();
+ mMMKV.encode(CACHE_WEATHER_HOURLY_BEAN_KEY, GsonUtils.toJSONString(hourly));
+ if (weatherHourlyCallback != null)
+ weatherHourlyCallback.onWeatherHourly(hourly);
+ } else {
+ //在此查看返回数据失败的原因
+ Code code = weatherHourlyBean.getCode();
+ Log.e("getWeather24Hourly", "failed code: " + code);
+ }
+ }
+ });
+
+ } else {
+ Log.e(TAG, "getWeather24Hourly: get cache");
+ try {
+ Type type = new TypeToken>() {
+ }.getType();
+ List hourly = mGson.fromJson(jsonString, type);
+ if (weatherHourlyCallback != null) weatherHourlyCallback.onWeatherHourly(hourly);
+ } catch (Exception e) {
+ Log.e(TAG, "getWeather24Hourly: " + e.getMessage());
+ mMMKV.remove(CACHE_WEATHER_HOURLY_BEAN_KEY);
+ }
+ }
+ }
+
+ public interface WeatherDailyCallback {
+ void onWeatherDaily(List dailyBeanList);
+ }
+
+ public synchronized void getWeather7Day(boolean refresh, String location, WeatherDailyCallback weatherDailyCallback) {
+ Log.e(TAG, "getWeather7Day: refresh = " + refresh);
+ long lastTime = mMMKV.decodeLong(GET_WEATHER_7_DAY_LAST_TIME_KEY, 0);
+ Log.e(TAG, "getWeather7Day: lastTime = " + lastTime);
+ String jsonString = mMMKV.decodeString(CACHE_WEATHER_DAILY_BEAN_KEY, "");
+ long time = System.currentTimeMillis();
+
+ if (lastTime == 0 || TextUtils.isEmpty(jsonString) || refresh ? time - lastTime > MINUTE_1_INTERVAL_MS : time - lastTime > HOURLY_24_INTERVAL_MS) {
+ Log.e(TAG, "getWeather7Day: get data");
+ QWeather.getWeather7D(mContext, location, new QWeather.OnResultWeatherDailyListener() {
+ @Override
+ public void onError(Throwable throwable) {
+ mMMKV.encode(GET_WEATHER_7_DAY_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeather7Day", "onError: " + throwable.getMessage());
+ }
+
+ @Override
+ public void onSuccess(WeatherDailyBean weatherDailyBean) {
+ mMMKV.encode(GET_WEATHER_7_DAY_LAST_TIME_KEY, System.currentTimeMillis());
+ Log.e("getWeather7Day", "onSuccess: ");
+
+ if (Code.OK == weatherDailyBean.getCode()) {
+ List dailyBeans = weatherDailyBean.getDaily();
+ mMMKV.encode(CACHE_WEATHER_DAILY_BEAN_KEY, GsonUtils.toJSONString(dailyBeans));
+ if (weatherDailyCallback != null)
+ weatherDailyCallback.onWeatherDaily(dailyBeans);
+ } else {
+ //在此查看返回数据失败的原因
+ Code code = weatherDailyBean.getCode();
+ Log.e("getWeather7Day", "failed code: " + code);
+ }
+ }
+ });
+
+ } else {
+ Log.e(TAG, "getWeather7Day: get cache");
+ try {
+ Type type = new TypeToken>() {
+ }.getType();
+ List dailyBeans = mGson.fromJson(jsonString, type);
+ if (weatherDailyCallback != null) weatherDailyCallback.onWeatherDaily(dailyBeans);
+ } catch (Exception e) {
+ Log.e(TAG, "getWeather7Day: " + e.getMessage());
+ mMMKV.remove(CACHE_WEATHER_DAILY_BEAN_KEY);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/vscool/os/network/NetInterfaceManager.java b/app/src/main/java/com/vscool/os/network/NetInterfaceManager.java
index 5bb48f1..2d7334b 100644
--- a/app/src/main/java/com/vscool/os/network/NetInterfaceManager.java
+++ b/app/src/main/java/com/vscool/os/network/NetInterfaceManager.java
@@ -473,6 +473,13 @@ public class NetInterfaceManager {
.observeOn(AndroidSchedulers.mainThread());
}
+ public Observable getAlarmClockEditObservable(Map params) {
+ return mRetrofit.create(AlarmClockEditApi.class)
+ .editAlarmClock(params)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
public Observable> getAlarmClockByIdObservable(int id) {
return mRetrofit.create(AlarmClockQueryApi.class)
.getAlarmClockById(Utils.getSerial(), id)
diff --git a/app/src/main/java/com/vscool/os/network/api/uiui/alarmclock/AlarmClockEditApi.java b/app/src/main/java/com/vscool/os/network/api/uiui/alarmclock/AlarmClockEditApi.java
index dbc9bde..728f571 100644
--- a/app/src/main/java/com/vscool/os/network/api/uiui/alarmclock/AlarmClockEditApi.java
+++ b/app/src/main/java/com/vscool/os/network/api/uiui/alarmclock/AlarmClockEditApi.java
@@ -19,4 +19,9 @@ public interface AlarmClockEditApi {
@QueryMap Map params,
@Part MultipartBody.Part body
);
+
+ @POST(UrlAddress.ALARM_CLOCK_EDIT)
+ Observable editAlarmClock(
+ @QueryMap Map params
+ );
}
diff --git a/app/src/main/java/com/vscool/os/service/main/MainService.java b/app/src/main/java/com/vscool/os/service/main/MainService.java
index a016da7..45848bb 100644
--- a/app/src/main/java/com/vscool/os/service/main/MainService.java
+++ b/app/src/main/java/com/vscool/os/service/main/MainService.java
@@ -230,12 +230,7 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
setAlarmTime();
registerTimeChangedReceiver();
- registerAlarmReceiver();
- registFastCallReceive();
- registerLockScreenReceiver();
- registerOperateAlarmClockReceiver();
- registerScreenLockReceiver();
- registerSmsReceiver();
+ registerReceivers();
Observable.create(new ObservableOnSubscribe() {
@Override
@@ -338,6 +333,31 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
Log.e(TAG, "onDestroy: ");
mPresenter.detachView();
NetworkUtils.unregisterNetworkStatusChangedListener(this);
+ unregisterReceivers();
+
+ if (mSoundPool != null) {
+ mSoundPool.release();
+ mSoundPool = null;
+ }
+ }
+
+ public boolean isScreenOn() {
+ PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ // true为打开,false为关闭
+ return powerManager.isInteractive();
+ }
+
+ private void registerReceivers() {
+ registerAlarmReceiver();
+ registFastCallReceive();
+ registerLockScreenReceiver();
+ registerOperateAlarmClockReceiver();
+ registerScreenLockReceiver();
+ registerSmsReceiver();
+ registerUpdateDesktopReceiver();
+ }
+
+ private void unregisterReceivers() {
if (alarmReceiver != null) {
unregisterReceiver(alarmReceiver);
}
@@ -359,19 +379,11 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
if (mSmsReceiver != null) {
unregisterReceiver(mSmsReceiver);
}
-
- if (mSoundPool != null) {
- mSoundPool.release();
- mSoundPool = null;
+ if (mUpdateSettingsReceiver != null) {
+ unregisterReceiver(mUpdateSettingsReceiver);
}
}
- public boolean isScreenOn() {
- PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
- // true为打开,false为关闭
- return powerManager.isInteractive();
- }
-
public static final String ALARMWAKEUP = "AIOS_ALARM_WAKEUP";
private void registerAlarmReceiver() {
@@ -809,6 +821,48 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
private SmsReceiver mSmsReceiver;
+ private static final String UPDATE_DESKTOP_SETTINGS_APP_KEY = "UPDATE_DESKTOP_SETTINGS_APP";
+ private static final String UPDATE_DESKTOP_SETTINGS_CLOCK_KEY = "UPDATE_DESKTOP_SETTINGS_CLCOK";
+ private static final String UPDATE_DESKTOP_SETTINGS_SOS_KEY = "UPDATE_DESKTOP_SETTINGS_SOS";
+ private static final String UPDATE_DESKTOP_SETTINGS_FLOAT_KEY = "UPDATE_DESKTOP_SETTINGS_FLOAT";
+ private static final String UPDATE_DESKTOP_SETTINGS_HOME_KEY = "UPDATE_DESKTOP_SETTINGS_HOME";
+ private static final String UPDATE_DESKTOP_SETTINGS_TIME_KEY = "UPDATE_DESKTOP_SETTINGS_TIME";
+ private static final String UPDATE_DESKTOP_SETTINGS_ANSWER_KEY = "UPDATE_DESKTOP_SETTINGS_ANSWER";
+
+ private UpdateSettingsReceiver mUpdateSettingsReceiver;
+
+ private void registerUpdateDesktopReceiver() {
+ if (mUpdateSettingsReceiver == null) {
+ mUpdateSettingsReceiver = new UpdateSettingsReceiver();
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_APP_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_CLOCK_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_SOS_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_FLOAT_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_HOME_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_TIME_KEY);
+ filter.addAction(UPDATE_DESKTOP_SETTINGS_ANSWER_KEY);
+ registerReceiver(mUpdateSettingsReceiver, filter);
+ }
+
+ class UpdateSettingsReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.e(TAG, "onReceive: " + action);
+ if (TextUtils.isEmpty(action)) return;
+ switch (action) {
+ case UPDATE_DESKTOP_SETTINGS_CLOCK_KEY:
+ int alarm_clock_ctrl = intent.getIntExtra("alarm_clock_ctrl", 1);
+ mMMKV.encode(CommonConfig.ALARM_CLOCK_CTRL, alarm_clock_ctrl);
+ break;
+ }
+ }
+ }
+
/**
* 显示弹出框
*/
diff --git a/app/src/main/java/com/vscool/os/utils/ContactsUtils.java b/app/src/main/java/com/vscool/os/utils/ContactsUtils.java
index 7264e00..5895535 100644
--- a/app/src/main/java/com/vscool/os/utils/ContactsUtils.java
+++ b/app/src/main/java/com/vscool/os/utils/ContactsUtils.java
@@ -15,17 +15,17 @@ import android.text.TextUtils;
import android.util.Log;
import com.bumptech.glide.Glide;
+import com.tencent.mmkv.MMKV;
import com.vscool.os.R;
import com.vscool.os.bean.Contact;
-import com.vscool.os.bean.ContactId;
+import com.vscool.os.config.CommonConfig;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
+import java.util.Objects;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
@@ -189,26 +189,31 @@ public class ContactsUtils {
}
public static void updateContactPhone(Context context, Contact contact, Bitmap bitmap) {
- long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
- Log.e(TAG, "updateContactPhone: rawContactId = " + rawContactId);
- ContentResolver resolver = context.getContentResolver();
+ String name = getContactNameFromNumber(context, contact.getMobile());
+ Log.e(TAG, "updateContactPhone: " + name);
+ if (!Objects.equals(name, contact.getName())) {
+ long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
+ Log.e(TAG, "updateContactPhone: rawContactId = " + rawContactId);
+ updateContactNameByNumber(context, contact.getMobile(), contact.getName());
- ContentValues values = new ContentValues();
- values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
- values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
- values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contact.getName());
- resolver.insert(ContactsContract.Data.CONTENT_URI, values);
+ ContentResolver resolver = context.getContentResolver();
- values.clear();
+ ContentValues values = new ContentValues();
+ values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
+ values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
+ values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contact.getName());
+ resolver.insert(ContactsContract.Data.CONTENT_URI, values);
- values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
- values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, out.toByteArray());
- resolver.insert(ContactsContract.Data.CONTENT_URI, values);
+ values.clear();
- values.clear();
+ values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+ values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
+ values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, out.toByteArray());
+ resolver.insert(ContactsContract.Data.CONTENT_URI, values);
+
+ values.clear();
// values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
// values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
@@ -228,7 +233,85 @@ public class ContactsUtils {
// values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
// values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
// Log.d("updateContact", "values已经产生");
-// int result = resolver.update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(bean.getId())});
+
+// int result = resolver.update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)});
+// Log.e(TAG, "updateContactPhone: " + result);
+ } else {
+ Log.e(TAG, "updateContactPhone: same contact info");
+ }
+ }
+
+ private static String getContactNameFromNumber(Context context, String phoneNumber) {
+ String contactName = null;
+ Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
+ String[] projection = {ContactsContract.PhoneLookup.DISPLAY_NAME};
+
+ try (Cursor cursor = context.getContentResolver().query(lookupUri, projection, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
+ }
+ } catch (Exception e) {
+ Log.e("ContactQuery", "查询失败", e);
+ }
+ return contactName != null ? contactName : "未知号码";
+ }
+
+ public static void editContactPhone(Context context, long contactId, Contact contact) {
+ if (contactId == -1) {
+ saveContactPhone(context, contact);
+ } else {
+ // 2. 获取所有关联的RawContact ID
+ List rawContactIds = getRawContactIds(context, contactId);
+ if (rawContactIds.isEmpty()) {
+ Log.e("UpdateContact", "rawContactIds is empty");
+ return;
+ }
+
+ // 3. 构建批量操作
+ ArrayList ops = new ArrayList<>();
+ for (Long rawId : rawContactIds) {
+ // 更新现有姓名(如果存在)
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
+ .withSelection(
+ ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
+ ContactsContract.Data.MIMETYPE + "=?",
+ new String[]{String.valueOf(rawId), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE}
+ )
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName())
+ .build());
+
+ // 插入新姓名(如果原数据不存在)
+// ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+// .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawId)
+// .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+// .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName())
+// .withYieldAllowed(true)
+// .build());
+
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
+ .withSelection(
+ ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
+ ContactsContract.Data.MIMETYPE + "=? AND " +
+ ContactsContract.CommonDataKinds.Phone.TYPE + "=?",
+ new String[]{
+ String.valueOf(rawId),
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
+ String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
+ }
+ )
+ .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.getMobile())
+ .build());
+ }
+
+ // 4. 执行修改
+ try {
+ context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+ context.getContentResolver().notifyChange(ContactsContract.Data.CONTENT_URI, null); // 通知数据变更
+ Log.i("UpdateContact", "姓名已更新为: " + contact.getName());
+ } catch (Exception e) {
+ Log.e("UpdateContact", "修改失败", e);
+ }
+ }
}
public static void updateContactPhone(Context context, Contact contact) {
@@ -243,6 +326,90 @@ public class ContactsUtils {
resolver.insert(ContactsContract.Data.CONTENT_URI, values);
}
+ private static void updateContactNameByNumber(Context context, String phoneNumber, String newName) {
+ // 1. 根据号码查找联系人ID
+ long contactId = findContactIdByPhoneNumber(context, phoneNumber);
+ if (contactId == -1) {
+ Log.e("UpdateContact", "未找到匹配的联系人");
+ return;
+ }
+
+ // 2. 获取所有关联的RawContact ID
+ List rawContactIds = getRawContactIds(context, contactId);
+ if (rawContactIds.isEmpty()) {
+ Log.e("UpdateContact", "rawContactIds is empty");
+ return;
+ }
+
+ // 3. 构建批量操作
+ ArrayList ops = new ArrayList<>();
+ for (Long rawId : rawContactIds) {
+ // 更新现有姓名(如果存在)
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
+ .withSelection(
+ ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
+ ContactsContract.Data.MIMETYPE + "=?",
+ new String[]{String.valueOf(rawId), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE}
+ )
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, newName)
+ .build());
+
+ // 插入新姓名(如果原数据不存在)
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawId)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, newName)
+ .withYieldAllowed(true)
+ .build());
+ }
+
+ // 4. 执行修改
+ try {
+ context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+ context.getContentResolver().notifyChange(ContactsContract.Data.CONTENT_URI, null); // 通知数据变更
+ Log.i("UpdateContact", "姓名已更新为: " + newName);
+ } catch (Exception e) {
+ Log.e("UpdateContact", "修改失败", e);
+ }
+ }
+
+ // 根据号码查询联系人ID
+ public static long findContactIdByPhoneNumber(Context context, String phoneNumber) {
+ Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
+ Cursor cursor = context.getContentResolver().query(
+ uri,
+ new String[]{ContactsContract.PhoneLookup._ID},
+ null, null, null
+ );
+
+ if (cursor != null && cursor.moveToFirst()) {
+ long contactId = cursor.getLong(0);
+ cursor.close();
+ return contactId;
+ }
+ return -1;
+ }
+
+ // 获取联系人所有RawContact ID
+ private static List getRawContactIds(Context context, long contactId) {
+ List rawIds = new ArrayList<>();
+ Cursor cursor = context.getContentResolver().query(
+ ContactsContract.RawContacts.CONTENT_URI,
+ new String[]{ContactsContract.RawContacts._ID},
+ ContactsContract.RawContacts.CONTACT_ID + "=?",
+ new String[]{String.valueOf(contactId)},
+ null
+ );
+
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ rawIds.add(cursor.getLong(0));
+ }
+ cursor.close();
+ }
+ return rawIds;
+ }
+
public static void update(Context context, Contact contact, Bitmap bitmap) {
long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
@@ -393,6 +560,32 @@ public class ContactsUtils {
return -1;
}
+ public static String getRawContactName(Context context, String phoneNum) {
+ ContentResolver resolver = context.getContentResolver();
+ Cursor cursor = null;
+ try {
+ cursor = resolver.query(ContactsContract.Data.CONTENT_URI,
+ new String[]{ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.CommonDataKinds.Phone.NUMBER,
+ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME},
+ ContactsContract.CommonDataKinds.Phone.NUMBER + "=?", new String[]{phoneNum}, null);
+ if (cursor.moveToFirst()) {
+ String displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
+ Log.e(TAG, "getRawContactName: displayName = " + displayName);
+ String name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
+ Log.e(TAG, "getRawContactName: rawName = " + name);
+ return name;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "getRawContactName: " + e.getMessage());
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return "";
+ }
+
/**
* 添加联系人信息
*/
@@ -557,32 +750,6 @@ public class ContactsUtils {
// cursor.close();
}
- public static List getLocalContacts(Context context) {
- ContentResolver resolver = context.getContentResolver();
- Uri uri = ContactsContract.Contacts.CONTENT_URI;
- Cursor cursor = resolver.query(uri, null, null, null, null);
- List contactIds = new ArrayList<>();
- while (cursor.moveToNext()) {
- long id = cursor.getLong(cursor.getColumnIndexOrThrow("name_raw_contact_id"));
- int in_phone = cursor.getInt(cursor.getColumnIndexOrThrow("indicate_phone_or_sim_contact"));
- String display_name = cursor.getString(cursor.getColumnIndexOrThrow("display_name"));
- String photo_uri = cursor.getString(cursor.getColumnIndexOrThrow("photo_uri"));
-
- ContactId contactId = new ContactId(id, in_phone, display_name, photo_uri);
- contactIds.add(contactId);
- }
- cursor.close();
- List filter = contactIds.stream().filter(new Predicate() {
- @Override
- public boolean test(ContactId contactId) {
- return contactId.getInPhone() == -1;
- }
- }).collect(Collectors.toList());
- Log.e(TAG, "getLocalContacts: " + filter);
- return filter;
- }
-
-
/**
* 判断某个手机号是否存在
*/
@@ -639,5 +806,33 @@ public class ContactsUtils {
return -1;
}
+ public static final String NAME = "name";
+ public static final String NUMBER = "number";
+ public static List getSIMContacts(Context context) {
+ List contactList = new ArrayList<>();
+ MMKV mmkv = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
+// boolean show_sim = mmkv.decodeInt(CommonConfig.SHOW_SIM_CARD_CONTACT, 0) == 1;
+// if (!show_sim) {
+// return contactList;
+// }
+ ContentResolver resolver = context.getContentResolver();
+ // 获取Sims卡联系人
+ Uri uri = Uri.parse("content://icc/adn");
+ Cursor phoneCursor = resolver.query(uri, null, null, null, null);
+ if (phoneCursor != null) {
+ final int colName = phoneCursor.getColumnIndex(NAME);
+ final int colNumber = phoneCursor.getColumnIndex(NUMBER);
+ while (phoneCursor.moveToNext()) {
+ String number = phoneCursor.getString(colNumber);
+ // 当手机号码为空的或者为空字段 跳过当前循环
+ String username = phoneCursor.getString(colName);
+ Log.e(TAG, "getSIMContacts: number = " + number + " username = " + username);
+ Contact contact = new Contact(username, number, true);
+ contactList.add(contact);
+ }
+ phoneCursor.close();
+ }
+ return contactList;
+ }
}
diff --git a/app/src/main/java/com/vscool/os/utils/FloatingWindowUtils.java b/app/src/main/java/com/vscool/os/utils/FloatingWindowUtils.java
new file mode 100644
index 0000000..eece08e
--- /dev/null
+++ b/app/src/main/java/com/vscool/os/utils/FloatingWindowUtils.java
@@ -0,0 +1,68 @@
+package com.vscool.os.utils;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Build;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class FloatingWindowUtils {
+
+ private static final String TAG = "FloatingWindowUtils";
+
+ public static boolean checkIsHuaweiRom() {
+ Log.e(TAG, "checkIsHuaweiRom: " + Build.MANUFACTURER);
+ return Build.MANUFACTURER.contains("HUAWEI") || Build.MANUFACTURER.contains("HONOR");
+ }
+
+ /***
+ * 检查悬浮窗开启权限
+ * @param context
+ * @return
+ */
+ public static boolean checkFloatPermission(Context context) {
+ //华为和荣耀最后返回的数据有问题
+ if (checkIsHuaweiRom()) {
+ return Settings.canDrawOverlays(context);
+ }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
+ return true;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ try {
+ Class cls = Class.forName("android.content.Context");
+ Field declaredField = cls.getDeclaredField("APP_OPS_SERVICE");
+ declaredField.setAccessible(true);
+ Object obj = declaredField.get(cls);
+ if (!(obj instanceof String)) {
+ return false;
+ }
+ String str2 = (String) obj;
+ obj = cls.getMethod("getSystemService", String.class).invoke(context, str2);
+ cls = Class.forName("android.app.AppOpsManager");
+ Field declaredField2 = cls.getDeclaredField("MODE_ALLOWED");
+ declaredField2.setAccessible(true);
+ Method checkOp = cls.getMethod("checkOp", Integer.TYPE, Integer.TYPE, String.class);
+ int result = (Integer) checkOp.invoke(obj, 24, Binder.getCallingUid(), context.getPackageName());
+ return result == declaredField2.getInt(cls);
+ } catch (Exception e) {
+ return false;
+ }
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ AppOpsManager appOpsMgr = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ if (appOpsMgr == null)
+ return false;
+ int mode = appOpsMgr.checkOpNoThrow("android:system_alert_window", android.os.Process.myUid(), context
+ .getPackageName());
+ return Settings.canDrawOverlays(context) || mode == AppOpsManager.MODE_ALLOWED || mode == AppOpsManager.MODE_IGNORED;
+ } else {
+ return Settings.canDrawOverlays(context);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_alarm_edit.xml b/app/src/main/res/layout/activity_alarm_edit.xml
index 124ffd7..a7bca47 100644
--- a/app/src/main/res/layout/activity_alarm_edit.xml
+++ b/app/src/main/res/layout/activity_alarm_edit.xml
@@ -53,7 +53,7 @@
+ app:layout_constraintBottom_toTopOf="@+id/cl_bottom"
+ app:layout_constraintTop_toBottomOf="@+id/cl_exit">
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml
index 5135e3a..d6f7234 100644
--- a/app/src/main/res/layout/activity_setting.xml
+++ b/app/src/main/res/layout/activity_setting.xml
@@ -110,7 +110,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:maxLines="1"
- android:text="主页按钮"
+ android:text="悬浮主页"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
@@ -144,7 +144,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:maxLines="1"
- android:text="语音播报"
+ android:text="来电和短信播报"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
@@ -177,7 +177,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:maxLines="1"
- android:text="自动接听"
+ android:text="微信自动接听"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/app/src/main/res/layout/dialog_permissions.xml b/app/src/main/res/layout/dialog_permissions.xml
new file mode 100644
index 0000000..5bf279e
--- /dev/null
+++ b/app/src/main/res/layout/dialog_permissions.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 9679e25..82266a5 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -21,6 +21,7 @@
#FFD3D3D3
#4880ff
#F8B551
+ #0166ff
#4D3AD8
#221C27
#bbbbbb