version:2.0.7

bugfixes:修复闹钟黑屏
update:增加报时亮屏,优化闹钟排序,显示优化
This commit is contained in:
2025-02-10 17:04:15 +08:00
parent 17a9c60979
commit e4ce6a79c0
21 changed files with 318 additions and 121 deletions

View File

@@ -16,8 +16,8 @@ android {
minSdkVersion 24
targetSdkVersion 29
versionCode 207
versionName "2.0.6"
versionCode 208
versionName "2.0.7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -31,7 +31,7 @@ import com.vscool.os.databinding.ActivityAlarmAddBinding;
import com.vscool.os.service.main.MainService;
import com.vscool.os.utils.FFmpegUtils;
import com.vscool.os.utils.FileUtil;
import com.vscool.os.utils.ScreenUtil;
import com.vscool.os.utils.ScreenUtils;
import com.vscool.os.utils.TimeUtils;
import java.io.File;
@@ -135,7 +135,7 @@ public class AlarmAddActivity extends BaseMvvmActivity<AlarmAddViewModel, Activi
mPictrueFilePath = result.get(0).getRealPath();
File file = new File(mPictrueFilePath);
if (file.exists()) {
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtil.dip2px(AlarmAddActivity.this, 8F)));
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(AlarmAddActivity.this, 8F)));
Glide.with(mViewDataBinding.nvPic).load(file).apply(options).into(mViewDataBinding.nvPic);
mViewDataBinding.nvPic.setVisibility(View.VISIBLE);
mViewDataBinding.clPic.setVisibility(View.GONE);
@@ -259,6 +259,7 @@ public class AlarmAddActivity extends BaseMvvmActivity<AlarmAddViewModel, Activi
@Override
public void onClick(View view) {
mDayType = 1;
mViewDataBinding.tvType.setText("一次");
mTypePopupWindow.dismiss();
}
});
@@ -267,6 +268,7 @@ public class AlarmAddActivity extends BaseMvvmActivity<AlarmAddViewModel, Activi
@Override
public void onClick(View view) {
mDayType = 2;
mViewDataBinding.tvType.setText("每天");
mTypePopupWindow.dismiss();
}
});

View File

@@ -36,7 +36,7 @@ import com.vscool.os.network.NetInterfaceManager;
import com.vscool.os.utils.FFmpegUtils;
import com.vscool.os.utils.FileUtil;
import com.vscool.os.utils.GlideLoadUtils;
import com.vscool.os.utils.ScreenUtil;
import com.vscool.os.utils.ScreenUtils;
import com.vscool.os.utils.TimeUtils;
import com.vscool.os.utils.Utils;
@@ -262,7 +262,7 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
mPictrueFilePath = result.get(0).getRealPath();
File file = new File(mPictrueFilePath);
if (file.exists()) {
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtil.dip2px(AlarmEditActivity.this, 8F)));
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(AlarmEditActivity.this, 8F)));
Glide.with(mViewDataBinding.nvPic).load(file).apply(options).into(mViewDataBinding.nvPic);
mViewDataBinding.nvPic.setVisibility(View.VISIBLE);
mViewDataBinding.clPic.setVisibility(View.GONE);
@@ -405,6 +405,7 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
@Override
public void onClick(View view) {
mDayType = 1;
mViewDataBinding.tvType.setText("一次");
mTypePopupWindow.dismiss();
}
});
@@ -413,6 +414,7 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
@Override
public void onClick(View view) {
mDayType = 2;
mViewDataBinding.tvType.setText("每天");
mTypePopupWindow.dismiss();
}
});

View File

