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