version:1.7.1

fix:
update:优化拨号显示
This commit is contained in:
2025-08-30 14:30:03 +08:00
parent d778ac35f5
commit 8c7c3bef54
29 changed files with 844 additions and 190 deletions

View File

@@ -17,8 +17,8 @@ android {
applicationId "com.xxpatx.os"
minSdkVersion 24
targetSdkVersion 29
versionCode 1069
versionName "1.6.9"
versionCode 1071
versionName "1.7.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -199,6 +199,8 @@ dependencies {
// implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
//
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
//log打印
implementation 'com.squareup.okhttp3:logging-interceptor:4.7.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'

View File

@@ -19,14 +19,15 @@ 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.xxpatx.os.bean.Contact;
import com.xxpatx.os.config.CommonConfig;
import com.xxpatx.os.utils.ForegroundAppUtil;
import com.xxpatx.os.utils.ToastUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
@@ -70,7 +71,7 @@ public class SelectToSpeakService extends AccessibilityService {
public static final int TYPE_VOICE = 0;
public static final int TYPE_VIDEO = 1;
private static final int WAIT_TIME = 1300;
private static final int WAIT_TIME = 1600;
private int mCallType = TYPE_VOICE;
@@ -79,6 +80,7 @@ public class SelectToSpeakService extends AccessibilityService {
private String mName = "";//微信昵称
private String mTagName = "";//微信联系人标签名
private boolean mAutoAccept = false;
private boolean mAutoHandsFree = false;
public interface AccessibilityEventCallback {
void onAccessibilityEventCallback(AccessibilityEvent accessibilityEvent);
@@ -92,6 +94,7 @@ public class SelectToSpeakService extends AccessibilityService {
Log.e(TAG, "onCreate: ");
registerSettingReceiver();
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
mAutoHandsFree = mMMKV.decodeBool(CommonConfig.WECHAT_AUTO_HNADS_FREE, false);
analysisAccessibilityEvent();
}
@@ -198,20 +201,18 @@ public class SelectToSpeakService extends AccessibilityService {
case WAITING:
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.WECHAT_HANDS_FREE;
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
} else {
mCurrentStep = Step.WAITING;
// clickAnswer();
if (mAutoAccept) {
autoAccept();
}
break;
case WECHAT_HANDS_FREE:
handsFree(Property.DESCRIPTION, HANDS_FREE_TEXT);
break;
mAutoHandsFree = mMMKV.decodeInt(CommonConfig.WECHAT_AUTO_HNADS_FREE, 0) == 1;
Log.e(TAG, "_onAccessibilityEvent: mAutoHandsFree = " + mAutoHandsFree);
if (mAutoHandsFree) {
handsFree(Property.DESCRIPTION, HANDS_FREE_TEXT);
} else {
Log.e(TAG, "_onAccessibilityEvent: not enable auto handsfree");
}
case DIALER_HANDS_FREE:
if (findHandsFree(Property.DESCRIPTION, DIALER_HANDS_FREE_CLOSE_TEXT)) {
dialerHandsFree(Property.TEXT, DIALER_HANDS_FREE_TEXT);
@@ -245,6 +246,13 @@ public class SelectToSpeakService extends AccessibilityService {
stepCall(Property.TEXT, PARENT_VIDEO_TEXT);
// clickVideoCall();
break;
case CLICK_CALL://打视频或者电话
if (mCallType == TYPE_VIDEO) {
step(Property.TEXT, VIDEO_TEXT, Step.WAITING);
} else if (mCallType == TYPE_VOICE) {
step(Property.TEXT, CALL_TEXT, Step.WAITING);
}
break;
case CLICK_CONTACT://进入通讯录界面
if (stepHome(Property.TEXT, CONTACT_TEXT, Step.FIND_TAG)) {
@@ -271,17 +279,11 @@ public class SelectToSpeakService extends AccessibilityService {
case CLICK_INFO://进入个人信息页面
stepCallDialog(Property.TEXT, DIALER_TEXT, Step.CLICK_CALL);
break;
case CLICK_CALL://打视频或者电话
if (mCallType == TYPE_VIDEO) {
step(Property.TEXT, VIDEO_TEXT, Step.WAITING);
} else if (mCallType == TYPE_VOICE) {
step(Property.TEXT, CALL_TEXT, Step.WAITING);
}
break;
// case CLICK_VIDEO_CALL:
// if (step(Property.TEXT, VIDEO_TEXT)) {
// Log.d(TAG, "finish, now: " + mCurrentStep);
// Toast.makeText(this, "成功发起视频聊天", Toast.LENGTH_LONG).show();
// ToastUtils.show("成功发起视频聊天");
// }
// break;
default:
@@ -316,6 +318,95 @@ public class SelectToSpeakService extends AccessibilityService {
}
}
private void autoAccept() {
if (stepAnswer(Property.DESCRIPTION, RECEIVE_DESCRIPTION)) {
mCurrentStep = Step.WECHAT_HANDS_FREE;
ToastUtils.show("已自动接听视频/语音");
} else if (clickNode("com.tencent.mm:id/kfp", false)) {
mCurrentStep = Step.WECHAT_HANDS_FREE;
ToastUtils.show("已自动接听视频/语音");
} else {
mCurrentStep = Step.WAITING;
// clickAnswer();
}
}
/**
* @param text 对应文本
* @param simulate 是否通过坐标模拟点击
* @return
*/
private boolean clickNode(String text, boolean simulate) {
findFloatWindowNode(text);
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId(text);
Optional<AccessibilityNodeInfo> optional = nodeInfos.stream().findAny();
if (optional.isPresent()) {
AccessibilityNodeInfo node = optional.get();
if (node.isClickable()) {
boolean performAction = node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
Log.e(TAG, "clickNode: performAction = " + performAction);
node.recycle();
return performAction;
} else {
if (simulate) {
Point point = getPointtByNode(node);
Log.e(TAG, "clickNode: " + point);
clickByPoint(point.x, point.y);
Log.e(TAG, "clickNode: mCurrentStep " + mCurrentStep + " done");
} else {
clickNode(findClickableNode(node));
}
}
return true;
} else {
Log.e(TAG, "clickNode: not found");
return false;
}
}
private AccessibilityNodeInfo findClickableNode(AccessibilityNodeInfo node) {
if (node == null) {
Log.e(TAG, "findClickableNode: node is null");
return null;
}
if (node.isClickable()) {
return node;
} else {
return findClickableNode(node);
}
}
public void findFloatWindowNode(String id) {
List<AccessibilityWindowInfo> windows = getWindows();
for (AccessibilityWindowInfo window : windows) {
// 筛选悬浮窗窗口
if (isFloatingWindow(window)) {
AccessibilityNodeInfo rootNode = window.getRoot();
// 处理悬浮窗节点
traverseNode(rootNode);
rootNode.recycle(); // 释放资源
}
}
}
private boolean isFloatingWindow(AccessibilityWindowInfo window) {
Log.e(TAG, "isFloatingWindow: " + window.getType());
// 根据窗口类型或标题筛选
return window.getType() == AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
}
private void traverseNode(AccessibilityNodeInfo node) {
if (node == null) return;
// 提取节点信息如文本、ID等
String text = node.getText() != null ? node.getText().toString() : "";
String id = node.getViewIdResourceName();
// 递归遍历子节点
for (int i = 0; i < node.getChildCount(); i++) {
traverseNode(node.getChild(i));
}
}
@Deprecated
private void clickAnswer() {
String className = ForegroundAppUtil.getForegroundActivityName(SelectToSpeakService.this);
@@ -325,7 +416,7 @@ public class SelectToSpeakService extends AccessibilityService {
boolean successful = clickByPoint(595, 1376);
Log.e(TAG, "clickAnswer: " + successful);
if (successful) {
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
ToastUtils.show("已自动接听视频/语音");
}
} else {
Log.e(TAG, "clickAnswer: Not in the answering interface");
@@ -433,13 +524,19 @@ public class SelectToSpeakService extends AccessibilityService {
clickNode(nodeInfo);
mCurrentStep = nextStep;
} else {
Toaster.show("没有找到搜索按钮");
// Toaster.show("没有找到搜索按钮");
step(Property.DESCRIPTION, SEARCH_TEXT, Step.CLICK_SEARCH);
}
}
private List<AccessibilityNodeInfo> findNodesByViewId(String id) {
List<AccessibilityNodeInfo> accessibilityNodeInfos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id);
return accessibilityNodeInfos;
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
List<AccessibilityNodeInfo> accessibilityNodeInfos = nodeInfo.findAccessibilityNodeInfosByViewId(id);
return accessibilityNodeInfos;
} else {
return new ArrayList<>();
}
}
private AccessibilityNodeInfo findNodeByText(AccessibilityNodeInfo root, String text) {
@@ -478,7 +575,7 @@ public class SelectToSpeakService extends AccessibilityService {
} else {
if (mFindCount == mMaxCount) {
Log.e("stepCallDialog", "mCurrentStep: max");
Toast.makeText(this, "没有找到联系人", Toast.LENGTH_LONG).show();
ToastUtils.show("没有找到联系人");
mCurrentStep = Step.WAITING;
mFindCount = 0;
return false;
@@ -522,7 +619,7 @@ public class SelectToSpeakService extends AccessibilityService {
} else {
if (mFindCount == mMaxCount) {
Log.e("findContact", "mCurrentStep: max");
Toast.makeText(this, "没有找到联系人", Toast.LENGTH_LONG).show();
ToastUtils.show("没有找到联系人");
mCurrentStep = Step.WAITING;
mFindCount = 0;
return false;
@@ -583,6 +680,10 @@ public class SelectToSpeakService extends AccessibilityService {
private void clickNode(AccessibilityNodeInfo node) {
if (node == null) {
Log.e(TAG, "clickNode: node is null");
return;
}
try {
Log.e(TAG, "clickNode: getText = " + node.getText());
Log.e(TAG, "clickNode: isClickable = " + node.isClickable());
@@ -811,29 +912,30 @@ public class SelectToSpeakService extends AccessibilityService {
WECHAT_HANDS_FREE,
//电话免提
DIALER_HANDS_FREE,
//微信主页找用户名
//1-1微信主页找用户名
CLICK_HOME,
//进入搜索界面
//2-2进入搜索界面
CLICK_SEARCH,
//是否弹出了联系人列表
//2-3是否弹出了联系人列表
CLICK_SEARCH_CONTACT,
//聊天界面+号
//1-2 2-4聊天界面+号
CLICK_QUICK_WECHAT_CALL,
//更多里面视频通话
//1-3 2-5更多里面视频通话
CLICK_TARGET,
/*1-4 语音通话*/
CLICK_CALL,
//主页点击导航栏通讯录
CLICK_CONTACT,
FIND_CONTACT,
//通讯录页面点击标签
FIND_TAG,
//点击对应的标签名
CLICK_TAG,
CLICK_NAME,
CLICK_INFO,
CLICK_CALL,
CLICK_VIDEO_CALL;
private Step next() {

View File

@@ -205,15 +205,11 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
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);
body = NetInterfaceManager.convertFileToMultipartBody("file", picFile, "image/png");
} 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);
body = NetInterfaceManager.convertFileToMultipartBody("file", picFile, "image/png");
}
mAlarmClockData.setId(mAlarmClockData.getId());

View File

@@ -9,6 +9,7 @@ import com.google.android.accessibility.selecttospeak.SelectToSpeakService;
import com.xxpatx.os.R;
import com.xxpatx.os.base.mvvm.BaseMvvmActivity;
import com.xxpatx.os.bean.Contact;
import com.xxpatx.os.bean.ContactConfig;
import com.xxpatx.os.databinding.ActivityWechatCallBinding;
import com.xxpatx.os.utils.AccessibilityUtils;
@@ -63,6 +64,12 @@ public class CallWechatActivity extends BaseMvvmActivity<CallWechatViewModel, Ac
mContact = contact;
mViewDataBinding.setContact(contact);
// mViewDataBinding.setTag(!TextUtils.isEmpty(contact.getTag()));
ContactConfig contactConfig = mContact.getConfig();
mViewDataBinding.clDial.setVisibility(contactConfig.getCall_phone() == 1 ? View.VISIBLE : View.GONE);
// mViewDataBinding.clSms.setVisibility(contactConfig.getSms() == 1 ? View.VISIBLE : View.GONE);
mViewDataBinding.clVideo.setVisibility(contactConfig.getWx_video() == 1 ? View.VISIBLE : View.GONE);
mViewDataBinding.clAudio.setVisibility(contactConfig.getWx_voice() == 1 ? View.VISIBLE : View.GONE);
}
}
}

View File

@@ -6,6 +6,7 @@ import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.google.gson.JsonObject;
import com.hjq.toast.Toaster;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
@@ -13,6 +14,7 @@ import com.xxpatx.os.R;
import com.xxpatx.os.base.mvvm.BaseViewModel;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.bean.Contact;
import com.xxpatx.os.bean.ContactConfig;
import com.xxpatx.os.databinding.ActivityContactAddBinding;
import com.xxpatx.os.network.NetInterfaceManager;
import com.xxpatx.os.utils.ContactsUtils;
@@ -54,6 +56,13 @@ public class AddContactViewModel extends BaseViewModel<ActivityContactAddBinding
String name = binding.etName.getText().toString();
String phone = binding.etPhone.getText().toString();
String tag = binding.etTag.getText().toString();
ContactConfig contactConfig = new ContactConfig();
contactConfig.setCall_phone(binding.cbDialer.isChecked() ? 1 : 0);
contactConfig.setSms(binding.cbSms.isChecked() ? 1 : 0);
contactConfig.setWx_video(binding.cbVideo.isChecked() ? 1 : 0);
contactConfig.setWx_voice(binding.cbAudio.isChecked() ? 1 : 0);
File avatarFile;
Log.e("checkContact", "avatarFilePath: " + avatarFilePath);
if (TextUtils.isEmpty(avatarFilePath)) {
@@ -66,16 +75,16 @@ public class AddContactViewModel extends BaseViewModel<ActivityContactAddBinding
Toaster.showShort("图片加载失败");
return;
}
MediaType mediaType = MediaType.Companion.parse("image/png");
RequestBody requestBody = RequestBody.Companion.create(avatarFile, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", avatarFile.getName(), requestBody);
Map<String, String> params = new HashMap<>();
params.put("sn", Utils.getSerial());
params.put("name", name);
params.put("mobile", phone);
params.put("tag", tag);
params.put("is_urgent", String.valueOf(binding.toggleButton.isToggleOn()));
params.put("show_desktop", String.valueOf(binding.tbShow.isToggleOn()));
MultipartBody.Part avatarBody = NetInterfaceManager.convertFileToMultipartBody("avatar", avatarFile, "image/png");
Map<String, RequestBody> params = new HashMap<>();
params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial()));
params.put("name", NetInterfaceManager.convertToRequestBody(name));
params.put("mobile", NetInterfaceManager.convertToRequestBody(phone));
params.put("tag", NetInterfaceManager.convertToRequestBody(tag));
params.put("is_urgent", NetInterfaceManager.convertToRequestBody(binding.toggleButton.isToggleOn()));
params.put("show_desktop", NetInterfaceManager.convertToRequestBody(binding.tbShow.isToggleOn()));
params.put("config", NetInterfaceManager.convertObjectToJsonRequestBody(contactConfig));
Contact contact = new Contact();
ThreadLocalRandom random = ThreadLocalRandom.current();
@@ -90,7 +99,7 @@ public class AddContactViewModel extends BaseViewModel<ActivityContactAddBinding
ContactsUtils.saveContactPhone(getCtx(), contact);
NetInterfaceManager.getInstance()
.getMailListAddObservable(params, body)
.getMailListAddObservable(params, avatarBody)
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
.subscribe(new Observer<BaseResponse>() {
@Override

View File

@@ -16,6 +16,7 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.gson.JsonObject;
import com.hjq.toast.Toaster;
import com.luck.picture.lib.basic.PictureSelector;
import com.luck.picture.lib.config.SelectMimeType;
@@ -26,8 +27,10 @@ import com.xxpatx.os.R;
import com.xxpatx.os.base.mvvm.BaseMvvmActivity;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.bean.Contact;
import com.xxpatx.os.bean.ContactConfig;
import com.xxpatx.os.custom.GlideEngine;
import com.xxpatx.os.databinding.ActivityContactEditBinding;
import com.xxpatx.os.network.NetInterfaceManager;
import com.xxpatx.os.utils.ContactsUtils;
import com.xxpatx.os.utils.FileUtil;
import com.xxpatx.os.utils.ScreenUtils;
@@ -114,6 +117,9 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
if (mContact == null) {
return;
}
ContactConfig contactConfig = mContact.getConfig();
mViewDataBinding.setContactConfig(contactConfig);
if (mContact.getIs_urgent() == 1) {
mViewDataBinding.toggleButton.setToggleOn(false);
} else {
@@ -172,10 +178,16 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
return;
}
String groupTag = mViewDataBinding.etGroup.getText().toString();
if (TextUtils.isEmpty(groupTag)) {
Toaster.show("请输入微信群组标签");
return;
}
// if (TextUtils.isEmpty(groupTag)) {
// Toaster.show("请输入微信群组标签");
// return;
// }
ContactConfig contactConfig = new ContactConfig();
contactConfig.setCall_phone(mViewDataBinding.cbDialer.isChecked() ? 1 : 0);
contactConfig.setSms(mViewDataBinding.cbSms.isChecked() ? 1 : 0);
contactConfig.setWx_video(mViewDataBinding.cbVideo.isChecked() ? 1 : 0);
contactConfig.setWx_voice(mViewDataBinding.cbAudio.isChecked() ? 1 : 0);
File avatarFile;
Log.e("checkContact", "mPictrueFilePath: " + mPictrueFilePath);
if (TextUtils.isEmpty(mPictrueFilePath)) {
@@ -184,17 +196,19 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
Uri uri = Uri.parse(mPictrueFilePath);
avatarFile = FileUtil.uriToFile(uri, EditContactActivity.this);
}
MediaType mediaType = MediaType.Companion.parse("image/png");
RequestBody requestBody = RequestBody.Companion.create(avatarFile, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", avatarFile.getName(), requestBody);
Map<String, String> params = new HashMap<>();
params.put("sn", Utils.getSerial());
params.put("id", String.valueOf(mContact.getId()));
params.put("name", name);
params.put("mobile", phone);
params.put("tag", groupTag);
params.put("is_urgent", String.valueOf(mViewDataBinding.toggleButton.isToggleOn()));
params.put("show_desktop", String.valueOf(mViewDataBinding.tbShow.isToggleOn()));
MultipartBody.Part avatarBody = NetInterfaceManager.convertFileToMultipartBody("avatar", avatarFile, "image/png");
Map<String, RequestBody> params = new HashMap<>();
params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial()));
params.put("id", NetInterfaceManager.convertToRequestBody(mContact.getId()));
params.put("name", NetInterfaceManager.convertToRequestBody(name));
params.put("mobile", NetInterfaceManager.convertToRequestBody(phone));
params.put("tag", NetInterfaceManager.convertToRequestBody(groupTag));
params.put("is_urgent", NetInterfaceManager.convertToRequestBody(mViewDataBinding.toggleButton.isToggleOn()));
params.put("show_desktop", NetInterfaceManager.convertToRequestBody(mViewDataBinding.tbShow.isToggleOn()));
params.put("config", NetInterfaceManager.convertObjectToJsonRequestBody(contactConfig));
Contact contact = new Contact();
ThreadLocalRandom random = ThreadLocalRandom.current();
int fakeId = random.nextInt(Integer.MAX_VALUE);
@@ -206,7 +220,8 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
contact.setIs_urgent(mViewDataBinding.toggleButton.isToggleOn());
contact.setAvatar(mPictrueFilePath);
ContactsUtils.saveContactPhone(EditContactActivity.this, contact);
mViewModel.editContact(params, body);
mViewModel.editContact(params, avatarBody);
mLoadingDialog.show();
}

View File

@@ -4,6 +4,7 @@ import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.google.gson.JsonObject;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.xxpatx.os.base.mvvm.BaseViewModel;
@@ -16,7 +17,9 @@ import java.util.Map;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class EditContactViewModel extends BaseViewModel<ActivityContactEditBinding, ActivityEvent> {
@@ -32,7 +35,7 @@ public class EditContactViewModel extends BaseViewModel<ActivityContactEditBindi
public MutableLiveData<BaseResponse> mBaseResponseMutableLiveData = new MutableLiveData<>();
public void editContact(Map<String, String> params, MultipartBody.Part body) {
public void editContact(Map<String, RequestBody> params, MultipartBody.Part body) {
NetInterfaceManager.getInstance()
.getMailListEditObservable(params, body)
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))

View File

@@ -148,6 +148,10 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
Log.e(TAG, "onConnected: " + networkType);
mViewModel.uploadContacts();
mViewModel.getTestApp();
int is_activation = Settings.Global.getInt(getContentResolver(), CommonConfig.UIUI_ACTIVATION_KEY, 0);
if (is_activation == 0) {
mViewModel.getSnIsActivation();
}
}
@Override
@@ -173,6 +177,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
@@ -186,6 +191,16 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
Log.e(TAG, "initView: ");
NetworkUtils.registerNetworkStatusChangedListener(this);
int is_activation = Settings.Global.getInt(getContentResolver(), CommonConfig.UIUI_ACTIVATION_KEY, 0);
if (is_activation == 0) {
mViewModel.getSnIsActivation();
}
try {
startService(new Intent("wakeup").setComponent(new ComponentName("com.xxpatx.sn", "com.xxpatx.sn.service.main.MainService")));
} catch (Exception e) {
Log.e(TAG, "initView: startService " + e.getMessage());
}
Log.e(TAG, "getContacts: " + ContactsUtils.isExist(MainActivity.this, "13220282310"));
Log.e(TAG, "getContacts: " + ContactsUtils.getRawContactId(MainActivity.this, "13220282310"));
@@ -636,7 +651,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
// }
// });
//
// mViewModel.getSnIsActivation();
mViewModel.mAppInfoMutableLiveData.observe(this, new Observer<AppInfo>() {
@Override

View File

@@ -24,6 +24,8 @@ import com.tencent.mmkv.MMKV;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.xxpatx.os.R;
import com.xxpatx.os.activity.setting.SettingActivity;
import com.xxpatx.os.activity.update.UpdateActivity;
import com.xxpatx.os.base.mvvm.BaseViewModel;
import com.xxpatx.os.bean.ActivationBean;
import com.xxpatx.os.bean.AppInfo;
@@ -374,7 +376,15 @@ public class MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEv
}
}
} else {
ApkUtils.ariaDownload(getCtx(), appInfo.getApp_url(), appInfo);
int is_forcedown = appInfo.getIs_forcedown();
if (is_forcedown == 1) {
ApkUtils.ariaDownload(getCtx(), appInfo.getApp_url(), appInfo);
} else {
Log.e("checkUpdate", "onNext: 不静默升级");
Intent intent = new Intent(getCtx(), UpdateActivity.class);
intent.putExtra("appUpdateInfo", appInfo);
getCtx().startActivity(intent);
}
}
} else {
Log.e("checkUpdate", "onNext: 已是最新");
@@ -447,17 +457,20 @@ public class MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEv
Uri uri = Uri.parse(contact.getAvatar());
avatarFile = FileUtil.uriToFile(uri, getCtx());
}
MediaType mediaType = MediaType.Companion.parse("image/png");
RequestBody requestBody = RequestBody.Companion.create(avatarFile, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", avatarFile.getName(), requestBody);
Map<String, String> params = new HashMap<>();
params.put("sn", Utils.getSerial());
params.put("name", contact.getName());
params.put("mobile", contact.getMobile());
params.put("tag", contact.getTag());
params.put("is_urgent", String.valueOf(contact.getIs_urgent()));
MultipartBody.Part avatarBody = NetInterfaceManager.convertFileToMultipartBody("avatar", avatarFile, "image/png");
Map<String, RequestBody> params = new HashMap<>();
params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial()));
params.put("name", NetInterfaceManager.convertToRequestBody(contact.getName()));
params.put("mobile", NetInterfaceManager.convertToRequestBody(contact.getMobile()));
params.put("tag", NetInterfaceManager.convertToRequestBody(contact.getTag()));
params.put("is_urgent", NetInterfaceManager.convertToRequestBody(contact.getIs_urgent()));
params.put("show_desktop", NetInterfaceManager.convertToRequestBody(contact.getShow_desktop()));
params.put("config", NetInterfaceManager.convertObjectToJsonRequestBody(contact.getConfig().toJsonObject()));
NetInterfaceManager.getInstance()
.getMailListAddObservable(params, body)
.getMailListAddObservable(params, avatarBody)
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
.subscribe(new Observer<BaseResponse>() {
@Override

View File

@@ -120,6 +120,11 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
Log.e(TAG, "initView: voiceBroadcast = " + voiceBroadcast);
mViewDataBinding.setVoiceBroadcast(voiceBroadcast);
boolean autoCall = mMMKV.decodeBool(CommonConfig.WECHAT_AUTO_CALL_KEY, false);
Log.e(TAG, "initView: autoCall = " + autoCall);
mViewDataBinding.setAutoCall(autoCall);
boolean autoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
Log.e(TAG, "initView: autoAccept = " + autoAccept);
mViewDataBinding.setAutoAccept(autoAccept);
@@ -140,6 +145,7 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
boolean voiceSpeaker = mMMKV.decodeInt(CommonConfig.VOICE_SPEAKER_KEY, 0) == 1;
Log.e(TAG, "appSpeak: voiceSpeaker = " + voiceSpeaker);
mViewDataBinding.setVoiceSpeaker(voiceSpeaker);
}
private static final int REQUEST_CODE_DRAW_OVER_OTHER_APPS_PERMISSION = 200;

View File

@@ -1,6 +1,8 @@
package com.xxpatx.os.base;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
@@ -42,9 +44,21 @@ import java.lang.reflect.Method;
public class BaseApplication extends Application {
private static final String TAG = "BaseApplication";
/**
* ViewModel中因为经常旋转导致弱引用为空
*/
@SuppressLint("StaticFieldLeak")
private static Context context;
public static Context getContext() {
return context;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
context = getApplicationContext();
if (!BuildConfig.DEBUG) {
catchException();
}

View File

@@ -34,6 +34,8 @@ public class AppInfo implements Serializable {
private int is_silent;
private String app_md5;
private String createtime;
int is_forcedown;
public int getApp_id() {
return app_id;
@@ -227,6 +229,14 @@ public class AppInfo implements Serializable {
this.app_md5 = app_md5;
}
public int getIs_forcedown() {
return is_forcedown;
}
public void setIs_forcedown(int is_forcedown) {
this.is_forcedown = is_forcedown;
}
@NonNull
@Override
public String toString() {

View File

@@ -19,6 +19,7 @@ public class Contact implements Serializable {
String avatar;//头像
String tag;//标签
int show_desktop;//是否在主页显示
ContactConfig config;//拨号配置
boolean simContact;
public Contact() {
@@ -91,6 +92,14 @@ public class Contact implements Serializable {
this.show_desktop = show_desktop;
}
public ContactConfig getConfig() {
return config;
}
public void setConfig(ContactConfig config) {
this.config = config;
}
public boolean isSimContact() {
return simContact;
}

View File

@@ -0,0 +1,65 @@
package com.xxpatx.os.bean;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.Serializable;
public class ContactConfig implements Serializable {
private static final long serialVersionUID = 8906803710668700228L;
int call_phone;
int sms;
int wx_video;
int wx_voice;
public int getCall_phone() {
return call_phone;
}
public void setCall_phone(int call_phone) {
this.call_phone = call_phone;
}
public int getSms() {
return sms;
}
public void setSms(int sms) {
this.sms = sms;
}
public int getWx_video() {
return wx_video;
}
public void setWx_video(int wx_video) {
this.wx_video = wx_video;
}
public int getWx_voice() {
return wx_voice;
}
public void setWx_voice(int wx_voice) {
this.wx_voice = wx_voice;
}
public JsonObject toJsonObject(){
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("call_phone", call_phone);
jsonObject.addProperty("sms", sms);
jsonObject.addProperty("wx_voice", wx_video);
jsonObject.addProperty("wx_video", wx_voice);
return jsonObject;
}
@NonNull
@Override
public String toString() {
return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString();
}
}

View File

@@ -88,7 +88,7 @@ public class ContactViewModel extends BaseViewModel<FragmentContactHomeBinding,
@Override
public void onError(@NonNull Throwable e) {
Log.e("getContactNoSave", "onError: ");
Log.e("getContactNoSave", "onError: " + e.getMessage());
}
@Override

View File

@@ -7,6 +7,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.tencent.mmkv.MMKV;
import com.trello.rxlifecycle4.RxLifecycle;
@@ -76,10 +77,7 @@ import com.xxpatx.os.network.api.uiui.alarmclock.AlarmClockGetApi;
import com.xxpatx.os.network.api.uiui.alarmclock.AlarmClockQueryApi;
import com.xxpatx.os.network.api.uiui.alarmclock.AlarmClockUpdateApi;
import com.xxpatx.os.network.api.uiui.app.RunNewApp;
import com.xxpatx.os.network.api.uiui.contact.GetMailList;
import com.xxpatx.os.network.api.uiui.contact.MailListAddApi;
import com.xxpatx.os.network.api.uiui.contact.MailListDeleteApi;
import com.xxpatx.os.network.api.uiui.contact.MailListEditApi;
import com.xxpatx.os.network.api.uiui.contact.ContactApi;
import com.xxpatx.os.network.api.uiui.desktop.GetDesktopApi;
import com.xxpatx.os.network.api.uiui.desktop.UpdateDesktopApi;
import com.xxpatx.os.network.api.uiui.order.AllOrderApi;
@@ -99,6 +97,8 @@ import com.xxpatx.os.network.interceptor.RepeatRequestInterceptor;
import com.xxpatx.os.utils.ContactsUtils;
import com.xxpatx.os.utils.Utils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -122,6 +122,7 @@ import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
@@ -161,6 +162,12 @@ public class NetInterfaceManager {
builder.readTimeout(TIME_OUT, TimeUnit.SECONDS);// 设置读取数据超时时间
builder.retryOnConnectionFailure(true);// 设置进行连接失败重试
builder.addInterceptor(new RepeatRequestInterceptor());
builder.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(@NotNull String s) {
Log.e("HttpLoggingInterceptor", "log: " + s);
}
}).setLevel(HttpLoggingInterceptor.Level.BASIC));
// 设置缓存文件路径
String cacheDirectory = mContext.getExternalCacheDir().getAbsolutePath() + "/OkHttpCache";
@@ -285,6 +292,33 @@ public class NetInterfaceManager {
return requestBody;
}
public static RequestBody convertToRequestBody(Object param) {
MediaType mediaType = MediaType.Companion.parse("text/plain");
RequestBody requestBody = RequestBody.Companion.create(String.valueOf(param), mediaType);
return requestBody;
}
public static RequestBody convertObjectToJsonRequestBody(Object object) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), GsonUtils.toJSONString(object));
return requestBody;
}
public static MultipartBody.Part createMultipartBody(RequestBody requestBody) {
MultipartBody.Part configPart = MultipartBody.Part.createFormData(
"config", // 后端接收的字段名(需与 @Part 名称一致)
null, // 文件名(此处不需要,传 null
requestBody
);
return configPart;
}
public static MultipartBody.Part convertFileToMultipartBody(String name, File file, String type) {
MediaType mediaType = MediaType.Companion.parse(type);
RequestBody requestBody = RequestBody.Companion.create(file, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData(name, file.getName(), requestBody);
return body;
}
/**
* 通过sn获取设备的信息
*
@@ -382,7 +416,7 @@ public class NetInterfaceManager {
}
public Observable<BaseResponse<List<Contact>>> getContactListObservable() {
return mRetrofit.create(GetMailList.class)
return mRetrofit.create(ContactApi.class)
.getContact(Utils.getSerial())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
@@ -402,22 +436,22 @@ public class NetInterfaceManager {
.observeOn(AndroidSchedulers.mainThread());
}
public Observable<BaseResponse> getMailListAddObservable(Map<String, String> params, MultipartBody.Part body) {
return mRetrofit.create(MailListAddApi.class)
.addMailList(params, body)
public Observable<BaseResponse> getMailListAddObservable(Map<String, RequestBody> partMap, MultipartBody.Part body) {
return mRetrofit.create(ContactApi.class)
.addMailList(partMap, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public Observable<BaseResponse> getMailListEditObservable(Map<String, String> params, MultipartBody.Part body) {
return mRetrofit.create(MailListEditApi.class)
.editContact(params, body)
public Observable<BaseResponse> getMailListEditObservable(Map<String, RequestBody> partMap, MultipartBody.Part body) {
return mRetrofit.create(ContactApi.class)
.editContact(partMap, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public Observable<BaseResponse> getMailListDeleteObservable(long id) {
return mRetrofit.create(MailListDeleteApi.class)
return mRetrofit.create(ContactApi.class)
.deleteMailList(Utils.getSerial(), id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());

View File

@@ -0,0 +1,48 @@
package com.xxpatx.os.network.api.uiui.contact;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.bean.Contact;
import com.xxpatx.os.network.UrlAddress;
import java.util.List;
import java.util.Map;
import io.reactivex.rxjava3.core.Observable;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.Query;
public interface ContactApi {
@GET(UrlAddress.GET_MAIL_LIST)
Observable<BaseResponse<List<Contact>>> getContact(
@Query("sn") String sn
);
@Multipart
@POST(UrlAddress.MAIL_LIST_ADD)
Observable<BaseResponse> addMailList(
@PartMap Map<String, RequestBody> partMap,
@Part MultipartBody.Part body
);
@Multipart
@POST(UrlAddress.MAIL_LIST_EDIT)
Observable<BaseResponse> editContact(
@PartMap Map<String, RequestBody> partMap,
@Part MultipartBody.Part body
);
@FormUrlEncoded
@POST(UrlAddress.MAIL_LIST_DELETE)
Observable<BaseResponse> deleteMailList(
@Field("sn") String sn,
@Field("id") long id
);
}

View File

@@ -1,18 +0,0 @@
package com.xxpatx.os.network.api.uiui.contact;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.bean.Contact;
import com.xxpatx.os.network.UrlAddress;
import java.util.List;
import io.reactivex.rxjava3.core.Observable;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface GetMailList {
@GET(UrlAddress.GET_MAIL_LIST)
Observable<BaseResponse<List<Contact>>> getContact(
@Query("sn") String sn
);
}

View File

@@ -1,22 +0,0 @@
package com.xxpatx.os.network.api.uiui.contact;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.network.UrlAddress;
import java.util.Map;
import io.reactivex.rxjava3.core.Observable;
import okhttp3.MultipartBody;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.QueryMap;
public interface MailListAddApi {
@Multipart
@POST(UrlAddress.MAIL_LIST_ADD)
Observable<BaseResponse> addMailList(
@QueryMap Map<String, String> params,
@Part MultipartBody.Part body
);
}

View File

@@ -1,18 +0,0 @@
package com.xxpatx.os.network.api.uiui.contact;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.network.UrlAddress;
import io.reactivex.rxjava3.core.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface MailListDeleteApi {
@FormUrlEncoded
@POST(UrlAddress.MAIL_LIST_DELETE)
Observable<BaseResponse> deleteMailList(
@Field("sn") String sn,
@Field("id") long id
);
}

View File

@@ -1,22 +0,0 @@
package com.xxpatx.os.network.api.uiui.contact;
import com.xxpatx.os.bean.BaseResponse;
import com.xxpatx.os.network.UrlAddress;
import java.util.Map;
import io.reactivex.rxjava3.core.Observable;
import okhttp3.MultipartBody;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.QueryMap;
public interface MailListEditApi {
@Multipart
@POST(UrlAddress.MAIL_LIST_EDIT)
Observable<BaseResponse> editContact(
@QueryMap Map<String, String> params,
@Part MultipartBody.Part body
);
}

View File

@@ -146,9 +146,7 @@ public class MainSPresenter implements MainSContact.Presenter {
});
} else {
File picFile = new File(alarmClockData.getFile());
MediaType mediaType = MediaType.Companion.parse("image/png");
RequestBody requestBody = RequestBody.Companion.create(picFile, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", picFile.getName(), requestBody);
MultipartBody.Part body = NetInterfaceManager.convertFileToMultipartBody("file", picFile, "image/png");
NetInterfaceManager.getInstance().getAlarmClockAddObservable(params, body)
.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
@@ -211,10 +209,7 @@ public class MainSPresenter implements MainSContact.Presenter {
params.put("is_onoff", "1");
File picFile = new File(alarmClockData.getFile());
MediaType mediaType = MediaType.Companion.parse("image/png");
RequestBody requestBody = RequestBody.Companion.create(picFile, mediaType);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", picFile.getName(), requestBody);
MultipartBody.Part body = NetInterfaceManager.convertFileToMultipartBody("file", picFile, "image/png");
return NetInterfaceManager.getInstance().getAlarmClockAddObservable(params, body);
}

View File

@@ -705,8 +705,7 @@ public class MainService extends BaseRxService implements MainSContact.MainSView
// fos.write(b, 0, x);
// }
// fos.close();
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
MultipartBody.Part body = NetInterfaceManager.convertFileToMultipartBody("file", file, "multipart/form-data");
return getSendFile(filePath, body);
}
}).subscribeOn(Schedulers.io())

View File

@@ -0,0 +1,28 @@
package com.xxpatx.os.utils;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
import com.xxpatx.os.base.BaseApplication;
public class ToastUtils {
public static void show(String msg) {
Handler mainHandler = new Handler(Looper.getMainLooper());
new Thread(() -> {
mainHandler.post(() -> {
Toast.makeText(BaseApplication.getContext(), msg, Toast.LENGTH_SHORT).show();
});
}).start();
}
public static void showLong(String msg) {
Handler mainHandler = new Handler(Looper.getMainLooper());
new Thread(() -> {
mainHandler.post(() -> {
Toast.makeText(BaseApplication.getContext(), msg, Toast.LENGTH_LONG).show();
});
}).start();
}
}

View File

@@ -289,6 +289,139 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="8dp"
android:background="@drawable/add_wechat_contact_background">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="在快捷联系人显示"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.xxpatx.os.view.ToggleButton
android:id="@+id/tb_show"
android:layout_width="48dp"
android:layout_height="24dp"
app:tbAsDefaultOn="true"
android:layout_marginEnd="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/add_wechat_contact_background"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp">
<ImageView
android:id="@+id/imageView30"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="快捷拨号类型"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/imageView31"
app:layout_constraintStart_toEndOf="@+id/imageView30"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView31"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CheckBox
android:id="@+id/cb_dialer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="电话" />
<CheckBox
android:id="@+id/cb_sms"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="短信" />
<CheckBox
android:id="@+id/cb_video"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="视频" />
<CheckBox
android:id="@+id/cb_audio"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="语音" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="60dp"
@@ -318,7 +451,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="60dp"
@@ -360,7 +492,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</ScrollView>

View File

@@ -318,6 +318,110 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/add_wechat_contact_background"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp">
<ImageView
android:id="@+id/imageView30"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="快捷拨号类型"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/imageView31"
app:layout_constraintStart_toEndOf="@+id/imageView30"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView31"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CheckBox
android:id="@+id/cb_dialer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="电话" />
<CheckBox
android:id="@+id/cb_sms"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="短信" />
<CheckBox
android:id="@+id/cb_video"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="视频" />
<CheckBox
android:id="@+id/cb_audio"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="true"
android:text="语音" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="60dp"

View File

@@ -13,6 +13,10 @@
<variable
name="contact"
type="com.xxpatx.os.bean.Contact" />
<variable
name="contactConfig"
type="com.xxpatx.os.bean.ContactConfig" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@@ -98,8 +102,8 @@
android:layout_marginTop="32dp"
android:layout_marginBottom="32dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:onClick="@{click::selectPic}"
android:scaleType="centerCrop"
android:src="@drawable/default_avatar"
app:error="@{@drawable/default_avatar}"
app:imageUrl="@{contact.avatar}"
@@ -341,6 +345,110 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/add_wechat_contact_background"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp">
<ImageView
android:id="@+id/imageView30"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="快捷拨号类型"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/imageView31"
app:layout_constraintStart_toEndOf="@+id/imageView30"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView31"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CheckBox
android:id="@+id/cb_dialer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="@{contactConfig.call_phone==1}"
android:text="电话" />
<CheckBox
android:id="@+id/cb_sms"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="@{contactConfig.sms==1}"
android:text="短信" />
<CheckBox
android:id="@+id/cb_video"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="@{contactConfig.wx_video==1}"
android:text="视频" />
<CheckBox
android:id="@+id/cb_audio"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/contact_on_color"
android:checked="@{contactConfig.wx_voice==1}"
android:text="语音" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -15,7 +15,23 @@
type="com.xxpatx.os.bean.Contact" />
<variable
name="tag"
name="contactConfig"
type="com.xxpatx.os.bean.ContactConfig" />
<variable
name="sms"
type="Boolean" />
<variable
name="dialer"
type="Boolean" />
<variable
name="voice"
type="Boolean" />
<variable
name="video"
type="Boolean" />
<import type="android.view.View" />
@@ -210,6 +226,7 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_audio"
android:layout_width="300dp"
android:layout_height="70dp"
android:layout_gravity="center"
@@ -234,6 +251,7 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_video"
android:layout_width="300dp"
android:layout_height="70dp"
android:layout_gravity="center"
@@ -258,6 +276,7 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_dial"
android:layout_width="300dp"
android:layout_height="70dp"
android:layout_gravity="center"

View File

@@ -76,4 +76,6 @@
<color name="contact_text_color">#98999a</color>
<color name="setting_enable_color">#2384BC</color>
<color name="setting_disable_color">#9D9D9D</color>
<color name="contact_on_color">#626E82</color>
</resources>