@@ -37,7 +37,7 @@ import com.vscool.os.network.NetInterfaceManager;
import com.vscool.os.network.UrlAddress;
import com.vscool.os.utils.ContactsUtils;
import com.vscool.os.utils.LocalContactUtils;
import com.vscool.os.utils.ScreenUtil;
import com.vscool.os.utils.ScreenUtils;
import com.xiasuhuei321.loadingdialog.view.LoadingDialog;
import com.zackratos.ultimatebarx.ultimatebarx.UltimateBarXKt;
import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX;
@@ -106,7 +106,7 @@ public class AddContactActivity extends BaseMvvmActivity<AddContactViewModel, Ac
mLoadingDialog.loadSuccess();
finish();
} else {
mLoadingDialog.loadFailed();
mLoadingDialog.loadSuccess();
}
}
});
@@ -144,7 +144,7 @@ public class AddContactActivity extends BaseMvvmActivity<AddContactViewModel, Ac
mViewModel.avatarFilePath = result.get(0).getRealPath();
File file = new File(mViewModel.avatarFilePath);
if (file.exists()) {
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtil.dip2px(AddContactActivity.this, 8F)));
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(AddContactActivity.this, 8F)));
Glide.with(mViewDataBinding.nvAvatar).load(file).apply(options).into(mViewDataBinding.nvAvatar);
} else {
mViewModel.avatarFilePath = "";

View File

@@ -28,7 +28,7 @@ import com.vscool.os.bean.Contact;
import com.vscool.os.custom.GlideEngine;
import com.vscool.os.databinding.ActivityContactEditBinding;
import com.vscool.os.utils.FileUtil;
import com.vscool.os.utils.ScreenUtil;
import com.vscool.os.utils.ScreenUtils;
import com.vscool.os.utils.Utils;
import com.xiasuhuei321.loadingdialog.view.LoadingDialog;
@@ -134,7 +134,7 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
mPictrueFilePath = result.get(0).getRealPath();
File file = new File(mPictrueFilePath);
if (file.exists()) {
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtil.dip2px(EditContactActivity.this, 8F)));
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(EditContactActivity.this, 8F)));
Glide.with(mViewDataBinding.nvAvatar).load(file).apply(options).into(mViewDataBinding.nvAvatar);
} else {
mPictrueFilePath = "";

View File

@@ -201,7 +201,8 @@ public class EmergencyActivity extends BaseMvvmActivity<EmergencyViewModel, Acti
}
});
} else {
Toaster.showLong("已呼叫所有联系人");
Log.e(TAG, "onStart: 已呼叫所有联系人");
// Toaster.showLong("已呼叫所有联系人");
finish();
}
} else {

View File

@@ -57,10 +57,12 @@ public class NoticeActivity extends BaseDataBindingActivity {
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "WakeAndLock");
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mWakeLock.acquire(60 * 1000L);
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {1000, 5000, 1000, 5000};
mVibrator.vibrate(pattern, 0);
WakeUpUtils.wakeUpAndUnlockScreen(this);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

View File

@@ -76,7 +76,6 @@ public class NoticeInfoActivity extends BaseMvvmActivity<NoticeInfoViewModel, Ac
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "WakeAndLock");
// mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
@@ -94,6 +93,7 @@ public class NoticeInfoActivity extends BaseMvvmActivity<NoticeInfoViewModel, Ac
mAlarmClockData = oldData.get(mId);
if (mAlarmClockData == null) {
finish();
return;
}
Log.e(TAG, "onCreate: " + mAlarmClockData);
showPic(mAlarmClockData);
@@ -179,18 +179,19 @@ public class NoticeInfoActivity extends BaseMvvmActivity<NoticeInfoViewModel, Ac
mViewDataBinding.clVoice.setVisibility(View.GONE);
}
String filePath = alarmClockData.getFile();
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(this, 16F)));
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length());
String realPath = Utils.getDownLoadPath(NoticeInfoActivity.this) + fileName;
File file = new File(realPath);
if (file.exists()) {
Glide.with(NoticeInfoActivity.this).load(file).apply(options).error(R.drawable.icon_nodata).into(mViewDataBinding.imageView);
} else {
Glide.with(NoticeInfoActivity.this).load(filePath).apply(options).error(R.drawable.icon_nodata).into(mViewDataBinding.imageView);
if (!TextUtils.isEmpty(filePath)) {
RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(this, 16F)));
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length());
String realPath = Utils.getDownLoadPath(NoticeInfoActivity.this) + fileName;
File file = new File(realPath);
if (file.exists()) {
Glide.with(NoticeInfoActivity.this).load(file).apply(options).error(R.drawable.icon_nodata).into(mViewDataBinding.imageView);
} else {
Glide.with(NoticeInfoActivity.this).load(filePath).apply(options).error(R.drawable.icon_nodata).into(mViewDataBinding.imageView);
}
}
}
private void showData(AlarmClockData alarmClockData) {
String filePath = alarmClockData.getFile();
if (!TextUtils.isEmpty(filePath)) {

View File

@@ -24,8 +24,8 @@ public class ScreenLockActivity extends BaseMvvmActivity<ScreenLockViewModel, Ac
private static final String TAG = "ScreenLockActivity";
private SoundPool soundPool;
private int soundId;
private SoundPool mSoundPool;
private int mSoundId;
@Override
@@ -34,12 +34,12 @@ public class ScreenLockActivity extends BaseMvvmActivity<ScreenLockViewModel, Ac
getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_GAME) // 设置音效使用场景
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build(); // 设置音效的类型
soundPool = new SoundPool.Builder().setAudioAttributes(attr) // 设置音效池的属性
mSoundPool = new SoundPool.Builder().setAudioAttributes(attr) // 设置音效池的属性
.setMaxStreams(1) // 设置最多可容纳10个音频流
.build(); // ①
// load方法加载指定音频文件并返回所加载的音效ID
// 此处使用HashMap来管理这些音频流
soundId = soundPool.load(this, R.raw.click, 1);
mSoundId = mSoundPool.load(this, R.raw.click, 1);
}
@Override
@@ -145,6 +145,15 @@ public class ScreenLockActivity extends BaseMvvmActivity<ScreenLockViewModel, Ac
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mSoundPool != null) {
mSoundPool.release();
mSoundPool = null;
}
}
private void add(VerificationCodeView codeView, String text) {
Log.e(TAG, "add: text = " + text);
String oldText = codeView.getEditText().getText().toString();

View File

@@ -701,10 +701,10 @@ public class AlarmUtils {
case ONCE:
if (!finished) {
if (timeStamp < System.currentTimeMillis()) {
Intent intent = new Intent(MainService.ALARMWAKEUP);
intent.putExtra("title", title);
intent.putExtra("id", id);
mContext.sendBroadcast(intent);
// Intent intent = new Intent(MainService.ALARMWAKEUP);
// intent.putExtra("title", title);
// intent.putExtra("id", id);
// mContext.sendBroadcast(intent);
} else {
setOnceAlarm(MainService.ALARMWAKEUP, title, id, timeStamp, local);
}

View File

@@ -454,7 +454,13 @@ public class CacheHelper {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
if (context.getExternalCacheDir() != null) {
cachePath = context.getExternalCacheDir().getPath();
} else if (context.getExternalFilesDir("cache") != null) {
cachePath = context.getExternalFilesDir("cache").getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
} else {
cachePath = context.getCacheDir().getPath();
}

View File

@@ -92,18 +92,19 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
});
Log.e(TAG, "initData: ");
mViewModel.getContact();
}
@Override
public void fetchData() {
Log.e(TAG, "fetchData: ");
mViewModel.getContact();
mViewModel.getContactNoSave();
}
@Override
public void onResume() {
super.onResume();
mViewModel.getContact();
mViewModel.getContactNoSave();
}
public static final String NAME = "name";

View File

@@ -1,18 +1,27 @@
package com.vscool.os.fragment.contact;
import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.tencent.mmkv.MMKV;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.FragmentEvent;
import com.vscool.os.base.mvvm.BaseViewModel;
import com.vscool.os.bean.BaseResponse;
import com.vscool.os.bean.Contact;
import com.vscool.os.config.CommonConfig;
import com.vscool.os.databinding.FragmentContactHomeBinding;
import com.vscool.os.gson.GsonUtils;
import com.vscool.os.network.NetInterfaceManager;
import com.vscool.os.network.UrlAddress;
import java.util.List;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
public class ContactViewModel extends BaseViewModel<FragmentContactHomeBinding, FragmentEvent> {
private static final String TAG = "ContactListViewModel";
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
@@ -55,4 +64,37 @@ public class ContactViewModel extends BaseViewModel<FragmentContactHomeBinding,
}
});
}
public void getContactNoSave() {
NetInterfaceManager.getInstance().getContactListObservable()
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
.subscribe(new Observer<BaseResponse<List<Contact>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.e("getContactNoSave", "onSubscribe: ");
}
@Override
public void onNext(@NonNull BaseResponse<List<Contact>> listBaseResponse) {
Log.e("getContactNoSave", "onNext: ");
if (listBaseResponse.code == 200) {
List<Contact> contactList = listBaseResponse.data;
mMMKV.putString(UrlAddress.GET_MAIL_LIST, GsonUtils.toJSONString(contactList));
mContactListData.setValue(contactList);
} else {
mMMKV.remove(UrlAddress.GET_MAIL_LIST);
}
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("getContactNoSave", "onError: ");
}
@Override
public void onComplete() {
Log.e("getContactNoSave", "onComplete: ");
}
});
}
}

