diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 23d2272..53552d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,7 @@ -2020-11-28 V1.0 -暂无。 \ No newline at end of file +#### 2020-12-18 V1.0.1 +- *.[新增]支持通过wifi名称来判断是否在上班。 +- *.[新增]增加游戏模式(尚未完成)。 +- *.[改进]不连公司wifi的情况下,个性化购物和淘口令声音。 + +#### 2020-11-28 V1.0 +- 暂无。 \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b6c4a6c..7ad2f64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.itrycn.tellmenotice" minSdkVersion 23 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.0.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b5ce804..13c3b87 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,24 +4,37 @@ + + + + + + - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/itrycn/ta/AccessibilityOpenHelperActivity.java b/app/src/main/java/com/itrycn/ta/AccessibilityOpenHelperActivity.java new file mode 100644 index 0000000..6d6793b --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/AccessibilityOpenHelperActivity.java @@ -0,0 +1,158 @@ +package com.itrycn.ta; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.widget.Toast; + +import com.itrycn.ta.utils.AccessibilityUtil; + +import java.util.Timer; +import java.util.TimerTask; + + +/** + * 辅助功能权限打开辅助activity,用于启动辅助功能设置页面 + */ +public class AccessibilityOpenHelperActivity extends Activity { + private boolean isFirstCome = true; + private static final String ACTION = "action"; + private static final String ACTION_FINISH_SELF = "action_finis_self"; + + private Timer timer; + private TimerTask timerTask; + private int mTimeoutCounter = 0; + + private int TIMEOUT_MAX_INTERVAL = 60 * 2; // 2 min + + private long TIMER_CHECK_INTERVAL = 1000; + protected static Handler mHandle = new Handler(); + protected static Runnable tipToastDelayRunnable; + + private static void removeDelayedToastTask() { + if (mHandle != null && tipToastDelayRunnable != null) { + mHandle.removeCallbacks(tipToastDelayRunnable); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //setContentView(R.layout.activity_accessibility_transparent_layout); + Intent intent = getIntent(); + if (intent != null && intent.getExtras() != null) { + String action = intent.getStringExtra(ACTION); + if (ACTION_FINISH_SELF.equals(action)) { + finishCurrentActivity(); + return; + } + } + mTimeoutCounter = 0; + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finishCurrentActivity(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (intent != null && intent.getExtras() != null) { + String action = intent.getStringExtra(ACTION); + if (ACTION_FINISH_SELF.equals(action)) { + finishCurrentActivity(); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + if (!isFirstCome) { + removeDelayedToastTask(); + finishCurrentActivity(); + } else { + jumpActivities(); + startCheckAccessibilityOpen(); + } + isFirstCome = false; + } + + private void jumpActivities() { + try { + Intent intent = AccessibilityUtil.getAccessibilitySettingPageIntent(this); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void onDestroy() { + freeTimeTask(); + super.onDestroy(); + } + + private void finishCurrentActivity() { + freeTimeTask(); + finish(); + } + + private void startCheckAccessibilityOpen() { + freeTimeTask(); + initTimeTask(); + timer.schedule(timerTask, 0, TIMER_CHECK_INTERVAL); + } + + private void initTimeTask() { + timer = new Timer(); + mTimeoutCounter = 0; + timerTask = new TimerTask() { + + @SuppressWarnings("static-access") + @Override + public void run() { + if (AccessibilityUtil.isAccessibilitySettingsOn(AccessibilityOpenHelperActivity.this)) { + freeTimeTask(); + Looper.prepare(); + try { + AccessibilityOpenHelperActivity.this.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(AccessibilityOpenHelperActivity.this, "辅助功能开启成功", Toast.LENGTH_SHORT).show(); + } + }); + Intent intent = new Intent(); + intent.putExtra(ACTION, ACTION_FINISH_SELF); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(AccessibilityOpenHelperActivity.this, AccessibilityOpenHelperActivity.this.getClass()); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + Looper.loop(); + } + // 超过2分钟超时,就释放timer。 + mTimeoutCounter++; + if (mTimeoutCounter > TIMEOUT_MAX_INTERVAL) { + freeTimeTask(); + } + } + }; + } + + private void freeTimeTask() { + if (timerTask != null) { + timerTask.cancel(); + timerTask = null; + } + if (timer != null) { + timer.cancel(); + timer = null; + } + } +} diff --git a/app/src/main/java/com/itrycn/ta/AccessibilityOperator.java b/app/src/main/java/com/itrycn/ta/AccessibilityOperator.java new file mode 100644 index 0000000..09d822f --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/AccessibilityOperator.java @@ -0,0 +1,601 @@ +package com.itrycn.ta; + +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.GestureDescription; +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.Path; +import android.graphics.Rect; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.Handler; +import android.provider.DocumentsContract; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.Size; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Toast; + +import androidx.core.content.FileProvider; + +import com.itrycn.ta.script.ScriptSystemInfo; +import com.itrycn.ta.utils.AccessibilityLog; + +import java.io.File; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +/** + * Created by popfisher on 2017/7/11. + */ + +@TargetApi(16) +public class AccessibilityOperator { + + private Context mContext; + private static AccessibilityOperator mInstance = new AccessibilityOperator(); + private AccessibilityEvent mAccessibilityEvent; + private AccessibilityService mAccessibilityService; + public Handler UIHandler; + public boolean IsExit=false; + private boolean result_bool=false; + public ScriptSystemInfo SystemInfo=ScriptSystemInfo.getInstance(); + private AccessibilityOperator() { + } + + public static AccessibilityOperator getInstance() { + return mInstance; + } + + public void init(Context context) { + mContext = context; + ScriptSystemInfo.getInstance().init(context); + } + + public void updateEvent(AccessibilityService service, AccessibilityEvent event) { + if (service != null && mAccessibilityService == null) { + mAccessibilityService = service; + } + if (event != null) { + mAccessibilityEvent = event; + } + } + + public boolean isServiceRunning() { + ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + List services = am.getRunningServices(Short.MAX_VALUE); + for (ActivityManager.RunningServiceInfo info : services) { + if (info.service.getClassName().equals("com.itryn.ta.AccessibilityTaService")) { + return true; + } + } + return false; + } + + private AccessibilityNodeInfo getRootNodeInfo() { + AccessibilityEvent curEvent = mAccessibilityEvent; + AccessibilityNodeInfo nodeInfo = null; + if (Build.VERSION.SDK_INT >= 16) { + // 建议使用getRootInActiveWindow,这样不依赖当前的事件类型 + if (mAccessibilityService != null) { + nodeInfo = mAccessibilityService.getRootInActiveWindow(); + if(nodeInfo==null) + { + Toast("无法获取当前界面内容1"); + } + //AccessibilityLog.printLog("nodeInfo: " + nodeInfo); + } + else{ + Toast("辅助服务开启失败,请重启软件"); + } + // 下面这个必须依赖当前的AccessibilityEvent +// nodeInfo = curEvent.getSource(); + } else { + nodeInfo = curEvent.getSource(); + if(nodeInfo==null) + { + Toast("无法获取当前界面内容2"); + } + } + return nodeInfo; + } + + /** + * 根据Text搜索所有符合条件的节点, 精确搜索方式 + */ + public List findNodesByText(String text) { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return FindByText(nodeInfo,text); + } + return null; + } + /** + * 根据Text搜索所有符合条件的节点, 精确搜索方式 + */ + public List findNodesByText(String[] text) { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return FindByText(nodeInfo,text); + } + return null; + } + /** + * 根据Text搜索所有符合条件的节点, 模糊搜索方式 + */ + public List findNodesByContainsText(String text) { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return FindByContainsText(nodeInfo,text); + } + return null; + } + /** + * 根据Text搜索所有符合条件的节点, 模糊搜索方式 + */ + public List findNodesByContainsText(String[] text) { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return FindByContainsText(nodeInfo,text); + } + return null; + } + /** + * 根据Text搜索所有符合条件的节点, 精确搜索方式 + */ + public List FindByText(AccessibilityNodeInfo info,String text) { + List list=new ArrayList(); + if (info.getChildCount() == 0 && info.getText()!=null) { + if(info.getText().toString().equals(text)) + { + list.add(info); + } + } else { + for (int i = 0; i < info.getChildCount(); i++) { + if(info.getChild(i)!=null){ + list.addAll(FindByText(info.getChild(i),text)); + } + } + } + return list; + } + /** + * 根据Text搜索所有符合条件的节点, 精确搜索方式 + */ + public List FindByText(AccessibilityNodeInfo info,String[] text) { + List list=new ArrayList(); + if (info.getChildCount() == 0 && info.getText()!=null) { + for (int k=0;k FindByContainsText(AccessibilityNodeInfo info,String[] text) { + List list=new ArrayList(); + if (info.getChildCount() == 0 && info.getText()!=null) { + for (int k=0;k FindByContainsText(AccessibilityNodeInfo info,String text) { + List list=new ArrayList(); + if (info.getChildCount() == 0 && info.getText()!=null) { + if(info.getText().toString().contains(text)) + { + list.add(info); + } + } else { + for (int i = 0; i < info.getChildCount(); i++) { + if(info.getChild(i)!=null){ + list.addAll(FindByContainsText(info.getChild(i),text)); + } + } + } + return list; + } + /** + * 获取当前页面上的所有控件信息 + */ + public List GetAllNodes() { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return GetAllNodes(nodeInfo); + } + return null; + } + /** + * 获取当前页面上的所有控件信息 + */ + public List GetAllNodes(AccessibilityNodeInfo info) { + List list=new ArrayList(); + if (info.getChildCount() == 0) { + list.add(info); + } else { + for (int i = 0; i < info.getChildCount(); i++) { + list.add(info); + if(info.getChild(i)!=null){ + list.addAll(GetAllNodes(info.getChild(i))); + } + } + } + return list; + } + /** + * 获取当前页面上的所有没有子控件的控件信息 + */ + public List GetAllNoChildsNodes() { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + return GetAllNoChildsNodes(nodeInfo); + } + return null; + } + /** + * 获取当前页面上的所有没有子控件的控件信息 + */ + public List GetAllNoChildsNodes(AccessibilityNodeInfo info) { + List list=new ArrayList(); + if (info.getChildCount() == 0) { + list.add(info); + } else { + for (int i = 0; i < info.getChildCount(); i++) { + if(info.getChild(i)!=null){ + list.addAll(GetAllNodes(info.getChild(i))); + } + } + } + return list; + } + /** + * 根据View的ID搜索符合条件的节点,精确搜索方式; + * 这个只适用于自己写的界面,因为ID可能重复 + * api要求18及以上 + * @param viewId + */ + public List findNodesById(String viewId) { + AccessibilityNodeInfo nodeInfo = getRootNodeInfo(); + if (nodeInfo != null) { + if (Build.VERSION.SDK_INT >= 18) { + return nodeInfo.findAccessibilityNodeInfosByViewId(viewId); + } + } + return null; + } + /** + * 按文本来点击 + * @param text + * @return 是否点击成功 + */ + public boolean clickByText(String text) { + return performClick(findNodesByText(text)); + } + /** + * 按文本来点击 + * @param text + * @return 是否点击成功 + */ + public boolean clickByText(String[] text) { + return performClick(findNodesByText(text)); + } + /** + * 按文本来点击,忽略黑名单中的控件 + * @param text + * @return 是否点击成功 + */ + public boolean clickByText(String[] text,Rect[] blackrect) { + runOnUiThread(new Runnable(){ + public void run(){ + List list=findNodesByText(text); + if(list==null) + { + //Toast("界面查找出错..."); + result_bool=false; + } + else { + for (int i = list.size() - 1; i >= 0; i--) { + AccessibilityNodeInfo node = list.get(i); + Rect rect = new Rect(); + node.getBoundsInScreen(rect); + for (int r = 0; r < blackrect.length; r++) { + if (isIntersect(rect, blackrect[r])) { + list.remove(i); + } + } + } + result_bool = performClick(list); + } + } + }); + + return result_bool; + } + private boolean isIntersect(Rect a, Rect b) { + return a.left <= b.right && b.left <= a.right && a.top <= b.bottom + && b.top <= a.bottom; + } + /** + * 根据View的ID搜索符合条件的节点,精确搜索方式; + * 这个只适用于自己写的界面,因为ID可能重复 + * api要求18及以上 + * @param viewId + * @return 是否点击成功 + */ + public boolean clickById(String viewId) { + return performClick(findNodesById(viewId)); + } + + public boolean performClick(List nodeInfos) { + if (nodeInfos != null && !nodeInfos.isEmpty()) { + AccessibilityNodeInfo node; + for (int i = 0; i < nodeInfos.size(); i++) { + node = nodeInfos.get(i); + // 获得点击View的类型 + AccessibilityLog.printLog("View类型:" + node.getClassName()); + // 进行模拟点击 + if (node.isEnabled()) { + return ClickByNode(node); + } + } + } + return false; + } + /** + * 从指定坐标1滑动到指定坐标2 + * @return 是否点击成功 + */ + public boolean Gesture(int x1,int y1,int x2,int y2,long duration){//仿滑动 + if(IsExit){return false;} + if(mAccessibilityService==null){Toast("辅助服务已失效"); return false;} + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + runOnUiThread(new Runnable(){ + public void run(){ + Path path = new Path(); + path.moveTo(x1, y1);//滑动起点 + path.lineTo(x2, y2);//滑动终点 + GestureDescription.Builder builder = new GestureDescription.Builder(); + GestureDescription description = builder.addStroke(new GestureDescription.StrokeDescription(path, 0, duration)).build(); + //100L 第一个是开始的时间,第二个是持续时间 + result_bool= mAccessibilityService.dispatchGesture(description, new MyCallBack(), null); + } + }); + return result_bool; + } + return false; + } + /** + * 从指定坐标1滑动到指定坐标2 + * @return 是否点击成功 + */ + public boolean Gesture(Path path,long startTime,long duration){//仿滑动 + if(IsExit){return false;} + if(mAccessibilityService==null){return false;} + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + GestureDescription.Builder builder = new GestureDescription.Builder(); + GestureDescription description = builder.addStroke(new GestureDescription.StrokeDescription(path, startTime, duration)).build(); + //100L 第一个是开始的时间,第二个是持续时间 + return mAccessibilityService.dispatchGesture(description, new MyCallBack(), null); + } + return false; + } + /** + * 获取控件矩形参数 + * @return 返回矩形 + */ + public Rect GetBounds(AccessibilityNodeInfo node){ + Rect rect = new Rect(); + if(node!=null) + { + node.getBoundsInScreen(rect); + } + return rect; + } + /** + * 点击指定控件 + * @return 是否点击成功 + */ + public boolean ClickByNode(AccessibilityNodeInfo node){//点击 + if(node!=null) + { + Rect rect = new Rect(); + node.getBoundsInScreen(rect); + int x=(rect.left+rect.right)/2; + int y = (rect.top + rect.bottom) / 2; + //设置随机位移,防止作弊被发现 + int width_d=RandomInt(0,((int)rect.width()/2)-2); + int height_d=RandomInt(0,((int)rect.height()/2)-2); + int add=RandomInt(0,1); + if(add==0) + { + x=x-width_d; + y=y-height_d; + } + else{ + x=x+width_d; + y=y+height_d; + } + return Click(x,y); + } + return false; + } + /** + * 生成随机数 + * @return + */ + public int RandomInt(int min,int max) + { + return (new Random()).nextInt((max - min) + 1) + min; + } + /** + * 生成随机数 + * @return + */ + public long RandomLong(long min,long max) + { + Random random = new Random(); + return ( long )random.nextDouble()*(max-min) + min; + } + /** + * 点击指定坐标 + * @return 是否点击成功 + */ + public boolean Click(int x,int y){//点击 + return Press(x,y,150); + } + + /** + * 长点击指定坐标 + * @return 是否点击成功 + */ + public boolean LongClick(int x,int y){//点击 + return Press(x,y,700); + } + /** + * 点击指定坐标 + * @return 是否点击成功 + */ + public boolean Press(int x,int y,long delay){//点击 + return Gesture(x,y,x,y,delay); + } + /** + * 运行app + * @return 是否成功 + */ + public boolean LaunchApp(String packageName) + { + if(IsExit){return false;} + Intent intent =mContext.getPackageManager().getLaunchIntentForPackage(packageName); + if (intent != null) { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + return true; + } + return false; + } + /** + * 安装应用 + * @param Path + */ + private void _InstallApk(String Path) { + + Uri uri; + File apkFile; + try { + apkFile = new File(Path); + if(!apkFile.exists()){return;} + Intent intentInstall = new Intent(Intent.ACTION_VIEW); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ + + Uri contentUri = FileProvider.getUriForFile(mContext, "com.rfid.application.MyApplication.provider", apkFile); + intentInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intentInstall.setDataAndType(contentUri, "application/vnd.android.package-archive"); + + }else{ + intentInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intentInstall.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); + + } + mContext.startActivity(intentInstall); + } + catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + /** + * 休眠多少毫秒 + */ + public void Sleep(long millis) { + Date date=new Date(); + long addtime= date.getTime()+millis; + while(addtime>=(new Date()).getTime() && !IsExit) { + try { + Thread.sleep(10); + } + catch (Exception e){e.printStackTrace();} + } + } + /** + * 休眠多少毫秒 + */ + public void Sleep(long millis_min,long millis_max) { + long R_millis=RandomLong(millis_min,millis_max); + Sleep(R_millis); + } + /** + *Toast提示 + */ + public void Toast(String text) + { + runOnUiThread(new Runnable(){ + public void run(){ + Toast.makeText(mContext.getApplicationContext(), text, Toast.LENGTH_SHORT).show(); + } + }); + } + public final void runOnUiThread(Runnable action) { + if(UIHandler==null) { + action.run(); + }else + { + UIHandler.post(action); + } + } + /** + *点击返回键 + */ + public boolean clickBackKey() { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); + } + + private boolean performGlobalAction(int action) { + if(IsExit){return false;} + if(mAccessibilityService==null){return false;} + runOnUiThread(new Runnable(){ + public void run(){ + result_bool= mAccessibilityService.performGlobalAction(action); + } + }); + return result_bool; + } +} diff --git a/app/src/main/java/com/itrycn/ta/AccessibilityTaService.java b/app/src/main/java/com/itrycn/ta/AccessibilityTaService.java new file mode 100644 index 0000000..d5ab85b --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/AccessibilityTaService.java @@ -0,0 +1,59 @@ +package com.itrycn.ta; + +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.TargetApi; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Toast; + +import com.itrycn.ta.utils.AccessibilityLog; +import com.itrycn.tellmenotice.NoticeService; + +/** + * Created by popfisher on 2017/7/6. + */ + +@TargetApi(25) +public class AccessibilityTaService extends AccessibilityService { + + @Override + protected void onServiceConnected() { + super.onServiceConnected(); + // 通过代码可以动态配置,但是可配置项少一点 +// AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(); +// accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPE_WINDOWS_CHANGED +// | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED +// | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED +// | AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED; +// accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK; +// accessibilityServiceInfo.notificationTimeout = 0; +// accessibilityServiceInfo.flags = AccessibilityServiceInfo.DEFAULT; +// setServiceInfo(accessibilityServiceInfo); + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + // 此方法是在主线程中回调过来的,所以消息是阻塞执行的 + // 获取包名 + if(event.getPackageName()==null) + { + //Toast.makeText(this, "获取不到包名", Toast.LENGTH_SHORT).show(); + return; + } + String pkgName = event.getPackageName().toString(); + int eventType = event.getEventType(); + AccessibilityOperator.getInstance().updateEvent(this, event); +// try { +// Thread.sleep(200); +// } catch (Exception e) {} + //Toast.makeText(this, "eventType: " + eventType + " pkgName: " + pkgName, Toast.LENGTH_SHORT).show(); + NoticeService.CurPackageName=pkgName; + AccessibilityLog.printLog("eventType: " + eventType + " pkgName: " + pkgName); + } + + @Override + public void onInterrupt() { + + } +} diff --git a/app/src/main/java/com/itrycn/ta/MyCallBack.java b/app/src/main/java/com/itrycn/ta/MyCallBack.java new file mode 100644 index 0000000..27a8b33 --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/MyCallBack.java @@ -0,0 +1,27 @@ +package com.itrycn.ta; + +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.GestureDescription; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +//模拟手势的监听 +@RequiresApi(api = Build.VERSION_CODES.N) +public class MyCallBack extends AccessibilityService.GestureResultCallback { + public MyCallBack() { + super(); + } + + @Override + public void onCompleted(GestureDescription gestureDescription) { + super.onCompleted(gestureDescription); + + } + + @Override + public void onCancelled(GestureDescription gestureDescription) { + super.onCancelled(gestureDescription); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/itrycn/ta/OpenAccessibilitySettingHelper.java b/app/src/main/java/com/itrycn/ta/OpenAccessibilitySettingHelper.java new file mode 100644 index 0000000..ad65ca5 --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/OpenAccessibilitySettingHelper.java @@ -0,0 +1,22 @@ +package com.itrycn.ta; + +import android.content.Context; +import android.content.Intent; + +/** + * Created by popfisher on 2017/7/6. + */ + +public class OpenAccessibilitySettingHelper { + private static final String ACTION = "action"; + private static final String ACTION_START_ACCESSIBILITY_SETTING = "action_start_accessibility_setting"; + + public static void jumpToSettingPage(Context context) { + try { + Intent intent = new Intent(context, AccessibilityOpenHelperActivity.class); + intent.putExtra(ACTION, ACTION_START_ACCESSIBILITY_SETTING); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } catch (Exception ignore) {} + } +} diff --git a/app/src/main/java/com/itrycn/ta/script/ScriptSystemInfo.java b/app/src/main/java/com/itrycn/ta/script/ScriptSystemInfo.java new file mode 100644 index 0000000..8444d6f --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/script/ScriptSystemInfo.java @@ -0,0 +1,158 @@ +package com.itrycn.ta.script; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.telephony.TelephonyManager; +import android.util.DisplayMetrics; +import android.util.Size; + +import com.itrycn.ta.AccessibilityOperator; + +public class ScriptSystemInfo { + private Context mContext; + private static ScriptSystemInfo mInstance = new ScriptSystemInfo(); + + private ScriptSystemInfo() { + } + + public static ScriptSystemInfo getInstance() { + return mInstance; + } + + public void init(Context context) { + mContext = context; + } + + /** + * 获取屏幕分辨率 + * + * @return 返回分辨率 + */ + public Size GetScreen() { + DisplayMetrics dm = new DisplayMetrics(); + dm = mContext.getResources().getDisplayMetrics(); + return new Size(dm.widthPixels, dm.heightPixels); + } + + /** + * 获取当前手机系统版本号 + * + * @return 系统版本号 + */ + public String getSystemVersion() { + return android.os.Build.VERSION.RELEASE; + } + + /** + * 获取手机型号 + * + * @return 手机型号 + */ + public String getSystemModel() { + return android.os.Build.MODEL; + } + + /** + * 获取手机厂商 + * + * @return 手机厂商 + */ + public String getDeviceBrand() { + return android.os.Build.BRAND; + } + + public int getVersion(String packageName) { + try { + PackageManager manager = mContext.getPackageManager(); + PackageInfo info = manager.getPackageInfo(packageName, 0); + return info.versionCode; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + /** + * 设置媒体音量 + * + * @return + */ + public void setMusicVolume(int value) + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, value, AudioManager.FLAG_PLAY_SOUND); + } + /** + * 获取媒体音量 + * + * @return + */ + public int getMusicVolume() + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + } + /** + * 设置闹钟音量 + * + * @return + */ + public void setAlarmVolume(int value) + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + audioManager.setStreamVolume(AudioManager.STREAM_ALARM, value, AudioManager.FLAG_PLAY_SOUND); + } + /** + * 获取闹钟音量 + * + * @return + */ + public int getAlarmVolume() + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + return audioManager.getStreamVolume(AudioManager.STREAM_ALARM); + } + /** + * 设置通知音量 + * + * @return + */ + public void setNotificationVolume(int value) + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, value, AudioManager.FLAG_PLAY_SOUND); + } + /** + * 获取通知音量 + * + * @return + */ + public int getNotificationVolume() + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + return audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION); + } + /** + * 设置电话铃声音量 + * + * @return + */ + public void setRingVolume(int value) + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + audioManager.setStreamVolume(AudioManager.STREAM_RING, value, AudioManager.FLAG_PLAY_SOUND); + } + /** + * 获取电话铃声音量 + * + * @return + */ + public int getRingVolume() + { + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + return audioManager.getStreamVolume(AudioManager.STREAM_RING); + } +} diff --git a/app/src/main/java/com/itrycn/ta/utils/AccessibilityLog.java b/app/src/main/java/com/itrycn/ta/utils/AccessibilityLog.java new file mode 100644 index 0000000..6d3fc4d --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/utils/AccessibilityLog.java @@ -0,0 +1,15 @@ +package com.itrycn.ta.utils; +import android.util.Log; + +/** + * Created by popfisher on 2017/7/11. + */ + +public class AccessibilityLog { + + private static final String TAG = "AccessibilityService"; + public static void printLog(String logMsg) { + //if (!BuildConfig.DEBUG) return; + //Log.d(TAG, logMsg); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/itrycn/ta/utils/AccessibilityUtil.java b/app/src/main/java/com/itrycn/ta/utils/AccessibilityUtil.java new file mode 100644 index 0000000..77fb231 --- /dev/null +++ b/app/src/main/java/com/itrycn/ta/utils/AccessibilityUtil.java @@ -0,0 +1,59 @@ +package com.itrycn.ta.utils; + +import android.content.Context; +import android.content.Intent; +import android.provider.Settings; +import android.text.TextUtils; + +import com.itrycn.ta.AccessibilityTaService; + +/** + * 辅助功能相关检查的帮助类 + */ +public class AccessibilityUtil { + private static final String ACCESSIBILITY_SERVICE_PATH = AccessibilityTaService.class.getCanonicalName(); + /** + * 判断是否有辅助功能权限 + * + * @param context + * @return + */ + public static boolean isAccessibilitySettingsOn(Context context) { + if (context == null) { + return false; + } + + int accessibilityEnabled = 0; + try { + accessibilityEnabled = Settings.Secure.getInt(context.getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED); + } catch (Settings.SettingNotFoundException e) { + e.printStackTrace(); + } + + String packageName = context.getPackageName(); + final String serviceStr = packageName + "/" + ACCESSIBILITY_SERVICE_PATH; + AccessibilityLog.printLog("serviceStr: " + serviceStr); + if (accessibilityEnabled == 1) { + TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':'); + + String settingValue = Settings.Secure.getString(context.getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); + if (settingValue != null) { + TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(settingValue); + while (splitter.hasNext()) { + String accessabilityService = splitter.next(); + + if (accessabilityService.equalsIgnoreCase(serviceStr)) { + return true; + } + } + } + } + return false; + } + + public static Intent getAccessibilitySettingPageIntent(Context context) { + // 一些品牌的手机可能不是这个Intent,需要适配 + return new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + } +} diff --git a/app/src/main/java/com/itrycn/tellmenotice/MainActivity.java b/app/src/main/java/com/itrycn/tellmenotice/MainActivity.java index 3c35db3..db7eb43 100644 --- a/app/src/main/java/com/itrycn/tellmenotice/MainActivity.java +++ b/app/src/main/java/com/itrycn/tellmenotice/MainActivity.java @@ -11,14 +11,20 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; -import android.view.View; import android.widget.TextView; import android.widget.Toast; +import com.itrycn.ta.AccessibilityOperator; +import com.itrycn.ta.OpenAccessibilitySettingHelper; + import java.util.Calendar; public class MainActivity extends AppCompatActivity { ScreenListener screenlistener; + /** + * + */ + public static Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -27,6 +33,12 @@ public class MainActivity extends AppCompatActivity { { gotoNotificationAccessSetting(MainActivity.this); } + AccessibilityOperator.getInstance().init(this); + OpenAccessibilitySettingHelper.jumpToSettingPage(this); + if (!Settings.canDrawOverlays(this)) { + Toast.makeText(this,"请授权app的悬浮框权限", Toast.LENGTH_SHORT).show(); + startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0); + } Intent intent2 = new Intent(MainActivity.this,NoticeService.class); startService(intent2); startFloatingButtonService(); @@ -57,9 +69,9 @@ public class MainActivity extends AppCompatActivity { AudioManager audioManager = (AudioManager) MainActivity.this.getSystemService(Context.AUDIO_SERVICE); int NoticeVolume= audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION); int NoticeMaxVolume= audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION); - if(NoticeVolume= Build.VERSION_CODES.O) { @@ -86,6 +98,8 @@ public class NoticeService extends NotificationListenerService { sp.unload(MP3_Ring); sp.unload(MP3_kuaidi); sp.unload(MP3_Dingding); + sp.unload(MP3_TaoCode); + sp.unload(MP3_Buy0); super.onDestroy(); } @Override @@ -101,6 +115,8 @@ public class NoticeService extends NotificationListenerService { int MP3_Ring; int MP3_kuaidi; int MP3_Dingding; + int MP3_TaoCode; + int MP3_Buy0; String Last_packageName=""; String Last_Title=""; String Last_Content=""; @@ -125,7 +141,33 @@ public class NoticeService extends NotificationListenerService { if(hour>=23 || hour<7) {return; } //23点到早上7点,免打扰时间段 //if(hour>=23 && hour<7) {return; } } + AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE); + int NoticeVolume= audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION); + int NoticeMaxVolume= audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION); + audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, 100, AudioManager.FLAG_VIBRATE); sp.play(SoundId, 1f, 1.0f,1,loop,1); + //audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, NoticeVolume, AudioManager.FLAG_VIBRATE); + } + //在进程中去寻找当前APP的信息,判断是否在前台运行 + private boolean isAppOnForeground(String packageName) { + return NoticeService.CurPackageName.equals(packageName); + } + private boolean IsGameMode() + { + if(isAppOnForeground("com.tencent.tmgp.sgame")) + { + return true; + } + return false; + } + /** + * 获取wifi名称(必须要有GPS定位权限) + */ + private String getWifiName() + { + WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + return wifiInfo.getSSID(); } private long LastDoorRingTime=0; @Override @@ -169,8 +211,10 @@ public class NoticeService extends NotificationListenerService { for (int i = 0; i < strArr.length; ++i){ if(Content.contains(strArr[i])) { - FloatView fv=new FloatView(this); - fv.showFloatingWindow(notice,Title,Content); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Title, Content); + } //showFloatingWindow(notice,Title,Content); PlaySound(MP3_mm,0,false); haveInfo=true; @@ -179,22 +223,52 @@ public class NoticeService extends NotificationListenerService { } } //endregion + //region 0元购 if(!haveInfo) { if(Title.contains("球球") || Content.contains("球球")) { String[] strArr2 = "球球独家;口令;拍下;http;拍第;体验;福利;一单;元抢;内部;复制打开;漏洞;好评;0元;抢到;免单;独家".split(";"); for (int i = 0; i < strArr2.length; ++i) { if (Content.contains(strArr2[i])) { - FloatView fv = new FloatView(this); - fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#FF0000")); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#FF0000")); + } //showFloatingWindow(notice,Title,Content); - PlaySound(MP3_Dingding, 0, false); + int hour = c.get(Calendar.HOUR_OF_DAY); // 时 + if(getWifiName().indexOf("当游")<0) { + PlaySound(MP3_Buy0, 0, false); + } + else { + PlaySound(MP3_Dingding, 0, false); + } haveTip=true; break; } } } } + //endregion + //region 淘口令 + if(!haveInfo) + { + String[] strArr2 = "tb.cn;淘tao;/宝;".split(";"); + for (int i = 0; i < strArr2.length; ++i) { + if (Content.contains(strArr2[i])) { + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#FF0000")); + } + int hour = c.get(Calendar.HOUR_OF_DAY); // 时 + if(getWifiName().indexOf("当游")<0) { + PlaySound(MP3_TaoCode, 0, false); + } + haveTip=true; + break; + } + } + } + //endregion } else if(packageName.equals("com.xiaomi.smarthome")) //如果是米家app { @@ -204,24 +278,25 @@ public class NoticeService extends NotificationListenerService { { if(LastDoorRingTime+60000>=NowTime){return;} //如果1分钟内有新的门铃提醒,则自动忽略 LastDoorRingTime=c.getTime().getTime(); - FloatView fv=new FloatView(this); - fv.showFloatingWindow(notice,Content,Title, Color.parseColor("#02BD9D")); - PlaySound(MP3_Ring,2,false); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Content, Title, Color.parseColor("#02BD9D")); + } + PlaySound(MP3_Ring,1,false); haveTip=true; } else { - FloatView fv=new FloatView(this); - if(Title.equals("自动化通知")) - { - fv.showFloatingWindow(notice,Title, Content, Color.parseColor("#02BD9D")); - } - else { - if(Title.length()>=Content.length()) { - fv.showFloatingWindow(notice, Content, Title, Color.parseColor("#02BD9D")); - } - else { - fv.showFloatingWindow(notice,Title, Content, Color.parseColor("#02BD9D")); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + if (Title.equals("自动化通知")) { + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#02BD9D")); + } else { + if (Title.length() >= Content.length()) { + fv.showFloatingWindow(notice, Content, Title, Color.parseColor("#02BD9D")); + } else { + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#02BD9D")); + } } } haveTip=true; @@ -236,8 +311,10 @@ public class NoticeService extends NotificationListenerService { for (int i = 0; i < strArr.length; ++i){ if(Title.contains(strArr[i]) || Content.contains(strArr[i])) { - FloatView fv=new FloatView(this); - fv.showFloatingWindow(notice,Title,Content); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Title, Content); + } PlaySound(MP3_kuaidi,0,false); haveTip=true; break; @@ -252,26 +329,22 @@ public class NoticeService extends NotificationListenerService { if(Title.contains("正在运行")){return;} if(Title.contains("哈啰顺风车运行中") || Content.contains("哈啰顺风车运行中")){return;} if(Title.contains("顺风车出行中") || Content.contains("顺风车出行中")){return;} - //region 如果是顺风车线路 - FloatView fv=new FloatView(this); - if(packageName.equals("com.jingyao.easybike")) - { - fv.showFloatingWindow(notice,Title, Content, Color.parseColor("#0391FF")); + if(!IsGameMode()) { + //region 如果是顺风车线路 + FloatView fv = new FloatView(this); + if (packageName.equals("com.jingyao.easybike")) { + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#0391FF")); + } else if (packageName.equals("com.sdu.didi.psnger")) { + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#F8934C")); + } else if (packageName.equals("com.didapinche.booking")) { + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#FED051")); + } else { + fv.showFloatingWindow(notice, Title, Content); + } + haveTip = true; + PlaySound(MP3_Dingding, 0, false); + //endregion } - else if(packageName.equals("com.sdu.didi.psnger")) - { - fv.showFloatingWindow(notice,Title, Content, Color.parseColor("#F8934C")); - } - else if(packageName.equals("com.didapinche.booking")) - { - fv.showFloatingWindow(notice,Title, Content, Color.parseColor("#FED051")); - } - else { - fv.showFloatingWindow(notice, Title, Content); - } - haveTip=true; - PlaySound(MP3_Dingding,0,false); - //endregion } else if(packageName.equals("com.taobao.taobao") || packageName.equals("com.jingdong.app.mall") @@ -282,8 +355,10 @@ public class NoticeService extends NotificationListenerService { for (int i = 0; i < strArr.length; ++i){ if(Title.contains(strArr[i]) || Content.contains(strArr[i])) { - FloatView fv=new FloatView(this); - fv.showFloatingWindow(notice,Title,Content, Color.parseColor("#FD5C02")); + if(!IsGameMode()) { + FloatView fv = new FloatView(this); + fv.showFloatingWindow(notice, Title, Content, Color.parseColor("#FD5C02")); + } PlaySound(MP3_Dingding,0,false); haveTip=true; break; diff --git a/app/src/main/res/raw/buy0.mp3 b/app/src/main/res/raw/buy0.mp3 new file mode 100644 index 0000000..8d6d516 Binary files /dev/null and b/app/src/main/res/raw/buy0.mp3 differ diff --git a/app/src/main/res/raw/taocode.mp3 b/app/src/main/res/raw/taocode.mp3 new file mode 100644 index 0000000..c472c20 Binary files /dev/null and b/app/src/main/res/raw/taocode.mp3 differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8c73c3c..60af9f1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,6 @@ 智能管家 睿元智能管家,你的私人管家。\n1.可以帮你监控系统通知,自动筛选对你有用的内容。\n2.不同通知展现不同的提醒界面和声音。 + Ta辅助 + 开启辅助功能,让你的手机更智能一点 \ No newline at end of file diff --git a/app/src/main/res/xml/accessibility_config.xml b/app/src/main/res/xml/accessibility_config.xml new file mode 100644 index 0000000..f307cb3 --- /dev/null +++ b/app/src/main/res/xml/accessibility_config.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file