Compare commits
10 Commits
ae8484b10f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| c746191304 | |||
| a992e40182 | |||
| 6d44cb8b7a | |||
| 219f0bd351 | |||
| 784ca8a8f8 | |||
| 31a77957ad | |||
| e748fcba64 | |||
| 3697aff8dc | |||
| d7e830985f | |||
| a86592005f |
1
app/.gitignore
vendored
1
app/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
/build
|
/build
|
||||||
/proguardbuild/
|
/proguardbuild/
|
||||||
|
/cache/
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
def appName() {
|
def appName() {
|
||||||
@@ -16,8 +18,8 @@ android {
|
|||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
|
|
||||||
versionCode 214
|
versionCode 221
|
||||||
versionName "2.1.4"
|
versionName "2.2.1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
@@ -49,6 +51,13 @@ android {
|
|||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
AMAP_KEY: "565d9142787653544ded10f3f58c48f7"
|
AMAP_KEY: "565d9142787653544ded10f3f58c48f7"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags "-std=c++11 -frtti -fexceptions -Wno-format"
|
||||||
|
arguments '-DANDROID_PLATFORM=android-23', '-DANDROID_STL=c++_shared' ,"-DANDROID_ARM_NEON=TRUE"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -129,6 +138,7 @@ dependencies {
|
|||||||
// Java language implementation
|
// Java language implementation
|
||||||
implementation "androidx.fragment:fragment:1.4.1"
|
implementation "androidx.fragment:fragment:1.4.1"
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
|
implementation 'androidx.browser:browser:1.7.0'
|
||||||
|
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
@@ -181,6 +191,7 @@ dependencies {
|
|||||||
// implementation 'com.baidu.lbsyun:BaiduMapSDK_Location:9.1.8'
|
// implementation 'com.baidu.lbsyun:BaiduMapSDK_Location:9.1.8'
|
||||||
//MMKV
|
//MMKV
|
||||||
implementation 'com.tencent:mmkv-static:1.2.14'
|
implementation 'com.tencent:mmkv-static:1.2.14'
|
||||||
|
// implementation 'com.tencent.tbs.tbssdk:sdk:43993'
|
||||||
//bugly
|
//bugly
|
||||||
implementation 'com.tencent.bugly:crashreport:4.1.9.2'
|
implementation 'com.tencent.bugly:crashreport:4.1.9.2'
|
||||||
/*xCrash */
|
/*xCrash */
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
<!-- 接收短信权限 -->
|
<!-- 接收短信权限 -->
|
||||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||||
<uses-permission android:name="android.permission.BIND_JOB_SERVICE" />
|
<uses-permission android:name="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
|
||||||
|
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
|
||||||
|
|
||||||
<!-- 允许访问网络,必选权限 -->
|
<!-- 允许访问网络,必选权限 -->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@@ -176,8 +178,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".activity.contact.EditContactActivity"
|
android:name=".activity.contact.EditContactActivity"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/AppTheme"
|
android:screenOrientation="portrait"
|
||||||
android:screenOrientation="portrait" />
|
android:theme="@style/AppTheme" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.phone.PhoneActivity"
|
android:name=".activity.phone.PhoneActivity"
|
||||||
android:configChanges="keyboardHidden"
|
android:configChanges="keyboardHidden"
|
||||||
@@ -278,6 +280,11 @@
|
|||||||
android:name=".activity.service.ServiceActivity"
|
android:name=".activity.service.ServiceActivity"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/activity_styles" />
|
android:theme="@style/activity_styles" />
|
||||||
|
<activity
|
||||||
|
android:name=".activity.privacy.PrivacyActivity"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:theme="@style/AppThemeFitsSystem" />
|
||||||
|
|
||||||
<!-- Intent received used to install shortcuts from other applications -->
|
<!-- Intent received used to install shortcuts from other applications -->
|
||||||
<receiver
|
<receiver
|
||||||
@@ -343,10 +350,11 @@
|
|||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.WeAccessibilityService"
|
android:name="com.google.android.accessibility.selecttospeak.SelectToSpeakService"
|
||||||
android:label="@string/accessibility_service_label"
|
android:label="@string/accessibility_service_label"
|
||||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||||
<intent-filter>
|
<!--android:priority="10000" 可提高服务在设置中的权重,排在前面 -->
|
||||||
|
<intent-filter android:priority="10000">
|
||||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.vscool.os.service;
|
package com.google.android.accessibility.selecttospeak;
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityService;
|
import android.accessibilityservice.AccessibilityService;
|
||||||
import android.accessibilityservice.GestureDescription;
|
import android.accessibilityservice.GestureDescription;
|
||||||
@@ -10,7 +10,8 @@ import android.content.IntentFilter;
|
|||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -18,28 +19,42 @@ import android.view.WindowManager;
|
|||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.view.accessibility.AccessibilityWindowInfo;
|
import android.view.accessibility.AccessibilityWindowInfo;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.hjq.toast.Toaster;
|
import com.hjq.toast.Toaster;
|
||||||
import com.tencent.mmkv.MMKV;
|
import com.tencent.mmkv.MMKV;
|
||||||
import com.vscool.os.bean.Contact;
|
import com.vscool.os.bean.Contact;
|
||||||
import com.vscool.os.config.CommonConfig;
|
import com.vscool.os.config.CommonConfig;
|
||||||
import com.vscool.os.utils.ForegroundAppUtil;
|
import com.vscool.os.utils.ForegroundAppUtil;
|
||||||
|
import com.vscool.os.utils.ToastUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.annotations.NonNull;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.core.ObservableEmitter;
|
||||||
|
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||||
|
import io.reactivex.rxjava3.functions.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过微信标签最高支持8.0.49,8.0.50 获取不到数据
|
* 通过微信标签最高支持8.0.49,8.0.50 获取不到数据
|
||||||
* 通过 {@link android.accessibilityservice.AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素
|
* 8.0.54 可以获取
|
||||||
|
* 通过 {@link AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素
|
||||||
*/
|
*/
|
||||||
public class WeAccessibilityService extends AccessibilityService {
|
public class SelectToSpeakService extends AccessibilityService {
|
||||||
private static final String TAG = "WeAccessibilityService";
|
private static final String TAG = "SelectToSpeakService";
|
||||||
|
|
||||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||||
|
|
||||||
|
private static final int ACTION_IME_ENTER_VERSION = 30;
|
||||||
|
private static final int ACTION_IME_ENTER_ID = 16908372;
|
||||||
|
|
||||||
private static final String DIALER_TEXT = "音视频通话";
|
private static final String DIALER_TEXT = "音视频通话";
|
||||||
private static final String CONTACT_TEXT = "通讯录";
|
private static final String CONTACT_TEXT = "通讯录";
|
||||||
|
private static final String SEARCH_TEXT = "搜索";
|
||||||
private static final String TAG_TEXT = "标签";
|
private static final String TAG_TEXT = "标签";
|
||||||
private static final String TAG_NAME = "亲情桌面";
|
private static final String TAG_NAME = "亲情桌面";
|
||||||
private static final String MORE_NAME = "更多功能按钮,已折叠";
|
private static final String MORE_NAME = "更多功能按钮,已折叠";
|
||||||
@@ -49,11 +64,14 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
private static final String CALL_TEXT = "语音通话";
|
private static final String CALL_TEXT = "语音通话";
|
||||||
|
|
||||||
private static final String RECEIVE_DESCRIPTION = "接听";
|
private static final String RECEIVE_DESCRIPTION = "接听";
|
||||||
|
private static final String HANDS_FREE_TEXT = "扬声器已关";
|
||||||
|
private static final String DIALER_HANDS_FREE_TEXT = "免提";
|
||||||
|
private static final String DIALER_HANDS_FREE_CLOSE_TEXT = "免提,已关闭";
|
||||||
|
|
||||||
public static final int TYPE_VOICE = 0;
|
public static final int TYPE_VOICE = 0;
|
||||||
public static final int TYPE_VIDEO = 1;
|
public static final int TYPE_VIDEO = 1;
|
||||||
|
|
||||||
private static final int WAIT_TIME = 1000;
|
private static final int WAIT_TIME = 1600;
|
||||||
|
|
||||||
private int mCallType = TYPE_VOICE;
|
private int mCallType = TYPE_VOICE;
|
||||||
|
|
||||||
@@ -62,17 +80,12 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
private String mName = "";//微信昵称
|
private String mName = "";//微信昵称
|
||||||
private String mTagName = "";//微信联系人标签名
|
private String mTagName = "";//微信联系人标签名
|
||||||
private boolean mAutoAccept = false;
|
private boolean mAutoAccept = false;
|
||||||
private boolean finished = true;
|
|
||||||
|
|
||||||
private Handler handler = null;
|
public interface AccessibilityEventCallback {
|
||||||
private AccessibilityEvent input = null;
|
void onAccessibilityEventCallback(AccessibilityEvent accessibilityEvent);
|
||||||
private Runnable runnable = new Runnable() {
|
}
|
||||||
@Override
|
|
||||||
public void run() {
|
private AccessibilityEventCallback mAccessibilityEventCallback;
|
||||||
_onAccessibilityEvent(input);
|
|
||||||
finished = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
@@ -80,10 +93,27 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
Log.e(TAG, "onCreate: ");
|
Log.e(TAG, "onCreate: ");
|
||||||
registerSettingReceiver();
|
registerSettingReceiver();
|
||||||
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
||||||
handler = new Handler();
|
analysisAccessibilityEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void analysisAccessibilityEvent() {
|
||||||
|
Observable.create(new ObservableOnSubscribe<AccessibilityEvent>() {
|
||||||
|
@Override
|
||||||
|
public void subscribe(@NonNull ObservableEmitter<AccessibilityEvent> emitter) throws Throwable {
|
||||||
|
mAccessibilityEventCallback = emitter::onNext;
|
||||||
|
}
|
||||||
|
}).throttleLast(WAIT_TIME, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribe(new Consumer<AccessibilityEvent>() {
|
||||||
|
@Override
|
||||||
|
public void accept(AccessibilityEvent accessibilityEvent) throws Throwable {
|
||||||
|
Log.e(TAG, "analysisAccessibilityEvent accept: ");
|
||||||
|
_onAccessibilityEvent(accessibilityEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
Log.e(TAG, "onStartCommand: ");
|
Log.e(TAG, "onStartCommand: ");
|
||||||
@@ -98,7 +128,7 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
} else {
|
} else {
|
||||||
mTagName = groupTag;
|
mTagName = groupTag;
|
||||||
}
|
}
|
||||||
mCurrentStep = Step.CLICK_CONTACT;
|
mCurrentStep = Step.CLICK_HOME;
|
||||||
launchWeChat();
|
launchWeChat();
|
||||||
}
|
}
|
||||||
return super.onStartCommand(intent, flags, startId);
|
return super.onStartCommand(intent, flags, startId);
|
||||||
@@ -116,16 +146,45 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
@Override
|
@Override
|
||||||
public void onAccessibilityEvent(AccessibilityEvent event) {
|
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||||
Log.v(TAG, "onAccessibilityEvent: event = " + event.toString());
|
Log.v(TAG, "onAccessibilityEvent: event = " + event.toString());
|
||||||
if (finished) {
|
checkClassName(event);
|
||||||
finished = false;
|
mAccessibilityEventCallback.onAccessibilityEventCallback(event);
|
||||||
} else {
|
|
||||||
Log.v(TAG, "bounce");
|
|
||||||
handler.removeCallbacks(runnable);
|
|
||||||
}
|
|
||||||
input = event;
|
|
||||||
handler.postDelayed(runnable, WAIT_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkClassName(AccessibilityEvent event) {
|
||||||
|
Log.e(TAG, "checkClassName: mCurrentStep = " + mCurrentStep);
|
||||||
|
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
||||||
|
String currentPackageName = event.getPackageName().toString();
|
||||||
|
String currentClassName = event.getClassName().toString();
|
||||||
|
|
||||||
|
switch (mCurrentStep) {
|
||||||
|
case WAITING:
|
||||||
|
if (!TextUtils.isEmpty(currentPackageName) && "com.android.incallui".equals(currentPackageName)) {
|
||||||
|
Log.e(TAG, "checkClassName: to dialer hands free");
|
||||||
|
// mCurrentStep = Step.DIALER_HANDS_FREE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!TextUtils.isEmpty(currentClassName)) {
|
||||||
|
switch (currentClassName) {
|
||||||
|
case "com.tencent.mm.ui.LauncherUI":
|
||||||
|
// if (mCurrentStep != Step.FIND_CONTACT) {
|
||||||
|
// mCurrentStep = Step.CLICK_CONTACT;
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
case "com.tencent.mm.plugin.account.ui.WelcomeActivity":
|
||||||
|
case "com.tencent.mm.plugin.account.ui.LoginPasswordUI":
|
||||||
|
Toaster.showLong("请先登录微信");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
break;
|
||||||
|
case "com.tencent.mm.plugin.label.ui.ContactLabelManagerUI":
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1.在微信页面直接找到联系人拨打电话
|
* 1.在微信页面直接找到联系人拨打电话
|
||||||
@@ -136,42 +195,56 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
*/
|
*/
|
||||||
private void _onAccessibilityEvent(AccessibilityEvent event) {
|
private void _onAccessibilityEvent(AccessibilityEvent event) {
|
||||||
Log.e(TAG, "_onAccessibilityEvent: " + mCurrentStep);
|
Log.e(TAG, "_onAccessibilityEvent: " + mCurrentStep);
|
||||||
switch (mCurrentStep) {
|
|
||||||
case WAITING:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!TextUtils.isEmpty(event.getClassName())) {
|
|
||||||
if ("com.tencent.mm.ui.LauncherUI".contentEquals(event.getClassName())) {
|
|
||||||
if (mCurrentStep != Step.FIND_CONTACT) {
|
|
||||||
mCurrentStep = Step.CLICK_CONTACT;
|
|
||||||
}
|
|
||||||
} else if ("com.tencent.mm.plugin.label.ui.ContactLabelManagerUI".contentEquals(event.getClassName())) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (mCurrentStep) {
|
switch (mCurrentStep) {
|
||||||
case WAITING:
|
case WAITING:
|
||||||
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
||||||
Log.e(TAG, "_onAccessibilityEvent: mAutoAccept = " + mAutoAccept);
|
Log.e(TAG, "_onAccessibilityEvent: mAutoAccept = " + mAutoAccept);
|
||||||
if (!mAutoAccept) {
|
if (mAutoAccept) {
|
||||||
return;
|
autoAccept();
|
||||||
}
|
}
|
||||||
if (stepAnswer(Property.DESCRIPTION, RECEIVE_DESCRIPTION)) {
|
break;
|
||||||
mCurrentStep = Step.WAITING;
|
case WECHAT_HANDS_FREE:
|
||||||
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
|
handsFree(Property.DESCRIPTION, HANDS_FREE_TEXT);
|
||||||
|
break;
|
||||||
|
case DIALER_HANDS_FREE:
|
||||||
|
if (findHandsFree(Property.DESCRIPTION, DIALER_HANDS_FREE_CLOSE_TEXT)) {
|
||||||
|
dialerHandsFree(Property.TEXT, DIALER_HANDS_FREE_TEXT);
|
||||||
} else {
|
} else {
|
||||||
// clickAnswer();
|
mCurrentStep = Step.WAITING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLICK_HOME://主页能找到直接点击进去更多
|
case CLICK_HOME://主页能找到直接点击进去更多
|
||||||
stepHome(Property.TEXT, mName);
|
if (stepHome(Property.TEXT, mName)) {
|
||||||
|
Log.e(TAG, "_onAccessibilityEvent: not found contact in home");
|
||||||
|
} else {
|
||||||
|
clickViewById("com.tencent.mm:id/jha", Step.CLICK_SEARCH);
|
||||||
|
// step(Property.DESCRIPTION, SEARCH_TEXT, Step.CLICK_SEARCH);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CLICK_SEARCH:
|
||||||
|
putString(mName, Step.CLICK_SEARCH_CONTACT);
|
||||||
|
break;
|
||||||
|
case CLICK_SEARCH_CONTACT:
|
||||||
|
if (findSearchContact(Step.FIND_CONTACT)) {
|
||||||
|
findSearchContact(Property.TEXT, mName, Step.CLICK_QUICK_WECHAT_CALL);
|
||||||
|
} else {
|
||||||
|
Toaster.show("没有找到联系人");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLICK_QUICK_WECHAT_CALL://点击更多页面
|
case CLICK_QUICK_WECHAT_CALL://点击更多页面
|
||||||
step(Property.DESCRIPTION, MORE_NAME, Step.CLICK_TARGET);
|
clickViewById("com.tencent.mm:id/bjz", Step.CLICK_TARGET);
|
||||||
|
// step(Property.DESCRIPTION, MORE_NAME, Step.CLICK_TARGET);
|
||||||
break;
|
break;
|
||||||
case CLICK_TARGET://点击视频通话
|
case CLICK_TARGET://点击视频通话
|
||||||
stepCall(Property.TEXT, PARENT_VIDEO_TEXT);
|
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;
|
break;
|
||||||
|
|
||||||
case CLICK_CONTACT://进入通讯录界面
|
case CLICK_CONTACT://进入通讯录界面
|
||||||
@@ -182,31 +255,28 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FIND_CONTACT://模拟滑动找到联系人
|
case FIND_CONTACT://模拟滑动找到联系人
|
||||||
findContact(Property.TEXT, mName, Step.CLICK_NAME);
|
findSearchContact(Property.TEXT, mName, Step.CLICK_QUICK_WECHAT_CALL);
|
||||||
break;
|
break;
|
||||||
case FIND_TAG:
|
case FIND_TAG:
|
||||||
step(Property.TEXT, TAG_TEXT, Step.CLICK_TAG);
|
step(Property.TEXT, TAG_TEXT, Step.CLICK_TAG);
|
||||||
break;
|
break;
|
||||||
case CLICK_TAG:
|
case CLICK_TAG:
|
||||||
step(Property.TEXT, mTagName, Step.CLICK_NAME);
|
if (!step(Property.TEXT, mTagName, Step.CLICK_NAME)) {
|
||||||
|
Toaster.show("没有找到标签");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLICK_NAME://点击item
|
case CLICK_NAME://点击item
|
||||||
step(Property.TEXT, mName, Step.CLICK_INFO);
|
findContact(Property.TEXT, mName, Step.CLICK_INFO);
|
||||||
break;
|
break;
|
||||||
case CLICK_INFO://进入个人信息页面
|
case CLICK_INFO://进入个人信息页面
|
||||||
stepCallDialog(Property.TEXT, DIALER_TEXT, Step.CLICK_CALL);
|
stepCallDialog(Property.TEXT, DIALER_TEXT, Step.CLICK_CALL);
|
||||||
break;
|
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:
|
// case CLICK_VIDEO_CALL:
|
||||||
// if (step(Property.TEXT, VIDEO_TEXT)) {
|
// if (step(Property.TEXT, VIDEO_TEXT)) {
|
||||||
// Log.d(TAG, "finish, now: " + mCurrentStep);
|
// Log.d(TAG, "finish, now: " + mCurrentStep);
|
||||||
// Toast.makeText(this, "成功发起视频聊天", Toast.LENGTH_LONG).show();
|
// ToastUtils.show("成功发起视频聊天");
|
||||||
// }
|
// }
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
@@ -241,16 +311,105 @@ public class WeAccessibilityService 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
|
@Deprecated
|
||||||
private void clickAnswer() {
|
private void clickAnswer() {
|
||||||
String className = ForegroundAppUtil.getForegroundActivityName(WeAccessibilityService.this);
|
String className = ForegroundAppUtil.getForegroundActivityName(SelectToSpeakService.this);
|
||||||
Log.e(TAG, "clickAnswer: " + className);
|
Log.e(TAG, "clickAnswer: " + className);
|
||||||
if (!TextUtils.isEmpty(className)) {
|
if (!TextUtils.isEmpty(className)) {
|
||||||
if ("com.tencent.mm.plugin.voip.ui.VideoActivity".contentEquals(className)) {
|
if ("com.tencent.mm.plugin.voip.ui.VideoActivity".contentEquals(className)) {
|
||||||
boolean successful = clickByPoint(595, 1376);
|
boolean successful = clickByPoint(595, 1376);
|
||||||
Log.e(TAG, "clickAnswer: " + successful);
|
Log.e(TAG, "clickAnswer: " + successful);
|
||||||
if (successful) {
|
if (successful) {
|
||||||
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
|
ToastUtils.show("已自动接听视频/语音");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "clickAnswer: Not in the answering interface");
|
Log.e(TAG, "clickAnswer: Not in the answering interface");
|
||||||
@@ -308,9 +467,69 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean findSearchContact(Step nextStep) {
|
||||||
|
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId("com.tencent.mm:id/gzf");
|
||||||
|
Log.e(TAG, "findSearchContact: " + nodeInfos);
|
||||||
|
Optional<AccessibilityNodeInfo> optional = nodeInfos.stream().findAny();
|
||||||
|
return optional.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findSearchContact(Property type, String text, Step nextStep) {
|
||||||
|
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId("com.tencent.mm:id/odf");
|
||||||
|
Log.e(TAG, "findSearchContact: " + nodeInfos);
|
||||||
|
Optional<AccessibilityNodeInfo> optional = nodeInfos.stream().findAny();
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
AccessibilityNodeInfo nodeInfo = optional.get();
|
||||||
|
clickNode(nodeInfo);
|
||||||
|
mCurrentStep = nextStep;
|
||||||
|
} else {
|
||||||
|
Toaster.show("没有找到联系人");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putString(String text, Step nextStep) {
|
||||||
|
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId("com.tencent.mm:id/d98");
|
||||||
|
Optional<AccessibilityNodeInfo> optional = nodeInfos.stream().findAny();
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
AccessibilityNodeInfo nodeInfo = optional.get();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
|
||||||
|
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
|
||||||
|
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); // 确保焦点在输入框
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= ACTION_IME_ENTER_VERSION) {
|
||||||
|
//see https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER
|
||||||
|
nodeInfo.performAction(ACTION_IME_ENTER_ID);
|
||||||
|
}
|
||||||
|
mCurrentStep = nextStep;
|
||||||
|
} else {
|
||||||
|
Toaster.show("没有找到搜索框");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickViewById(String id, Step nextStep) {
|
||||||
|
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId(id);
|
||||||
|
Optional<AccessibilityNodeInfo> optional = nodeInfos.stream().findAny();
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
AccessibilityNodeInfo nodeInfo = optional.get();
|
||||||
|
clickNode(nodeInfo);
|
||||||
|
mCurrentStep = nextStep;
|
||||||
|
} else {
|
||||||
|
// Toaster.show("没有找到搜索按钮");
|
||||||
|
step(Property.DESCRIPTION, SEARCH_TEXT, Step.CLICK_SEARCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<AccessibilityNodeInfo> findNodesByViewId(String id) {
|
private List<AccessibilityNodeInfo> findNodesByViewId(String id) {
|
||||||
List<AccessibilityNodeInfo> accessibilityNodeInfos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id);
|
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
|
||||||
return accessibilityNodeInfos;
|
if (nodeInfo != null) {
|
||||||
|
List<AccessibilityNodeInfo> accessibilityNodeInfos = nodeInfo.findAccessibilityNodeInfosByViewId(id);
|
||||||
|
return accessibilityNodeInfos;
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessibilityNodeInfo findNodeByText(AccessibilityNodeInfo root, String text) {
|
private AccessibilityNodeInfo findNodeByText(AccessibilityNodeInfo root, String text) {
|
||||||
@@ -349,7 +568,7 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
} else {
|
} else {
|
||||||
if (mFindCount == mMaxCount) {
|
if (mFindCount == mMaxCount) {
|
||||||
Log.e("stepCallDialog", "mCurrentStep: max");
|
Log.e("stepCallDialog", "mCurrentStep: max");
|
||||||
Toast.makeText(this, "没有找到联系人", Toast.LENGTH_LONG).show();
|
ToastUtils.show("没有找到联系人");
|
||||||
mCurrentStep = Step.WAITING;
|
mCurrentStep = Step.WAITING;
|
||||||
mFindCount = 0;
|
mFindCount = 0;
|
||||||
return false;
|
return false;
|
||||||
@@ -368,11 +587,11 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
if (node != null) {
|
if (node != null) {
|
||||||
clickNode(node);
|
clickNode(node);
|
||||||
Log.e(TAG, "stepHome: mCurrentStep: " + mCurrentStep + " done");
|
Log.e(TAG, "stepHome: mCurrentStep: " + mCurrentStep + " done");
|
||||||
mCurrentStep = mCurrentStep.next();
|
mCurrentStep = Step.CLICK_QUICK_WECHAT_CALL;
|
||||||
Log.e(TAG, "stepHome: next: " + mCurrentStep);
|
Log.e(TAG, "stepHome: next: " + mCurrentStep);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
mCurrentStep = Step.CLICK_CONTACT;
|
mCurrentStep = Step.CLICK_SEARCH;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +612,7 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
} else {
|
} else {
|
||||||
if (mFindCount == mMaxCount) {
|
if (mFindCount == mMaxCount) {
|
||||||
Log.e("findContact", "mCurrentStep: max");
|
Log.e("findContact", "mCurrentStep: max");
|
||||||
Toast.makeText(this, "没有找到联系人", Toast.LENGTH_LONG).show();
|
ToastUtils.show("没有找到联系人");
|
||||||
mCurrentStep = Step.WAITING;
|
mCurrentStep = Step.WAITING;
|
||||||
mFindCount = 0;
|
mFindCount = 0;
|
||||||
return false;
|
return false;
|
||||||
@@ -454,6 +673,10 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
|
|
||||||
|
|
||||||
private void clickNode(AccessibilityNodeInfo node) {
|
private void clickNode(AccessibilityNodeInfo node) {
|
||||||
|
if (node == null) {
|
||||||
|
Log.e(TAG, "clickNode: node is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Log.e(TAG, "clickNode: getText = " + node.getText());
|
Log.e(TAG, "clickNode: getText = " + node.getText());
|
||||||
Log.e(TAG, "clickNode: isClickable = " + node.isClickable());
|
Log.e(TAG, "clickNode: isClickable = " + node.isClickable());
|
||||||
@@ -461,6 +684,14 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
Log.e(TAG, "clickNode: e = " + e.getMessage());
|
Log.e(TAG, "clickNode: e = " + e.getMessage());
|
||||||
}
|
}
|
||||||
if (node.isClickable()) {
|
if (node.isClickable()) {
|
||||||
|
//防检测机制:
|
||||||
|
//添加随机延迟(避免高频操作)
|
||||||
|
// handler.postDelayed(new Runnable() {
|
||||||
|
// @Override
|
||||||
|
// public void run() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }, 1000 + new Random().nextInt(100));
|
||||||
boolean performAction = node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
|
boolean performAction = node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
|
||||||
Log.e(TAG, "clickNode: performAction = " + performAction);
|
Log.e(TAG, "clickNode: performAction = " + performAction);
|
||||||
if (!performAction) {
|
if (!performAction) {
|
||||||
@@ -489,12 +720,13 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
private boolean stepCall(Property type, String text) {
|
private boolean stepCall(Property type, String text) {
|
||||||
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
|
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
Point point = getPointtByNode(node);
|
Point point = getPointtByNode(node);
|
||||||
Log.e(TAG, "stepCall: " + point);
|
Log.e(TAG, "stepCall: " + point);
|
||||||
clickByPoint(point.x, point.y + 30);
|
clickByPoint(point.x, point.y);
|
||||||
// clickNode(node);
|
// clickNode(node);
|
||||||
Log.e(TAG, "stepCall: mCurrentStep " + mCurrentStep + " done");
|
Log.e(TAG, "stepCall: mCurrentStep " + mCurrentStep + " done");
|
||||||
mCurrentStep = Step.CLICK_CALL;
|
mCurrentStep = Step.CLICK_CALL;
|
||||||
@@ -506,6 +738,18 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clickVideoCall() {
|
||||||
|
List<AccessibilityNodeInfo> nodeInfos = findNodesByViewId("com.tencent.mm:id/a12");
|
||||||
|
Optional<AccessibilityNodeInfo> accessibilityNodeInfo = nodeInfos.stream().findAny();
|
||||||
|
if (accessibilityNodeInfo.isPresent()) {
|
||||||
|
AccessibilityNodeInfo nodeInfo = accessibilityNodeInfo.get();
|
||||||
|
clickNode(nodeInfo);
|
||||||
|
mCurrentStep = Step.CLICK_CALL;
|
||||||
|
} else {
|
||||||
|
Toaster.show("没有找到通话按钮");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean stepAnswer(Property type, String text) {
|
private boolean stepAnswer(Property type, String text) {
|
||||||
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
@@ -524,6 +768,52 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean dialerHandsFree(Property type, String text) {
|
||||||
|
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||||
|
if (node != null) {
|
||||||
|
Rect rect = new Rect();
|
||||||
|
node.getBoundsInScreen(rect);
|
||||||
|
Log.e(TAG, "dialerHandsFree: rect = " + rect);
|
||||||
|
clickNode(node);
|
||||||
|
Log.e(TAG, "dialerHandsFree: mCurrentStep: " + mCurrentStep + " done");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
Log.e(TAG, "dialerHandsFree: next: " + mCurrentStep);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean findHandsFree(Property type, String text) {
|
||||||
|
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||||
|
if (node != null) {
|
||||||
|
Log.e(TAG, "findHandsFree: true");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "findHandsFree: false");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handsFree(Property type, String text) {
|
||||||
|
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||||
|
if (node != null) {
|
||||||
|
Point point = getPointtByNode(node);
|
||||||
|
Log.e(TAG, "handsFree: " + point);
|
||||||
|
clickByPoint(point.x, point.y - 50);
|
||||||
|
clickByPoint(point.x, point.y);
|
||||||
|
// clickNode(node);
|
||||||
|
Log.e(TAG, "handsFree: mCurrentStep " + mCurrentStep + " done");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
Log.e(TAG, "handsFree: next " + mCurrentStep);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "handsFree: not found");
|
||||||
|
mCurrentStep = Step.WAITING;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//根据节点信息可获得对应的x,y坐标
|
//根据节点信息可获得对应的x,y坐标
|
||||||
static Point getPointtByNode(AccessibilityNodeInfo node) {
|
static Point getPointtByNode(AccessibilityNodeInfo node) {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
@@ -543,7 +833,9 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
path.moveTo(point.x, point.y);
|
path.moveTo(point.x, point.y);
|
||||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||||
builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200));
|
//防检测机制:
|
||||||
|
//添加随机延迟(避免高频操作)
|
||||||
|
builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200 + new Random().nextInt(100)));
|
||||||
GestureDescription gesture = builder.build();
|
GestureDescription gesture = builder.build();
|
||||||
boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() {
|
boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -609,19 +901,34 @@ public class WeAccessibilityService extends AccessibilityService {
|
|||||||
|
|
||||||
private enum Step {
|
private enum Step {
|
||||||
WAITING,
|
WAITING,
|
||||||
CLICK_HOME,
|
//微信免提
|
||||||
CLICK_QUICK_WECHAT_CALL,
|
WECHAT_HANDS_FREE,
|
||||||
CLICK_TARGET,
|
//电话免提
|
||||||
|
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,
|
CLICK_CONTACT,
|
||||||
FIND_CONTACT,
|
FIND_CONTACT,
|
||||||
CLICK_TAG,
|
//通讯录页面点击标签
|
||||||
FIND_TAG,
|
FIND_TAG,
|
||||||
|
//点击对应的标签名
|
||||||
|
CLICK_TAG,
|
||||||
CLICK_NAME,
|
CLICK_NAME,
|
||||||
CLICK_INFO,
|
CLICK_INFO,
|
||||||
|
|
||||||
CLICK_CALL,
|
|
||||||
CLICK_VIDEO_CALL;
|
CLICK_VIDEO_CALL;
|
||||||
|
|
||||||
private Step next() {
|
private Step next() {
|
||||||
@@ -2,24 +2,29 @@ package com.vscool.os.activity.callwechat;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.Settings;
|
import android.util.Log;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.hjq.toast.Toaster;
|
import com.google.android.accessibility.selecttospeak.SelectToSpeakService;
|
||||||
|
import com.tencent.mmkv.MMKV;
|
||||||
import com.vscool.os.R;
|
import com.vscool.os.R;
|
||||||
import com.vscool.os.base.mvvm.BaseMvvmActivity;
|
import com.vscool.os.base.mvvm.BaseMvvmActivity;
|
||||||
import com.vscool.os.bean.Contact;
|
import com.vscool.os.bean.Contact;
|
||||||
|
import com.vscool.os.config.CommonConfig;
|
||||||
import com.vscool.os.databinding.ActivityWechatCallBinding;
|
import com.vscool.os.databinding.ActivityWechatCallBinding;
|
||||||
import com.vscool.os.service.WeAccessibilityService;
|
|
||||||
import com.vscool.os.utils.AccessibilityUtils;
|
import com.vscool.os.utils.AccessibilityUtils;
|
||||||
|
import com.vscool.os.utils.ApkUtils;
|
||||||
|
|
||||||
public class CallWechatActivity extends BaseMvvmActivity<CallWechatViewModel, ActivityWechatCallBinding> {
|
public class CallWechatActivity extends BaseMvvmActivity<CallWechatViewModel, ActivityWechatCallBinding> {
|
||||||
|
private static final String TAG = "CallWechatActivity";
|
||||||
|
|
||||||
|
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||||
|
|
||||||
private Contact mContact;
|
private Contact mContact;
|
||||||
|
|
||||||
|
// private static final int REQUEST_CODE_SCREEN_CAPTURE = 1874;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setfitWindow() {
|
public boolean setfitWindow() {
|
||||||
return true;
|
return true;
|
||||||
@@ -62,20 +67,48 @@ public class CallWechatActivity extends BaseMvvmActivity<CallWechatViewModel, Ac
|
|||||||
if (contact != null) {
|
if (contact != null) {
|
||||||
mContact = contact;
|
mContact = contact;
|
||||||
mViewDataBinding.setContact(contact);
|
mViewDataBinding.setContact(contact);
|
||||||
mViewDataBinding.setTag(!TextUtils.isEmpty(contact.getTag()));
|
// mViewDataBinding.setTag(!TextUtils.isEmpty(contact.getTag()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
// super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
// Log.e(TAG, "onActivityResult: requestCode = " + requestCode);
|
||||||
|
// Log.e(TAG, "onActivityResult: resultCode = " + resultCode);
|
||||||
|
//
|
||||||
|
// if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) {
|
||||||
|
// // 启动屏幕捕获服务
|
||||||
|
// Intent intent = new Intent(CallWechatActivity.this, SelectToSpeakService.class);
|
||||||
|
// intent.putExtra("WechatInfo", mContact);
|
||||||
|
// intent.putExtra("call_type", mCallType);
|
||||||
|
// intent.putExtra("resultCode", resultCode);
|
||||||
|
// intent.putExtra("resultData", data);
|
||||||
|
//
|
||||||
|
//// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
//// startForegroundService(intent);
|
||||||
|
//// } else {
|
||||||
|
// startService(intent);
|
||||||
|
//// }
|
||||||
|
// finish();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
private boolean checkSettings() {
|
private boolean checkSettings() {
|
||||||
boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(this);
|
boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(this);
|
||||||
if (!accessibility) {
|
if (!accessibility) {
|
||||||
Toast.makeText(this, "请在无障碍服务中打开 - 亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
AccessibilityUtils.openAccessibilitySettings(this);
|
||||||
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
|
|
||||||
}
|
}
|
||||||
return accessibility;
|
return accessibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isWeChatAutoCall() {
|
||||||
|
boolean wxAutoVideo = mMMKV.decodeInt(CommonConfig.WECHAT_AUTO_CALL_KEY, 0) == 1;
|
||||||
|
Log.e(TAG, "isWeChatAutoCall: " + wxAutoVideo);
|
||||||
|
return wxAutoVideo;
|
||||||
|
}
|
||||||
|
|
||||||
public class BtnClick {
|
public class BtnClick {
|
||||||
public void callPhone(View view) {
|
public void callPhone(View view) {
|
||||||
Intent dialIntent = new Intent(Intent.ACTION_CALL);
|
Intent dialIntent = new Intent(Intent.ACTION_CALL);
|
||||||
@@ -87,31 +120,59 @@ public class CallWechatActivity extends BaseMvvmActivity<CallWechatViewModel, Ac
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void callWechatVideo(View view) {
|
public void callWechatVideo(View view) {
|
||||||
if (TextUtils.isEmpty(mContact.getTag())) {
|
// if (TextUtils.isEmpty(mContact.getTag())) {
|
||||||
Toaster.show("没有设置标签,无法拨打微信视频");
|
// Toaster.show("没有设置标签,无法拨打微信视频");
|
||||||
return;
|
// finish();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
if (isWeChatAutoCall()) {
|
||||||
|
if (checkSettings()) {
|
||||||
|
// 1. 获取 MediaProjectionManager 实例
|
||||||
|
// MediaProjectionManager projectionManager = (MediaProjectionManager)
|
||||||
|
// getSystemService(Context.MEDIA_PROJECTION_SERVICE);
|
||||||
|
// Intent captureIntent = projectionManager.createScreenCaptureIntent();
|
||||||
|
// startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE);
|
||||||
|
|
||||||
|
// // 2. 系统应用可通过反射绕过用户确认
|
||||||
|
// Intent intent = new Intent("android.media.action.GET_SCREEN_CAPTURE");
|
||||||
|
// intent.putExtra("extra_screen_capture_allowed", true);
|
||||||
|
// startActivityForResult(intent, REQUEST_CODE_SCREEN_CAPTURE);
|
||||||
|
|
||||||
|
Intent intent = new Intent(CallWechatActivity.this, SelectToSpeakService.class);
|
||||||
|
intent.putExtra("WechatInfo", mContact);
|
||||||
|
intent.putExtra("call_type", SelectToSpeakService.TYPE_VIDEO);
|
||||||
|
|
||||||
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
// startForegroundService(intent);
|
||||||
|
// } else {
|
||||||
|
startService(intent);
|
||||||
|
// }
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ApkUtils.openPackage(CallWechatActivity.this, "com.tencent.mm");
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
if (checkSettings()) {
|
|
||||||
Intent intent = new Intent(CallWechatActivity.this, WeAccessibilityService.class);
|
|
||||||
intent.putExtra("WechatInfo", mContact);
|
|
||||||
intent.putExtra("call_type", WeAccessibilityService.TYPE_VIDEO);
|
|
||||||
startService(intent);
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callWechatVoice(View view) {
|
public void callWechatVoice(View view) {
|
||||||
if (TextUtils.isEmpty(mContact.getTag())) {
|
// if (TextUtils.isEmpty(mContact.getTag())) {
|
||||||
Toaster.show("没有设置标签,无法拨打微信语音");
|
// Toaster.show("没有设置标签,无法拨打微信语音");
|
||||||
return;
|
// finish();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
if (isWeChatAutoCall()) {
|
||||||
|
if (checkSettings()) {
|
||||||
|
Intent intent = new Intent(CallWechatActivity.this, SelectToSpeakService.class);
|
||||||
|
intent.putExtra("WechatInfo", mContact);
|
||||||
|
intent.putExtra("call_type", SelectToSpeakService.TYPE_VOICE);
|
||||||
|
startService(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ApkUtils.openPackage(CallWechatActivity.this, "com.tencent.mm");
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
if (checkSettings()) {
|
|
||||||
Intent intent = new Intent(CallWechatActivity.this, WeAccessibilityService.class);
|
|
||||||
intent.putExtra("WechatInfo", mContact);
|
|
||||||
intent.putExtra("call_type", WeAccessibilityService.TYPE_VOICE);
|
|
||||||
startService(intent);
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exit(View view) {
|
public void exit(View view) {
|
||||||
|
|||||||
@@ -164,10 +164,10 @@ public class EditContactActivity extends BaseMvvmActivity<EditContactViewModel,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String groupTag = mViewDataBinding.etGroup.getText().toString();
|
String groupTag = mViewDataBinding.etGroup.getText().toString();
|
||||||
if (TextUtils.isEmpty(groupTag)) {
|
// if (TextUtils.isEmpty(groupTag)) {
|
||||||
Toaster.show("请输入微信群组标签");
|
// Toaster.show("请输入微信群组标签");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
File avatarFile;
|
File avatarFile;
|
||||||
Log.e("checkContact", "mPictrueFilePath: " + mPictrueFilePath);
|
Log.e("checkContact", "mPictrueFilePath: " + mPictrueFilePath);
|
||||||
if (TextUtils.isEmpty(mPictrueFilePath)) {
|
if (TextUtils.isEmpty(mPictrueFilePath)) {
|
||||||
|
|||||||
@@ -841,7 +841,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
|||||||
// 去开启 监听通知权限
|
// 去开启 监听通知权限
|
||||||
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
|
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
|
||||||
}
|
}
|
||||||
|
// sendBroadcast(new Intent(SelectToSpeakService.STOP_RECORD_ACTION));
|
||||||
setDockApp();
|
setDockApp();
|
||||||
initAmap();
|
initAmap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package com.vscool.os.activity.privacy;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.WebChromeClient;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import com.vscool.os.R;
|
||||||
|
import com.vscool.os.base.mvvm.BaseMvvmActivity;
|
||||||
|
import com.vscool.os.databinding.ActivityPrivacyBinding;
|
||||||
|
|
||||||
|
public class PrivacyActivity extends BaseMvvmActivity<PrivacyViewModel, ActivityPrivacyBinding> {
|
||||||
|
private static final String TAG = "PrivacyActivity";
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setNightMode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setfitWindow() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLayoutId() {
|
||||||
|
return R.layout.activity_privacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initDataBinding() {
|
||||||
|
mViewModel.setCtx(this);
|
||||||
|
mViewModel.setVDBinding(mViewDataBinding);
|
||||||
|
mViewModel.setLifecycle(getLifecycleSubject());
|
||||||
|
mViewDataBinding.setClick(new BtnClick());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initView() {
|
||||||
|
WebSettings settings = mViewDataBinding.webView.getSettings();
|
||||||
|
// settings.setUseWideViewPort(true);
|
||||||
|
settings.setJavaScriptEnabled(true);
|
||||||
|
settings.setAllowFileAccess(true);
|
||||||
|
settings.setAllowContentAccess(true);
|
||||||
|
settings.setAllowFileAccessFromFileURLs(true);
|
||||||
|
settings.setAllowUniversalAccessFromFileURLs(true);
|
||||||
|
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
|
||||||
|
|
||||||
|
mViewDataBinding.webView.setWebViewClient(new WebViewClient());
|
||||||
|
mViewDataBinding.webView.setWebChromeClient(new WebChromeClient() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(WebView view, int newProgress) {
|
||||||
|
super.onProgressChanged(view, newProgress);
|
||||||
|
if (newProgress == 100) {
|
||||||
|
mViewDataBinding.progressBar.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
mViewDataBinding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
mViewDataBinding.progressBar.setMax(100);
|
||||||
|
mViewDataBinding.progressBar.setProgress(newProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Intent intent = getIntent();
|
||||||
|
int contentType = intent.getIntExtra("ContentType", 1);
|
||||||
|
switch (contentType) {
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
mViewDataBinding.tvTitle.setText("用户协议");
|
||||||
|
mViewDataBinding.webView.loadUrl("https://www.uiuios.com/agreement.html?section=1-1&status=1&projectId=10");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mViewDataBinding.tvTitle.setText("隐私政策");
|
||||||
|
mViewDataBinding.webView.loadUrl("https://www.uiuios.com/agreement.html?section=1-2&status=1&projectId=10");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mViewDataBinding.tvTitle.setText("SDK共享清单");
|
||||||
|
mViewDataBinding.webView.loadUrl("https://www.uiuios.com/agreement.html?section=1-3&status=1&projectId=10");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mViewDataBinding.tvTitle.setText("微信一键视频、语音通话功能用户须知");
|
||||||
|
mViewDataBinding.webView.loadUrl("https://www.uiuios.com/agreement.html?section=3-6&status=1&projectId=10");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initData() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BtnClick {
|
||||||
|
public void exit(View view) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.vscool.os.activity.privacy;
|
||||||
|
|
||||||
|
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||||
|
import com.vscool.os.base.mvvm.BaseViewModel;
|
||||||
|
import com.vscool.os.databinding.ActivityPrivacyBinding;
|
||||||
|
|
||||||
|
public class PrivacyViewModel extends BaseViewModel<ActivityPrivacyBinding, ActivityEvent> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActivityPrivacyBinding getVDBinding() {
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.lifecycle.Observer;
|
import androidx.lifecycle.Observer;
|
||||||
|
|
||||||
|
import com.google.android.accessibility.selecttospeak.SelectToSpeakService;
|
||||||
import com.hjq.toast.Toaster;
|
import com.hjq.toast.Toaster;
|
||||||
import com.tencent.mmkv.MMKV;
|
import com.tencent.mmkv.MMKV;
|
||||||
import com.vscool.os.BuildConfig;
|
import com.vscool.os.BuildConfig;
|
||||||
@@ -32,7 +33,7 @@ import com.vscool.os.config.CommonConfig;
|
|||||||
import com.vscool.os.databinding.ActivitySettingBinding;
|
import com.vscool.os.databinding.ActivitySettingBinding;
|
||||||
import com.vscool.os.dialog.CustomDialog;
|
import com.vscool.os.dialog.CustomDialog;
|
||||||
import com.vscool.os.dialog.PermissionsDialog;
|
import com.vscool.os.dialog.PermissionsDialog;
|
||||||
import com.vscool.os.service.WeAccessibilityService;
|
import com.vscool.os.fragment.dialog.PrivacyPolicyFragment;
|
||||||
import com.vscool.os.service.main.MainService;
|
import com.vscool.os.service.main.MainService;
|
||||||
import com.vscool.os.utils.AccessibilityUtils;
|
import com.vscool.os.utils.AccessibilityUtils;
|
||||||
import com.vscool.os.utils.ApkUtils;
|
import com.vscool.os.utils.ApkUtils;
|
||||||
@@ -84,7 +85,12 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
@Override
|
@Override
|
||||||
public void onToggle(boolean on) {
|
public void onToggle(boolean on) {
|
||||||
if (on) {
|
if (on) {
|
||||||
showFloatingWindow();
|
boolean permission = checkFloatPermission(SettingActivity.this);
|
||||||
|
if (permission) {
|
||||||
|
showFloatingWindow();
|
||||||
|
} else {
|
||||||
|
showFloatWindowDialog();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hideFloatingWindow();
|
hideFloatingWindow();
|
||||||
}
|
}
|
||||||
@@ -96,12 +102,18 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
setVoiceBroadcast(on);
|
setVoiceBroadcast(on);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mViewDataBinding.tbAuto.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
|
mViewDataBinding.tbAutoAnswer.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
|
||||||
@Override
|
@Override
|
||||||
public void onToggle(boolean on) {
|
public void onToggle(boolean on) {
|
||||||
setAutoAccept(on);
|
setAutoAccept(on);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mViewDataBinding.tbAutoCall.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
|
||||||
|
@Override
|
||||||
|
public void onToggle(boolean on) {
|
||||||
|
setWechatAutoCall(on);
|
||||||
|
}
|
||||||
|
});
|
||||||
mViewDataBinding.tbDialer.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
|
mViewDataBinding.tbDialer.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
|
||||||
@Override
|
@Override
|
||||||
public void onToggle(boolean on) {
|
public void onToggle(boolean on) {
|
||||||
@@ -214,32 +226,44 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
Log.e(TAG, "onResume: ");
|
||||||
setStatus();
|
setStatus();
|
||||||
mViewModel.getSystemSettings();
|
mViewModel.getSystemSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStatus() {
|
private void setStatus() {
|
||||||
boolean showFloatWindow = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
boolean showFloatWindow = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
||||||
Log.e(TAG, "initView: showFloatWindow = " + showFloatWindow);
|
Log.e(TAG, "setStatus: showFloatWindow = " + showFloatWindow);
|
||||||
mViewDataBinding.tbFloat.setToggleStatu(showFloatWindow);
|
mViewDataBinding.tbFloat.setToggleStatu(showFloatWindow);
|
||||||
|
if (showFloatWindow) {
|
||||||
|
boolean permission = checkFloatPermission(SettingActivity.this);
|
||||||
|
if (permission) {
|
||||||
|
showFloatingWindow();
|
||||||
|
} else {
|
||||||
|
showFloatWindowDialog();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hideFloatingWindow();
|
||||||
|
}
|
||||||
|
|
||||||
boolean voiceBroadcast = mMMKV.decodeBool(CommonConfig.VOICE_BROADCAST, false);
|
boolean voiceBroadcast = mMMKV.decodeBool(CommonConfig.VOICE_BROADCAST, false);
|
||||||
Log.e(TAG, "initView: voiceBroadcast = " + voiceBroadcast);
|
Log.e(TAG, "setStatus: voiceBroadcast = " + voiceBroadcast);
|
||||||
mViewDataBinding.tbSms.setToggleStatu(voiceBroadcast);
|
mViewDataBinding.tbSms.setToggleStatu(voiceBroadcast);
|
||||||
|
|
||||||
boolean autoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
boolean autoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
||||||
Log.e(TAG, "initView: autoAccept = " + autoAccept);
|
Log.e(TAG, "setStatus: autoAccept = " + autoAccept);
|
||||||
mViewDataBinding.tbAuto.setToggleStatu(autoAccept);
|
mViewDataBinding.tbAutoAnswer.setToggleStatu(autoAccept);
|
||||||
if (autoAccept) {
|
if (autoAccept) {
|
||||||
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
||||||
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
|
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
|
||||||
if (floatWindowEnable && permission) {
|
boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this);
|
||||||
|
if (floatWindowEnable && permission && !accessibility) {
|
||||||
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
|
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
|
||||||
showFloatWindowDialog();
|
showFloatHideDialog();
|
||||||
} else {
|
} else {
|
||||||
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
||||||
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
|
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
|
||||||
Intent intent = new Intent(WeAccessibilityService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
Intent intent = new Intent(SelectToSpeakService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
||||||
intent.putExtra("auto_answer", true);
|
intent.putExtra("auto_answer", true);
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
} else {
|
} else {
|
||||||
@@ -248,29 +272,33 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean wxAutoVideo = mMMKV.decodeInt(CommonConfig.WECHAT_AUTO_CALL_KEY, 0) == 1;
|
||||||
|
Log.e(TAG, "setStatus: wxAutoVideo = " + autoAccept);
|
||||||
|
mViewDataBinding.tbAutoCall.setToggleStatu(wxAutoVideo);
|
||||||
|
|
||||||
boolean dialTone = mMMKV.decodeBool(CommonConfig.DISABLE_DIAL_TONE_MODIFY, true);
|
boolean dialTone = mMMKV.decodeBool(CommonConfig.DISABLE_DIAL_TONE_MODIFY, true);
|
||||||
Log.e(TAG, "initView: dialTone = " + dialTone);
|
Log.e(TAG, "setStatus: dialTone = " + dialTone);
|
||||||
mViewDataBinding.tbDialer.setToggleStatu(dialTone);
|
mViewDataBinding.tbDialer.setToggleStatu(dialTone);
|
||||||
|
|
||||||
int code = Settings.System.getInt(getContentResolver(), CommonConfig.ACTION_STATUS_BAR_STATE, 0);
|
int code = Settings.System.getInt(getContentResolver(), CommonConfig.ACTION_STATUS_BAR_STATE, 0);
|
||||||
boolean statusBar = code == 1;
|
boolean statusBar = code == 1;
|
||||||
Log.e(TAG, "initView: statusBar = " + statusBar);
|
Log.e(TAG, "setStatus: statusBar = " + statusBar);
|
||||||
mViewDataBinding.tbStatu.setToggleStatu(statusBar);
|
mViewDataBinding.tbStatu.setToggleStatu(statusBar);
|
||||||
|
|
||||||
boolean hourlyTime = mMMKV.decodeBool(CommonConfig.HOURLY_TIME_SIGNAL_KEY, false);
|
boolean hourlyTime = mMMKV.decodeBool(CommonConfig.HOURLY_TIME_SIGNAL_KEY, false);
|
||||||
Log.e(TAG, "initView: hourlyTime = " + hourlyTime);
|
Log.e(TAG, "setStatus: hourlyTime = " + hourlyTime);
|
||||||
mViewDataBinding.tbHourly.setToggleStatu(hourlyTime);
|
mViewDataBinding.tbHourly.setToggleStatu(hourlyTime);
|
||||||
|
|
||||||
boolean disableKey = mMMKV.decodeBool(CommonConfig.DISABLE_VOLUME_KEY, false);
|
boolean disableKey = mMMKV.decodeBool(CommonConfig.DISABLE_VOLUME_KEY, false);
|
||||||
Log.e(TAG, "initView: disableKey = " + disableKey);
|
Log.e(TAG, "setStatus: disableKey = " + disableKey);
|
||||||
mViewDataBinding.tbVolume.setToggleStatu(!disableKey);
|
mViewDataBinding.tbVolume.setToggleStatu(!disableKey);
|
||||||
|
|
||||||
boolean contactModify = mMMKV.decodeBool(CommonConfig.DISABLE_CONTACT_MODIFY, false);
|
boolean contactModify = mMMKV.decodeBool(CommonConfig.DISABLE_CONTACT_MODIFY, false);
|
||||||
Log.e(TAG, "initView: contactModify = " + contactModify);
|
Log.e(TAG, "setStatus: contactModify = " + contactModify);
|
||||||
mViewDataBinding.tbContact.setToggleStatu(!contactModify);
|
mViewDataBinding.tbContact.setToggleStatu(!contactModify);
|
||||||
|
|
||||||
int clockModify = mMMKV.decodeInt(CommonConfig.ALARM_CLOCK_CTRL, 1);
|
int clockModify = mMMKV.decodeInt(CommonConfig.ALARM_CLOCK_CTRL, 1);
|
||||||
Log.e(TAG, "initView: clockModify = " + clockModify);
|
Log.e(TAG, "setStatus: clockModify = " + clockModify);
|
||||||
mViewDataBinding.tbClock.setToggleStatu(clockModify == 1);
|
mViewDataBinding.tbClock.setToggleStatu(clockModify == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,30 +402,48 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
|
|
||||||
public void setAutoAccept(boolean on) {
|
public void setAutoAccept(boolean on) {
|
||||||
if (on) {
|
if (on) {
|
||||||
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
new PrivacyPolicyFragment(new PrivacyPolicyFragment.DialogFragmentCallback() {
|
||||||
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
|
@Override
|
||||||
if (floatWindowEnable && permission) {
|
public void onPositive() {
|
||||||
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
|
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
||||||
showFloatWindowDialog();
|
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
|
||||||
} else {
|
boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this);
|
||||||
showAutoAcceptDialog();
|
if (floatWindowEnable && permission && !accessibility) {
|
||||||
|
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
|
||||||
|
showFloatHideDialog();
|
||||||
|
} else {
|
||||||
|
showAutoAcceptDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNegative() {
|
||||||
|
Toaster.show("请先阅读并同意用户须知");
|
||||||
|
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 0);
|
||||||
|
mViewDataBinding.tbAutoCall.setToggleStatu(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss() {
|
||||||
|
setStatus();
|
||||||
|
}
|
||||||
|
}).show(getSupportFragmentManager(), PrivacyPolicyFragment.class.getSimpleName());
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 0);
|
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 0);
|
||||||
mViewDataBinding.tbAuto.setToggleStatu(false);
|
mViewDataBinding.tbAutoAnswer.setToggleStatu(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
// if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
||||||
// mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, on);
|
// mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, on);
|
||||||
// Intent intent = new Intent(WeAccessibilityService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
// Intent intent = new Intent(SelectToSpeakService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
||||||
// intent.putExtra("auto_answer", on);
|
// intent.putExtra("auto_answer", on);
|
||||||
// sendBroadcast(intent);
|
// sendBroadcast(intent);
|
||||||
// } else {
|
// } else {
|
||||||
// boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
// boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
|
||||||
// if (floatWindowEnable) {
|
// if (floatWindowEnable) {
|
||||||
// Toaster.showLong("由于系统限制,请先关闭 主页按钮 功能,开启自动接听后再打开");
|
// Toaster.showLong("由于系统限制,请先关闭 主页按钮 功能,开启自动接听后再打开");
|
||||||
// mViewDataBinding.tbAuto.setToggleOff();
|
// mViewDataBinding.tbAutoAnswer.setToggleOff();
|
||||||
// } else {
|
// } else {
|
||||||
// Toast.makeText(SettingActivity.this, "请在无障碍服务中打开 - 亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
// Toast.makeText(SettingActivity.this, "请在无障碍服务中打开 - 亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
||||||
// startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
|
// startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
|
||||||
@@ -406,6 +452,62 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setWechatAutoCall(boolean on) {
|
||||||
|
if (on) {
|
||||||
|
new PrivacyPolicyFragment(new PrivacyPolicyFragment.DialogFragmentCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPositive() {
|
||||||
|
mMMKV.encode(CommonConfig.WECHAT_AUTO_CALL_KEY, 1);
|
||||||
|
mViewDataBinding.tbAutoCall.setToggleStatu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNegative() {
|
||||||
|
Toaster.show("请先阅读并同意用户须知");
|
||||||
|
mMMKV.encode(CommonConfig.WECHAT_AUTO_CALL_KEY, 0);
|
||||||
|
mViewDataBinding.tbAutoCall.setToggleStatu(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss() {
|
||||||
|
setStatus();
|
||||||
|
}
|
||||||
|
}).show(getSupportFragmentManager(), PrivacyPolicyFragment.class.getSimpleName());
|
||||||
|
} else {
|
||||||
|
mMMKV.encode(CommonConfig.WECHAT_AUTO_CALL_KEY, 0);
|
||||||
|
mViewDataBinding.tbAutoCall.setToggleStatu(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PermissionsDialog mFloatWindowHideDialog;
|
||||||
|
|
||||||
|
private void showFloatHideDialog() {
|
||||||
|
if (mFloatWindowHideDialog != null) {
|
||||||
|
mFloatWindowHideDialog.dismiss();
|
||||||
|
mFloatWindowHideDialog = null;
|
||||||
|
}
|
||||||
|
mFloatWindowHideDialog = new PermissionsDialog(SettingActivity.this);
|
||||||
|
mFloatWindowHideDialog.setTitle("功能说明");
|
||||||
|
mFloatWindowHideDialog.setContent("由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗");
|
||||||
|
mFloatWindowHideDialog.setDeniedtext("取消");
|
||||||
|
mFloatWindowHideDialog.setGrantedtext("确定");
|
||||||
|
mFloatWindowHideDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() {
|
||||||
|
@Override
|
||||||
|
public void onGranted() {
|
||||||
|
mFloatWindowHideDialog.dismiss();
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDenied() {
|
||||||
|
mFloatWindowHideDialog.dismiss();
|
||||||
|
mViewDataBinding.tbAutoAnswer.setToggleStatu(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mFloatWindowHideDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
private PermissionsDialog mFloatWindowDialog;
|
private PermissionsDialog mFloatWindowDialog;
|
||||||
|
|
||||||
private void showFloatWindowDialog() {
|
private void showFloatWindowDialog() {
|
||||||
@@ -415,21 +517,29 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
}
|
}
|
||||||
mFloatWindowDialog = new PermissionsDialog(SettingActivity.this);
|
mFloatWindowDialog = new PermissionsDialog(SettingActivity.this);
|
||||||
mFloatWindowDialog.setTitle("功能说明");
|
mFloatWindowDialog.setTitle("功能说明");
|
||||||
mFloatWindowDialog.setContent("由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗");
|
mFloatWindowDialog.setContent("您已开启悬浮窗功能,程序需要授予悬浮窗权限才能使用此功能,是否同意授权");
|
||||||
mFloatWindowDialog.setDeniedtext("取消");
|
mFloatWindowDialog.setDeniedtext("取消");
|
||||||
mFloatWindowDialog.setGrantedtext("确定");
|
mFloatWindowDialog.setGrantedtext("确定");
|
||||||
mFloatWindowDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() {
|
mFloatWindowDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onGranted() {
|
public void onGranted() {
|
||||||
mFloatWindowDialog.dismiss();
|
// 在Activity或Fragment中请求权限
|
||||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
|
if (!Settings.canDrawOverlays(SettingActivity.this)) {
|
||||||
startActivity(intent);
|
Toast.makeText(SettingActivity.this, "请先打开悬浮窗权限", Toast.LENGTH_LONG).show();
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||||
|
Uri.parse("package:" + getPackageName()));
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_DRAW_OVER_OTHER_APPS_PERMISSION);
|
||||||
|
} else {
|
||||||
|
showFloatingWindow();
|
||||||
|
mFloatWindowDialog.dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDenied() {
|
public void onDenied() {
|
||||||
mFloatWindowDialog.dismiss();
|
mFloatWindowDialog.dismiss();
|
||||||
mViewDataBinding.tbAuto.setToggleStatu(false);
|
mViewDataBinding.tbFloat.setToggleStatu(false);
|
||||||
|
Settings.Global.putInt(getContentResolver(), CommonConfig.HOVER_HOME, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mFloatWindowDialog.show();
|
mFloatWindowDialog.show();
|
||||||
@@ -445,9 +555,9 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
mAutoAcceptDialog = new PermissionsDialog(SettingActivity.this);
|
mAutoAcceptDialog = new PermissionsDialog(SettingActivity.this);
|
||||||
mAutoAcceptDialog.setTitle("功能说明");
|
mAutoAcceptDialog.setTitle("功能说明");
|
||||||
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
||||||
mAutoAcceptDialog.setContent("微信视频和语言通话全屏通知情况下,开启自动接听。");
|
mAutoAcceptDialog.setContent("微信视频和语音通话全屏通知情况下,开启自动接听。");
|
||||||
} else {
|
} else {
|
||||||
mAutoAcceptDialog.setContent("微信视频和语言通话全屏通知情况下,开启自动接听。微信自动接听功能需要获取无障碍权限,点击确定将会跳转到系统设置页面");
|
mAutoAcceptDialog.setContent("微信视频和语音通话全屏通知情况下,开启自动接听。微信自动接听功能需要获取无障碍权限,点击确定将会跳转到系统设置页面");
|
||||||
}
|
}
|
||||||
mAutoAcceptDialog.setDeniedtext("取消");
|
mAutoAcceptDialog.setDeniedtext("取消");
|
||||||
mAutoAcceptDialog.setGrantedtext("确定");
|
mAutoAcceptDialog.setGrantedtext("确定");
|
||||||
@@ -456,13 +566,13 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
public void onGranted() {
|
public void onGranted() {
|
||||||
mAutoAcceptDialog.dismiss();
|
mAutoAcceptDialog.dismiss();
|
||||||
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
|
||||||
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
|
Intent intent = new Intent(SelectToSpeakService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
||||||
Intent intent = new Intent(WeAccessibilityService.SETTING_AUTOMATIC_ANSWER_ACTION);
|
|
||||||
intent.putExtra("auto_answer", true);
|
intent.putExtra("auto_answer", true);
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
|
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
|
||||||
|
mViewDataBinding.tbAutoAnswer.setToggleStatu(true);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(SettingActivity.this, "请在无障碍服务中打开 - 亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
AccessibilityUtils.openAccessibilitySettings(SettingActivity.this);
|
||||||
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +580,7 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
|
|||||||
public void onDenied() {
|
public void onDenied() {
|
||||||
mAutoAcceptDialog.dismiss();
|
mAutoAcceptDialog.dismiss();
|
||||||
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 0);
|
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 0);
|
||||||
mViewDataBinding.tbAuto.setToggleStatu(false);
|
mViewDataBinding.tbAutoAnswer.setToggleStatu(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mAutoAcceptDialog.show();
|
mAutoAcceptDialog.show();
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ package com.vscool.os.adapter;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
@@ -112,8 +110,7 @@ public class WechatContactAdapter extends RecyclerView.Adapter<WechatContactAdap
|
|||||||
|
|
||||||
private void checkAccessibility() {
|
private void checkAccessibility() {
|
||||||
if (!AccessibilityUtils.isAccessibilitySettingsOn(mContext)) {
|
if (!AccessibilityUtils.isAccessibilitySettingsOn(mContext)) {
|
||||||
Toast.makeText(mContext, "请在无障碍服务中打开 - 亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
AccessibilityUtils.openAccessibilitySettings(mContext);
|
||||||
mContext.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
|
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "checkAccessibility: 无障碍服务已打开");
|
Log.e(TAG, "checkAccessibility: 无障碍服务已打开");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.vscool.os.base;
|
package com.vscool.os.base;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -36,9 +38,20 @@ import com.vscool.os.utils.Utils;
|
|||||||
public class BaseApplication extends Application {
|
public class BaseApplication extends Application {
|
||||||
private static final String TAG = "BaseApplication";
|
private static final String TAG = "BaseApplication";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewModel中因为经常旋转导致弱引用为空
|
||||||
|
*/
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static Context context;
|
||||||
|
|
||||||
|
public static Context getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
context = getApplicationContext();
|
||||||
if (!BuildConfig.DEBUG) {
|
if (!BuildConfig.DEBUG) {
|
||||||
catchException();
|
catchException();
|
||||||
}
|
}
|
||||||
@@ -46,6 +59,7 @@ public class BaseApplication extends Application {
|
|||||||
Log.e(TAG, "mmkv root: " + rootDir);
|
Log.e(TAG, "mmkv root: " + rootDir);
|
||||||
|
|
||||||
JgyUtils.init(this);
|
JgyUtils.init(this);
|
||||||
|
JgyUtils.getInstance().hookWebView();
|
||||||
|
|
||||||
// 初始化 Toast 框架
|
// 初始化 Toast 框架
|
||||||
Toaster.init(this);
|
Toaster.init(this);
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ public class CommonConfig {
|
|||||||
public static final String VOICE_BROADCAST = "voice_broadcast_key";
|
public static final String VOICE_BROADCAST = "voice_broadcast_key";
|
||||||
/*微信语音自动接听*/
|
/*微信语音自动接听*/
|
||||||
public static final String WECHAT_CALL_AUTO_ACCEPT = "wechat_call_auto_accept";
|
public static final String WECHAT_CALL_AUTO_ACCEPT = "wechat_call_auto_accept";
|
||||||
|
/*微信语音自动免提*/
|
||||||
|
public static final String WECHAT_AUTO_HNADS_FREE = "wechat_auto_hands_free";
|
||||||
|
/*是否为微信自动拨打电话*/
|
||||||
|
public static final String WECHAT_AUTO_CALL_KEY = "wechat_auto_call_video";
|
||||||
|
|
||||||
/*本地设置的*/
|
/*本地设置的*/
|
||||||
/*悬浮窗*/
|
/*悬浮窗*/
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package com.vscool.os.fragment.dialog;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.text.style.ClickableSpan;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import com.vscool.os.R;
|
||||||
|
import com.vscool.os.activity.privacy.PrivacyActivity;
|
||||||
|
import com.vscool.os.databinding.FragmentPrivacyPolicyBinding;
|
||||||
|
|
||||||
|
public class PrivacyPolicyFragment extends DialogFragment {
|
||||||
|
private static final String TAG = "PrivacyPolicyFragment";
|
||||||
|
|
||||||
|
private FragmentPrivacyPolicyBinding mBinding;
|
||||||
|
private View rootView;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public interface DialogFragmentCallback {
|
||||||
|
void onPositive();
|
||||||
|
|
||||||
|
void onNegative();
|
||||||
|
|
||||||
|
void onDismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DialogFragmentCallback mDismissCallback;
|
||||||
|
|
||||||
|
public PrivacyPolicyFragment(DialogFragmentCallback dialogFragmentCallback) {
|
||||||
|
this.mDismissCallback = dialogFragmentCallback;
|
||||||
|
// Required empty public constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
Log.e(TAG, "onCreateView: ");
|
||||||
|
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_privacy_policy, container, false);
|
||||||
|
mBinding.setClick(new BtnClick());
|
||||||
|
rootView = mBinding.getRoot();
|
||||||
|
mContext = rootView.getContext();
|
||||||
|
initView();
|
||||||
|
return rootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
return super.onCreateDialog(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initView() {
|
||||||
|
mBinding.tvConfirm.setEnabled(false);
|
||||||
|
mBinding.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
if (isChecked) {
|
||||||
|
mBinding.tvConfirm.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
mBinding.tvConfirm.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SpannableString spannableString = new SpannableString(mContext.getResources().getString(R.string.user_notice));
|
||||||
|
spannableString.setSpan(new ClickableSpan() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull View widget) {
|
||||||
|
// String url = "https://www.uiuios.com/agreement.html?section=1-1&status=1";
|
||||||
|
// CustomTabsIntent intent = new CustomTabsIntent.Builder().build();
|
||||||
|
// try {
|
||||||
|
// intent.launchUrl(mContext, Uri.parse(url));
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// Log.e(TAG, "onClick: " + e.getMessage());
|
||||||
|
// }
|
||||||
|
|
||||||
|
Intent intent = new Intent(mContext, PrivacyActivity.class);
|
||||||
|
intent.putExtra("ContentType", 4);
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
}
|
||||||
|
}, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
spannableString.setSpan(new ForegroundColorSpan(Color.BLUE), 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
mBinding.tvUserNotice.setText(spannableString);
|
||||||
|
mBinding.tvUserNotice.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
if (getDialog() != null) {
|
||||||
|
Window window = getDialog().getWindow();
|
||||||
|
if (window == null) return;
|
||||||
|
WindowManager.LayoutParams params = window.getAttributes();
|
||||||
|
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
window.setAttributes(params);
|
||||||
|
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||||
|
getDialog().setCancelable(true);
|
||||||
|
getDialog().setCanceledOnTouchOutside(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void show(FragmentManager manager, String tag) {
|
||||||
|
DialogFragment fragment = (DialogFragment) manager.findFragmentByTag(tag);
|
||||||
|
if (fragment != null && fragment.isAdded()
|
||||||
|
&& fragment.getDialog() != null && fragment.getDialog().isShowing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FragmentTransaction ft = manager.beginTransaction();
|
||||||
|
ft.add(this, tag);
|
||||||
|
ft.commitAllowingStateLoss();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "show: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||||
|
super.onDismiss(dialog);
|
||||||
|
if (mDismissCallback != null) {
|
||||||
|
mDismissCallback.onDismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BtnClick {
|
||||||
|
|
||||||
|
public void onPositiveClick(View view) {
|
||||||
|
if (mBinding.checkBox.isChecked()) {
|
||||||
|
if (mDismissCallback != null) {
|
||||||
|
mDismissCallback.onPositive();
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
} else {
|
||||||
|
if (mDismissCallback != null) {
|
||||||
|
mDismissCallback.onNegative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRead(View view) {
|
||||||
|
mBinding.checkBox.setChecked(!mBinding.checkBox.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ public class AppStatusManager {
|
|||||||
this.add("com.tencent.mm");
|
this.add("com.tencent.mm");
|
||||||
this.add("com.ss.android.ugc.aweme");
|
this.add("com.ss.android.ugc.aweme");
|
||||||
this.add("com.mediatek.camera");
|
this.add("com.mediatek.camera");
|
||||||
|
this.add("com.uiui.browser");
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private static final Set<String> mExcludeApp = new HashSet<String>() {{
|
private static final Set<String> mExcludeApp = new HashSet<String>() {{
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.vscool.os.service;
|
package com.vscool.os.service;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
import android.service.notification.NotificationListenerService;
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.vscool.os.utils.ApkUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -79,6 +83,19 @@ public class NotificationService extends NotificationListenerService {
|
|||||||
for (NotificationListener listener : mListener) {
|
for (NotificationListener listener : mListener) {
|
||||||
listener.onListenerUpdate();
|
listener.onListenerUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取通知来源包名(如微信、QQ)
|
||||||
|
String packageName = sbn.getPackageName();
|
||||||
|
if ("com.tencent.mm".equalsIgnoreCase(packageName)) {
|
||||||
|
// 提取通知内容
|
||||||
|
Notification notification = sbn.getNotification();
|
||||||
|
String text = notification.extras.getString(Notification.EXTRA_TEXT);
|
||||||
|
if (!TextUtils.isEmpty(text)) {
|
||||||
|
if (text.contains("邀请你语音通话") || text.contains("邀请你视频通话")) {
|
||||||
|
ApkUtils.openPackage(NotificationService.this, "com.tencent.mm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
package com.vscool.os.utils;
|
package com.vscool.os.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.vscool.os.service.WeAccessibilityService;
|
import com.google.android.accessibility.selecttospeak.SelectToSpeakService;
|
||||||
|
|
||||||
public class AccessibilityUtils {
|
public class AccessibilityUtils {
|
||||||
private static final String TAG = "AccessibilityUtils";
|
private static final String TAG = "AccessibilityUtils";
|
||||||
|
|
||||||
public static boolean isAccessibilitySettingsOn(Context context) {
|
public static boolean isAccessibilitySettingsOn(Context context) {
|
||||||
int accessibilityEnabled = 0;
|
int accessibilityEnabled = 0;
|
||||||
final String service = context.getPackageName() + "/" + WeAccessibilityService.class.getCanonicalName();
|
final String service = context.getPackageName() + "/" + SelectToSpeakService.class.getCanonicalName();
|
||||||
try {
|
try {
|
||||||
accessibilityEnabled = Settings.Secure.getInt(
|
accessibilityEnabled = Settings.Secure.getInt(
|
||||||
context.getApplicationContext().getContentResolver(),
|
context.getApplicationContext().getContentResolver(),
|
||||||
@@ -40,4 +43,16 @@ public class AccessibilityUtils {
|
|||||||
Log.v(TAG, "***ACCESSIBILITY IS DISABLED***");
|
Log.v(TAG, "***ACCESSIBILITY IS DISABLED***");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openAccessibilitySettings(Context context) {
|
||||||
|
Toast.makeText(context, "请在无障碍服务中打开 -亲情桌面快捷服务", Toast.LENGTH_LONG).show();
|
||||||
|
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||||
|
String str = context.getPackageName() + "/" + SelectToSpeakService.class.getName();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(":settings:fragment_args_key", str);
|
||||||
|
intent.putExtra(":settings:fragment_args_key", str);
|
||||||
|
intent.putExtra(":settings:show_fragment_args", bundle);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import android.provider.Settings;
|
|||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class JgyUtils {
|
public class JgyUtils {
|
||||||
private static String TAG = "JgyUtils";
|
private static String TAG = "JgyUtils";
|
||||||
|
|
||||||
@@ -99,5 +103,45 @@ public class JgyUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String chromium_pkg = "org.chromium.browser";
|
||||||
|
|
||||||
|
public void hookWebView() {
|
||||||
|
// if (!ApkUtils.isAvailable(mContext, chromium_pkg)) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
int sdkInt = Build.VERSION.SDK_INT;
|
||||||
|
try {
|
||||||
|
Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
|
||||||
|
Field field = factoryClass.getDeclaredField("sProviderInstance");
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object sProviderInstance = field.get(null);
|
||||||
|
if (sProviderInstance != null) {
|
||||||
|
Log.d(TAG, "sProviderInstance isn't null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Method getProviderClassMethod;
|
||||||
|
if (sdkInt > 22) { // above 22
|
||||||
|
getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
|
||||||
|
} else if (sdkInt == 22) { // method name is a little different
|
||||||
|
getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
|
||||||
|
} else { // no security check below 22
|
||||||
|
Log.i(TAG, "Don't need to Hook WebView");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getProviderClassMethod.setAccessible(true);
|
||||||
|
Class<?> providerClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
|
||||||
|
Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
|
||||||
|
Constructor<?> declaredConstructor = delegateClass.getDeclaredConstructor();
|
||||||
|
declaredConstructor.setAccessible(true);
|
||||||
|
sProviderInstance = providerClass
|
||||||
|
.getDeclaredMethod("create", delegateClass)
|
||||||
|
.invoke(providerClass, declaredConstructor.newInstance());
|
||||||
|
Log.d("sProviderInstance", sProviderInstance.toString());
|
||||||
|
field.set("sProviderInstance", sProviderInstance);
|
||||||
|
Log.d(TAG, "Hook done!");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.e(TAG, "hook WebView Failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
28
app/src/main/java/com/vscool/os/utils/ToastUtils.java
Normal file
28
app/src/main/java/com/vscool/os/utils/ToastUtils.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package com.vscool.os.utils;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.vscool.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,7 +138,9 @@ public class ToggleButton extends View {
|
|||||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||||
springSystem = SpringSystem.create();
|
springSystem = SpringSystem.create();
|
||||||
spring = springSystem.createSpring();
|
spring = springSystem.createSpring();
|
||||||
spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(50, 7));
|
//张力(tension),摩擦力(friction)
|
||||||
|
//增大张力会使弹簧更快地向目标值运动,减小摩擦力会减少弹簧运动过程中的阻力,从而使回弹更加迅速和有力。
|
||||||
|
spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(80, 10));
|
||||||
this.setOnClickListener(new OnClickListener() {
|
this.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View arg0) {
|
public void onClick(View arg0) {
|
||||||
@@ -342,7 +344,7 @@ public class ToggleButton extends View {
|
|||||||
/**
|
/**
|
||||||
* @param on = =
|
* @param on = =
|
||||||
*/
|
*/
|
||||||
public void onToggle(boolean on);
|
void onToggle(boolean on);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnToggleChanged(OnToggleChanged onToggleChanged) {
|
public void setOnToggleChanged(OnToggleChanged onToggleChanged) {
|
||||||
|
|||||||
BIN
app/src/main/res/drawable-hdpi/icon_back_black.png
Normal file
BIN
app/src/main/res/drawable-hdpi/icon_back_black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
9
app/src/main/res/drawable/ic_negative.xml
Normal file
9
app/src/main/res/drawable/ic_negative.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:fillColor="#CDE0FF"
|
||||||
|
android:pathData="M512,512m-448,0a448,448 0,1 0,896 0,448 448,0 1,0 -896,0Z" />
|
||||||
|
</vector>
|
||||||
10
app/src/main/res/drawable/ic_positive.xml
Normal file
10
app/src/main/res/drawable/ic_positive.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#0362ff"
|
||||||
|
android:pathData="M511.6,63.6c-246.9,0 -448,201.2 -448,448 0,247.3 201.2,448 448,448s448,-200.7 448,-448c0,-246.9 -200.7,-448 -448,-448zM771.5,382.1L474.6,699.3c-7,7.3 -16.5,12.1 -27.4,12.1 -10.5,0 -20.5,-4.7 -27.4,-12.1L252,520c-7,-7.3 -11.5,-17.8 -11.5,-29.4 0,-23.1 17.5,-41.4 38.9,-41.4 10.5,0 20.5,4.7 27.4,12.1l140.7,149.9 270,-287.8c7,-7.3 16.5,-12.1 27.4,-12.1 21.5,0 38.9,18.3 38.9,41.4 -0.8,11.6 -5.3,22.1 -12.3,29.4zM771.5,382.1" />
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/policy_checkbox_bg.xml
Normal file
5
app/src/main/res/drawable/policy_checkbox_bg.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_enabled="true" android:state_checked="false" android:drawable="@drawable/ic_negative" />
|
||||||
|
<item android:state_enabled="true" android:state_checked="true" android:drawable="@drawable/ic_positive" />
|
||||||
|
</selector>
|
||||||
25
app/src/main/res/drawable/privacy_policy_card_bg.xml
Normal file
25
app/src/main/res/drawable/privacy_policy_card_bg.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<!-- 填充的颜色:这里设置背景透明 -->
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
<!-- 边框的颜色 :不能和窗口背景色一样 -->
|
||||||
|
|
||||||
|
<!-- 设置按钮的四个角为弧形 -->
|
||||||
|
<!-- android:radius 弧形的半径 -->
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="12dp"
|
||||||
|
android:bottomRightRadius="12dp"
|
||||||
|
android:topLeftRadius="12dp"
|
||||||
|
android:topRightRadius="12dp" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- padding:Button里面的文字与Button边界的间隔 -->
|
||||||
|
<!-- <padding-->
|
||||||
|
<!-- android:bottom="10dp"-->
|
||||||
|
<!-- android:left="10dp"-->
|
||||||
|
<!-- android:right="10dp"-->
|
||||||
|
<!-- android:top="10dp" />-->
|
||||||
|
|
||||||
|
</shape>
|
||||||
23
app/src/main/res/drawable/privacy_policy_negative_bg.xml
Normal file
23
app/src/main/res/drawable/privacy_policy_negative_bg.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<!-- 填充的颜色:这里设置背景透明 -->
|
||||||
|
<solid android:color="#CDE0FF" />
|
||||||
|
<!-- 边框的颜色 :不能和窗口背景色一样 -->
|
||||||
|
|
||||||
|
<!-- 设置按钮的四个角为弧形 -->
|
||||||
|
<!-- android:radius 弧形的半径 -->
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="12dp"
|
||||||
|
android:bottomRightRadius="12dp"
|
||||||
|
android:topLeftRadius="12dp"
|
||||||
|
android:topRightRadius="12dp" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- padding:Button里面的文字与Button边界的间隔 -->
|
||||||
|
<padding
|
||||||
|
android:bottom="8dp"
|
||||||
|
android:top="8dp" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
23
app/src/main/res/drawable/privacy_policy_positive_bg.xml
Normal file
23
app/src/main/res/drawable/privacy_policy_positive_bg.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<!-- 填充的颜色:这里设置背景透明 -->
|
||||||
|
<solid android:color="#0362FF" />
|
||||||
|
<!-- 边框的颜色 :不能和窗口背景色一样 -->
|
||||||
|
|
||||||
|
<!-- 设置按钮的四个角为弧形 -->
|
||||||
|
<!-- android:radius 弧形的半径 -->
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="12dp"
|
||||||
|
android:bottomRightRadius="12dp"
|
||||||
|
android:topLeftRadius="12dp"
|
||||||
|
android:topRightRadius="12dp" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- padding:Button里面的文字与Button边界的间隔 -->
|
||||||
|
<padding
|
||||||
|
android:bottom="8dp"
|
||||||
|
android:top="8dp" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 没有焦点时的背景颜色 -->
|
||||||
|
<item android:drawable="@drawable/privacy_policy_positive_bg" android:state_enabled="true" />
|
||||||
|
<!-- <!– 非触摸模式下获得焦点并单击时的背景颜色 –>-->
|
||||||
|
<!-- <item android:drawable="@drawable/privacy_policy_positive_bg" android:state_focused="true" android:state_pressed="true" />-->
|
||||||
|
<!-- <!– 触摸模式下单击时的背景颜色 –>-->
|
||||||
|
<!-- <item android:drawable="@drawable/privacy_policy_positive_bg" android:state_focused="false" android:state_pressed="true" />-->
|
||||||
|
<!-- <!– 选中时的背景颜色 –>-->
|
||||||
|
<!-- <item android:drawable="@drawable/privacy_policy_positive_bg" android:state_selected="true" />-->
|
||||||
|
<!-- <!– 获得焦点时的背景 颜色 –>-->
|
||||||
|
<!-- <item android:drawable="@drawable/privacy_policy_positive_bg" android:state_focused="true" />-->
|
||||||
|
|
||||||
|
<item android:drawable="@drawable/privacy_policy_negative_bg" android:state_enabled="false" />
|
||||||
|
</selector>
|
||||||
26
app/src/main/res/drawable/progress_background.xml
Normal file
26
app/src/main/res/drawable/progress_background.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:id="@android:id/background">
|
||||||
|
<shape>
|
||||||
|
<corners android:radius="2dp" />
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:centerColor="#E3E3E3"
|
||||||
|
android:endColor="#E6E6E6"
|
||||||
|
android:startColor="#C8C8C8" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:id="@android:id/progress">
|
||||||
|
<clip>
|
||||||
|
<shape>
|
||||||
|
<corners android:radius="2dp" />
|
||||||
|
<gradient
|
||||||
|
android:centerColor="#2196F3"
|
||||||
|
android:endColor="#2196F3"
|
||||||
|
android:startColor="#2099FA" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
|
</clip>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
||||||
@@ -212,6 +212,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
android:background="@drawable/add_wechat_contact_background">
|
android:background="@drawable/add_wechat_contact_background">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|||||||
@@ -234,7 +234,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:background="@drawable/add_wechat_contact_background">
|
android:background="@drawable/add_wechat_contact_background"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageView11"
|
android:id="@+id/imageView11"
|
||||||
|
|||||||
72
app/src/main/res/layout/activity_privacy.xml
Normal file
72
app/src/main/res/layout/activity_privacy.xml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context=".activity.privacy.PrivacyActivity">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="click"
|
||||||
|
type="com.vscool.os.activity.privacy.PrivacyActivity.BtnClick" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/cl_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView3"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:onClick="@{click::exit}"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/icon_back_black"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="隐私协议"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageView3"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:progressDrawable="@drawable/progress_background"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cl_bar" />
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/webView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/progressBar" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</layout>
|
||||||
@@ -185,7 +185,40 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.vscool.os.view.ToggleButton
|
<com.vscool.os.view.ToggleButton
|
||||||
android:id="@+id/tb_auto"
|
android:id="@+id/tb_auto_answer"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/lightGray"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="72dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
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.vscool.os.view.ToggleButton
|
||||||
|
android:id="@+id/tb_auto_call"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
|
|||||||
@@ -132,7 +132,7 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/update_cancel_background"
|
android:background="@drawable/update_cancel_background"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:onClick="@{click.exit}"
|
android:onClick="@{click::exit}"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="取消"
|
android:text="取消"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/update_background"
|
android:background="@drawable/update_background"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:onClick="@{click.upgrade}"
|
android:onClick="@{click::upgrade}"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="更新"
|
android:text="更新"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
|
|||||||
@@ -215,8 +215,7 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:background="@drawable/icon_wechat_call_video"
|
android:background="@drawable/icon_wechat_call_video"
|
||||||
android:onClick="@{click::callWechatVideo}"
|
android:onClick="@{click::callWechatVideo}">
|
||||||
android:visibility="@{tag==true?View.VISIBLE:View.GONE}">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -241,8 +240,7 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:background="@drawable/icon_wechat_call_voice"
|
android:background="@drawable/icon_wechat_call_voice"
|
||||||
android:onClick="@{click::callWechatVoice}"
|
android:onClick="@{click::callWechatVoice}">
|
||||||
android:visibility="@{tag==true?View.VISIBLE:View.GONE}">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
137
app/src/main/res/layout/fragment_privacy_policy.xml
Normal file
137
app/src/main/res/layout/fragment_privacy_policy.xml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context=".fragment.dialog.PrivacyPolicyFragment">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="click"
|
||||||
|
type="com.vscool.os.fragment.dialog.PrivacyPolicyFragment.BtnClick" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="330dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/privacy_policy_card_bg"
|
||||||
|
android:maxHeight="500dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="功能开启提醒"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginBottom="32dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/constraintLayout7"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_title">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:text="@string/wechat_auto_call_hint"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/constraintLayout7"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout5"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:onClick="@{click::onRead}">
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/checkBox"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:button="@drawable/policy_checkbox_bg"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_user_notice"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/user_notice"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/checkBox"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_confirm"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/privacy_policy_positive_selector"
|
||||||
|
android:enabled="false"
|
||||||
|
android:gravity="center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:onClick="@{click::onPositiveClick}"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="我已知晓并需要启动此功能"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="17sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/tv_content"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</layout>
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
<string name="title_activity_settings">Settings</string>
|
<string name="title_activity_settings">Settings</string>
|
||||||
<string name="clear_app_size">已清理%d个应用</string>
|
<string name="clear_app_size">已清理%d个应用</string>
|
||||||
|
|
||||||
|
<string name="wechat_auto_call_hint">您当前要开启微信自动拨打视频、语音、自动接听等功能,此功能需要开启系统的无障碍服务才能实现。用户在开启前需要明确知晓其风险,请详细查看协议内容,用户同意后方可使用此功能。</string>
|
||||||
|
<string name="user_notice">《微信一键视频、语音通话功能用户须知》</string>
|
||||||
|
|
||||||
<!-- Preference Titles -->
|
<!-- Preference Titles -->
|
||||||
<string name="messages_header">Messages</string>
|
<string name="messages_header">Messages</string>
|
||||||
<string name="sync_header">Sync</string>
|
<string name="sync_header">Sync</string>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:accessibilityEventTypes="typeAllMask|typeViewClicked|typeViewFocused|typeWindowStateChanged|typeWindowsChanged|typeContextClicked|typeWindowContentChanged"
|
android:accessibilityEventTypes="typeAllMask"
|
||||||
android:accessibilityFeedbackType="feedbackAllMask|feedbackGeneric|feedbackSpoken"
|
android:accessibilityFeedbackType="feedbackAllMask"
|
||||||
android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews"
|
android:accessibilityFlags="flagDefault|flagReportViewIds|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews"
|
||||||
android:canPerformGestures="true"
|
android:canPerformGestures="true"
|
||||||
android:canRetrieveWindowContent="true"
|
android:canRetrieveWindowContent="true"
|
||||||
android:description="@string/accessibility_service_description"
|
android:description="@string/accessibility_service_description"
|
||||||
|
|||||||
16
build.gradle
16
build.gradle
@@ -4,11 +4,13 @@ buildscript {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
// mavenCentral()
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
maven { url 'https://developer.huawei.com/repo/' }
|
maven { url 'https://developer.huawei.com/repo/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/central/' }
|
maven { url "https://maven.aliyun.com/repository/jcenter" }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/google' }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
classpath 'com.android.tools.build:gradle:3.6.4'
|
||||||
@@ -26,11 +28,13 @@ allprojects {
|
|||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
// mavenCentral()
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
maven { url 'https://developer.huawei.com/repo/' }
|
maven { url 'https://developer.huawei.com/repo/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/central/' }
|
maven { url "https://maven.aliyun.com/repository/jcenter" }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/google' }
|
||||||
}
|
}
|
||||||
gradle.projectsEvaluated {
|
gradle.projectsEvaluated {
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
|
|||||||
Reference in New Issue
Block a user