View File

@@ -37,7 +37,7 @@ public class DialerFragment extends BaseMvvmFragment<DialerViewModel, FragmentDi
private Context mContext;
private SoundPool soundPool;
private SoundPool mSoundPool;
private HashMap<Integer, Integer> soundMap = new HashMap<>();
public DialerFragment() {
@@ -67,23 +67,23 @@ public class DialerFragment extends BaseMvvmFragment<DialerViewModel, FragmentDi
protected void initView(Bundle bundle) {
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_GAME) // 设置音效使用场景
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build(); // 设置音效的类型
soundPool = new SoundPool.Builder().setAudioAttributes(attr) // 设置音效池的属性
mSoundPool = new SoundPool.Builder().setAudioAttributes(attr) // 设置音效池的属性
.setMaxStreams(12) // 设置最多可容纳10个音频流
.build(); // ①
// load方法加载指定音频文件并返回所加载的音效ID
// 此处使用HashMap来管理这些音频流
soundMap.put(0, soundPool.load(mContext, R.raw.s_0, 1));
soundMap.put(1, soundPool.load(mContext, R.raw.s_1, 1));
soundMap.put(2, soundPool.load(mContext, R.raw.s_2, 1));
soundMap.put(3, soundPool.load(mContext, R.raw.s_3, 1));
soundMap.put(4, soundPool.load(mContext, R.raw.s_4, 1));
soundMap.put(5, soundPool.load(mContext, R.raw.s_5, 1));
soundMap.put(6, soundPool.load(mContext, R.raw.s_6, 1));
soundMap.put(7, soundPool.load(mContext, R.raw.s_7, 1));
soundMap.put(8, soundPool.load(mContext, R.raw.s_8, 1));
soundMap.put(9, soundPool.load(mContext, R.raw.s_9, 1));
soundMap.put(10, soundPool.load(mContext, R.raw.s_x, 1));
soundMap.put(11, soundPool.load(mContext, R.raw.s_j, 1));
soundMap.put(0, mSoundPool.load(mContext, R.raw.s_0, 1));
soundMap.put(1, mSoundPool.load(mContext, R.raw.s_1, 1));
soundMap.put(2, mSoundPool.load(mContext, R.raw.s_2, 1));
soundMap.put(3, mSoundPool.load(mContext, R.raw.s_3, 1));
soundMap.put(4, mSoundPool.load(mContext, R.raw.s_4, 1));
soundMap.put(5, mSoundPool.load(mContext, R.raw.s_5, 1));
soundMap.put(6, mSoundPool.load(mContext, R.raw.s_6, 1));
soundMap.put(7, mSoundPool.load(mContext, R.raw.s_7, 1));
soundMap.put(8, mSoundPool.load(mContext, R.raw.s_8, 1));
soundMap.put(9, mSoundPool.load(mContext, R.raw.s_9, 1));
soundMap.put(10, mSoundPool.load(mContext, R.raw.s_x, 1));
soundMap.put(11, mSoundPool.load(mContext, R.raw.s_j, 1));
mViewDataBinding.etPhone.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -149,6 +149,15 @@ public class DialerFragment extends BaseMvvmFragment<DialerViewModel, FragmentDi
}
@Override
public void onDestroy() {
super.onDestroy();
if (mSoundPool != null) {
mSoundPool.release();
mSoundPool = null;
}
}
private void callNumber() {
String phone = mViewDataBinding.etPhone.getText().toString();
if (TextUtils.isEmpty(phone)) {
@@ -181,7 +190,7 @@ public class DialerFragment extends BaseMvvmFragment<DialerViewModel, FragmentDi
}
boolean dialTone = mMMKV.decodeBool(CommonConfig.DISABLE_DIAL_TONE_MODIFY, true);
if (dialTone) {
soundPool.play(soundMap.get(position), 1, 1, 0, 0, 1);
mSoundPool.play(soundMap.get(position), 1, 1, 0, 0, 1);
}
}

View File

@@ -98,7 +98,11 @@ import com.vscool.os.utils.Utils;
import java.io.File;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -1071,13 +1075,50 @@ public class NetInterfaceManager {
if (list == null || list.size() == 0) {
if (callback != null) callback.setAlarmClock(null);
} else {
List<AlarmClockData> filter = list.stream().filter(alarmClockData -> !alarmClockData.isDeleted()).collect(Collectors.toList());
List<AlarmClockData> filter = list.stream().filter(alarmClockData -> !alarmClockData.isDeleted())
.sorted(new Comparator<AlarmClockData>() {
@Override
public int compare(AlarmClockData o1, AlarmClockData o2) {
long time1 = getClockTimestamp(o1);
long time2 = getClockTimestamp(o2);
return Long.compare(time1, time2);
}
})
.collect(Collectors.toList());
if (callback != null) callback.setAlarmClock(filter);
}
}
};
}
SimpleDateFormat mSimpleDateFormatYear = new SimpleDateFormat("yyyy-MM-dd HH:mm");
SimpleDateFormat mSimpleDateFormatHour = new SimpleDateFormat("HH:mm");
private long getClockTimestamp(AlarmClockData alarmClockData) {
long timestamp;
Date date = new Date();
if (alarmClockData.getType() == 1) {
try {
date = mSimpleDateFormatYear.parse(alarmClockData.getTime());
} catch (ParseException e) {
e.printStackTrace();
Log.e(TAG, "getClockTimestamp: " + e.getMessage());
}
} else {
try {
date = mSimpleDateFormatHour.parse(alarmClockData.getTime());
} catch (ParseException e) {
e.printStackTrace();
Log.e(TAG, "getClockTimestamp: " + e.getMessage());
}
}
timestamp = date.getTime();
return timestamp;
}
public interface SnInfoCallback {
void setSnInfo(SnInfo snInfo);
}

View File

@@ -17,17 +17,20 @@ import android.util.Log;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.Toast;
import com.hjq.toast.Toaster;
import com.tencent.mmkv.MMKV;
import com.vscool.os.bean.Contact;
import com.vscool.os.config.CommonConfig;
import com.vscool.os.utils.ForegroundAppUtil;
import java.util.List;
/**
* 通过微信标签最高支持8.0.498.0.50 获取不到数据
* 通过 {@link android.accessibilityservice.AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素
*/
public class WeAccessibilityService extends AccessibilityService {
private static final String TAG = "WeAccessibilityService";
@@ -132,7 +135,7 @@ public class WeAccessibilityService extends AccessibilityService {
* @param event
*/
private void _onAccessibilityEvent(AccessibilityEvent event) {
Log.e(TAG, "_onAccessibilityEvent: " + mCurrentStep);
switch (mCurrentStep) {
case WAITING:
break;
@@ -147,13 +150,18 @@ public class WeAccessibilityService extends AccessibilityService {
}
}
}
Log.e(TAG, "_onAccessibilityEvent: " + mCurrentStep);
switch (mCurrentStep) {
case WAITING:
if (!mAutoAccept) return;
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
Log.e(TAG, "_onAccessibilityEvent: mAutoAccept = " + mAutoAccept);
if (!mAutoAccept) {
return;
}
if (stepAnswer(Property.DESCRIPTION, RECEIVE_DESCRIPTION)) {
mCurrentStep = Step.WAITING;
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
} else {
// clickAnswer();
}
break;
case CLICK_HOME://主页能找到直接点击进去更多
@@ -167,8 +175,11 @@ public class WeAccessibilityService extends AccessibilityService {
break;
case CLICK_CONTACT://进入通讯录界面
touchContact();
// step(Property.TEXT, CONTACT_TEXT, Step.FIND_TAG);
if (stepHome(Property.TEXT, CONTACT_TEXT, Step.FIND_TAG)) {
Log.e(TAG, "_onAccessibilityEvent: enter contact");
} else {
touchContact();
}
break;
case FIND_CONTACT://模拟滑动找到联系人
findContact(Property.TEXT, mName, Step.CLICK_NAME);
@@ -230,6 +241,23 @@ public class WeAccessibilityService extends AccessibilityService {
}
}
@Deprecated
private void clickAnswer() {
String className = ForegroundAppUtil.getForegroundActivityName(WeAccessibilityService.this);
Log.e(TAG, "clickAnswer: " + className);
if (!TextUtils.isEmpty(className)) {
if ("com.tencent.mm.plugin.voip.ui.VideoActivity".contentEquals(className)) {
boolean successful = clickByPoint(595, 1376);
Log.e(TAG, "clickAnswer: " + successful);
if (successful) {
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
}
} else {
Log.e(TAG, "clickAnswer: Not in the answering interface");
}
}
}
private boolean step(Property type, String text, Step nextStep) {
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
if (node != null) {
@@ -249,6 +277,27 @@ public class WeAccessibilityService extends AccessibilityService {
}
}
// TODO: 2025/2/8 先把通讯录点击的换成node
private boolean stepHome(Property type, String text, Step nextStep) {
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
if (node != null) {
Rect rect = new Rect();
node.getBoundsInScreen(rect);
Log.e(TAG, "step: rect = " + rect);
if (rect.left < 0 || rect.top < 0 || rect.right < 0 || rect.bottom < 0) {
return false;
}
clickNode(node);
Log.e(TAG, "step: mCurrentStep: " + mCurrentStep + " done");
mCurrentStep = nextStep;
Log.e(TAG, "step: next: " + mCurrentStep);
return true;
} else {
return false;
}
}
@Deprecated
private void touchContact() {
boolean successful = clickByPoint(268, 1440);
if (successful) {
@@ -392,6 +441,18 @@ public class WeAccessibilityService extends AccessibilityService {
return null;
}
private AccessibilityNodeInfo findNode(List<AccessibilityWindowInfo> windows, Property type, String text) {
for (AccessibilityWindowInfo accessibilityWindowInfo : windows) {
AccessibilityNodeInfo nodeInfo = findNode(accessibilityWindowInfo.getRoot(), type, text);
if (nodeInfo != null) {
return nodeInfo;
}
}
Log.e(TAG, "findNode windows: not found");
return null;
}
private void clickNode(AccessibilityNodeInfo node) {
try {
Log.e(TAG, "clickNode: getText = " + node.getText());
@@ -446,7 +507,7 @@ public class WeAccessibilityService extends AccessibilityService {
}
private boolean stepAnswer(Property type, String text) {
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
if (node != null) {
Point point = getPointtByNode(node);
Log.e(TAG, "stepAnswer: " + point);

View File

@@ -79,6 +79,9 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
public MainSPresenter mPresenter;
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
private SoundPool mSoundPool;
private HashMap<Integer, Integer> soundMap = new HashMap<>();
@@ -161,8 +164,9 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
// ApkUtils.UninstallAPP(this, "com.joytv.live");
// ApkUtils.UninstallAPP(this, "com.tencent.android.qqdownloader");
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "WakeAndLock");
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM) // 设置音效使用场景
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build(); // 设置音效的类型
@@ -245,6 +249,7 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
@Override
public void onNext(@NonNull Integer hour) {
Log.e("mTimeSignalCallback", "onNext: ");
mWakeLock.acquire(60 * 1000L);
mSoundPool.play(soundMap.get(hour), 1, 1, 0, 0, 1);
}
@@ -317,6 +322,11 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
if (mSmsReceiver != null) {
unregisterReceiver(mSmsReceiver);
}
if (mSoundPool != null) {
mSoundPool.release();
mSoundPool = null;
}
}
public boolean isScreenOn() {

View File

@@ -14,11 +14,7 @@ import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.vscool.os.R;
import com.vscool.os.bean.Contact;
import com.vscool.os.bean.ContactId;
@@ -31,7 +27,6 @@ import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
@@ -47,21 +42,27 @@ public class ContactsUtils {
Observable.create(new ObservableOnSubscribe<Long>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Long> emitter) throws Throwable {
long time = System.currentTimeMillis();
Log.e(TAG, "saveContactPhone: " + contact.getMobile() + " isExist = " + ContactsUtils.isExist(context, contact.getMobile()));
Glide.with(context).asBitmap().load(contact.getAvatar()).override(200, 200).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@androidx.annotation.NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, resource);
} else {
insertContactPhone(context, contact, resource);
}
if (TextUtils.isEmpty(contact.getAvatar())) {
Bitmap bitmap = Glide.with(context).asBitmap().load(R.drawable.default_avatar).override(200, 200).submit().get();
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, bitmap);
} else {
insertContactPhone(context, contact, bitmap);
}
});
emitter.onNext(1L);
} else {
Bitmap bitmap = Glide.with(context).asBitmap().load(contact.getAvatar()).override(200, 200).error(R.drawable.default_avatar).submit().get();
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, bitmap);
} else {
insertContactPhone(context, contact, bitmap);
}
}
emitter.onNext(System.currentTimeMillis() - time);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.newThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
@@ -91,27 +92,33 @@ public class ContactsUtils {
Observable.create(new ObservableOnSubscribe<Long>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Long> emitter) throws Throwable {
long time = System.currentTimeMillis();
for (Contact contact : contactList) {
if (TextUtils.isEmpty(contact.getMobile())) {
continue;
}
Log.e(TAG, "saveContactPhone: " + contact.getMobile() + " isExist = " + ContactsUtils.isExist(context, contact.getMobile()));
Glide.with(context).asBitmap().load(contact.getAvatar()).error(R.drawable.default_avatar).override(200, 200).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@androidx.annotation.NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, resource);
emitter.onNext(0L);
} else {
insertContactPhone(context, contact, resource);
emitter.onNext(1L);
}
if (TextUtils.isEmpty(contact.getAvatar())) {
Bitmap bitmap = Glide.with(context).asBitmap().load(R.drawable.default_avatar).override(200, 200).submit().get();
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, bitmap);
} else {
insertContactPhone(context, contact, bitmap);
}
});
} else {
Bitmap bitmap = Glide.with(context).asBitmap().load(contact.getAvatar()).override(200, 200).error(R.drawable.default_avatar).submit().get();
if (ContactsUtils.isExist(context, contact.getMobile())) {
updateContactPhone(context, contact, bitmap);
} else {
insertContactPhone(context, contact, bitmap);
}
}
}
emitter.onNext(System.currentTimeMillis() - time);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.newThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
@@ -162,6 +169,24 @@ public class ContactsUtils {
resolver.insert(ContactsContract.Data.CONTENT_URI, values);
}
public static void insertContactPhone(Context context, Contact contact) {
ContentValues values = new ContentValues();
long rawContactId = ContentUris.parseId(context.getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values));
Log.e(TAG, "insertContactPhone: rawContactId = " + rawContactId);
ContentResolver resolver = context.getContentResolver();
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.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.getMobile());
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
resolver.insert(ContactsContract.Data.CONTENT_URI, values);
}
public static void updateContactPhone(Context context, Contact contact, Bitmap bitmap) {
long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
@@ -173,6 +198,7 @@ public class ContactsUtils {
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.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
@@ -181,6 +207,7 @@ public class ContactsUtils {
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);
@@ -204,6 +231,18 @@ public class ContactsUtils {
// int result = resolver.update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(bean.getId())});
}
public static void updateContactPhone(Context context, Contact contact) {
long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
Log.e(TAG, "updateContactPhone: rawContactId = " + rawContactId);
ContentResolver resolver = context.getContentResolver();
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);
}
public static void update(Context context, Contact contact, Bitmap bitmap) {
long rawContactId = ContactsUtils.getRawContactId(context, contact.getMobile());
@@ -272,7 +311,7 @@ public class ContactsUtils {
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.newThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

View File

@@ -31,16 +31,8 @@ public class ForegroundAppUtil {
* 获取栈顶的应用包名
*/
public static String getForegroundActivityName(Context context) {
String currentClassName = "";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
currentClassName = manager.getRunningTasks(1).get(0).topActivity.getPackageName();
} else {
UsageStats initStat = getForegroundUsageStats(context, START_TIME, END_TIME);
if (initStat != null) {
currentClassName = initStat.getPackageName();
}
}
ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
String currentClassName = manager.getRunningTasks(1).get(0).topActivity.getClassName();
return currentClassName;
}

View File

@@ -1,21 +0,0 @@
package com.vscool.os.utils;
import android.content.Context;
public class ScreenUtil {
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}

View File

@@ -1,7 +1,7 @@
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackSpoken"
android:accessibilityFlags="flagIncludeNotImportantViews"
android:accessibilityEventTypes="typeAllMask|typeViewClicked|typeViewFocused|typeWindowStateChanged|typeWindowsChanged|typeContextClicked|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackAllMask|feedbackGeneric|feedbackSpoken"
android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"