diff --git a/README.md b/README.md index d428146..240d9ca 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,9 @@ V免签为完全开源项目,开源项目意味着作者没有任何收入来 + 微信收款商业版店员到账收款通知 ## 更新记录 + + v1.7(2019.05.17) + + 删除辅助功能依赖,改为使用通知使用权进行监听,修复一大堆bug,建议更新到该版本 + + v1.6.2(2019.05.17) + 增加微信收款商业版到账支持 diff --git a/app/app-release.apk b/app/app-release.apk index 91f1314..cdeffbf 100644 Binary files a/app/app-release.apk and b/app/app-release.apk differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 290dc29..7e35af6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,6 @@ - - - - - - { - - private int code; - private String msg; - private V data; - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public V getData() { - return data; - } - - public void setData(V data) { - this.data = data; - } -} diff --git a/app/src/main/java/com/vone/vmq/MainActivity.java b/app/src/main/java/com/vone/vmq/MainActivity.java index 126fae2..2c695be 100644 --- a/app/src/main/java/com/vone/vmq/MainActivity.java +++ b/app/src/main/java/com/vone/vmq/MainActivity.java @@ -47,18 +47,16 @@ import okhttp3.Response; public class MainActivity extends AppCompatActivity{ - Button btnQrCode; - Button btnStart; - Button btnInput; - TextView txthost; // 结果 - TextView txtkey; // 结果 - boolean isOk = false; - public static String TAG = "MainActivity"; + private TextView txthost; + private TextView txtkey; - public static String host; - public static String key; + private boolean isOk = false; + private static String TAG = "MainActivity"; + + private static String host; + private static String key; int id = 0; @@ -68,28 +66,19 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - //初始化界面 - btnQrCode = (Button) findViewById(R.id.btn_qrcode);//扫码配置 - btnInput = (Button) findViewById(R.id.btn_input);//手动配置 - btnStart = (Button) findViewById(R.id.btn_start);//开启服务 txthost = (TextView) findViewById(R.id.txt_host); txtkey = (TextView) findViewById(R.id.txt_key); - //检测服务是否在线 - if(isAccessibilitySettingsOn(this)){ - btnStart.setText("检测服务状态"); - } + //检测通知使用权是否启用 if (!isNotificationListenersEnabled()) { + //跳转到通知使用权页面 gotoNotificationAccessSetting(); } - -// if (!isNotificationListenerServiceEnabled(this)){ -// -// } + //重启监听服务 toggleNotificationListenerService(this); @@ -108,6 +97,9 @@ protected void onCreate(Bundle savedInstanceState) { } + + + //扫码配置 public void startQrCode(View v) { // 申请相机权限 @@ -146,20 +138,15 @@ public void onClick(DialogInterface dialog, int which) { String t = String.valueOf(new Date().getTime()); String sign = md5(t+tmp[1]); - //1.创建OkHttpClient对象 + OkHttpClient okHttpClient = new OkHttpClient(); - //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。 Request request = new Request.Builder().url("http://"+tmp[0]+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); - //3.创建一个call对象,参数就是Request请求对象 Call call = okHttpClient.newCall(request); - //4.请求加入调度,重写回调方法 call.enqueue(new Callback() { - //请求失败执行的方法 @Override public void onFailure(Call call, IOException e) { } - //请求成功执行的方法 @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "onResponse: "+response.body().string()); @@ -178,12 +165,9 @@ public void onResponse(Call call, Response response) throws IOException { host = tmp[0]; key = tmp[1]; - //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作 SharedPreferences.Editor editor = getSharedPreferences("vone", MODE_PRIVATE).edit(); - //步骤2-2:将获取过来的值放入文件 editor.putString("host", host); editor.putString("key", key); - //步骤3:提交 editor.commit(); } @@ -191,143 +175,37 @@ public void onResponse(Call call, Response response) throws IOException { builder.show(); } - //启动服务 + //检测心跳 public void doStart(View view) { if (isOk==false){ Toast.makeText(MainActivity.this, "请您先配置!", Toast.LENGTH_SHORT).show(); return; } - if (!isAccessibilitySettingsOn(this)) { - Toast.makeText(MainActivity.this, "辅助功能未开启,请您前往开启!", Toast.LENGTH_SHORT).show(); - Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); - startActivity(intent); - return; - } - -// if(!notificationListenerEnable()){ -// Toast.makeText(MainActivity.this, "通知使用权权限未授予,请您前往授权!", Toast.LENGTH_SHORT).show(); -// gotoNotificationAccessSetting(this); -// return; -// } - - if (btnStart.getText().equals("开启服务")){ - btnStart.setText("检测服务状态"); - Toast.makeText(MainActivity.this, "开启成功!", Toast.LENGTH_SHORT).show(); - }else{ - - String t = String.valueOf(new Date().getTime()); - String sign = md5(t+key); - - //1.创建OkHttpClient对象 - OkHttpClient okHttpClient = new OkHttpClient(); - //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。 - Request request = new Request.Builder().url("http://"+host+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); - //3.创建一个call对象,参数就是Request请求对象 - Call call = okHttpClient.newCall(request); - //4.请求加入调度,重写回调方法 - call.enqueue(new Callback() { - //请求失败执行的方法 - @Override - public void onFailure(Call call, IOException e) { - Looper.prepare(); - Toast.makeText(MainActivity.this, "心跳状态错误,请检查配置是否正确!", Toast.LENGTH_SHORT).show(); - Looper.loop(); - } - //请求成功执行的方法 - @Override - public void onResponse(Call call, Response response) throws IOException { - //Log.d(TAG, "onResponse heard: "+response.body().string()); - Looper.prepare(); - Toast.makeText(MainActivity.this, "程序运行正常,心跳返回:"+response.body().string(), Toast.LENGTH_LONG).show(); - Looper.loop(); - } - }); - - - - } - } + String t = String.valueOf(new Date().getTime()); + String sign = md5(t+key); - private boolean isAccessibilitySettingsOn(Context mContext) { - int accessibilityEnabled = 0; - // TestService为对应的服务 - final String service = getPackageName() + "/" + NeNotificationService.class.getCanonicalName(); - Log.i(TAG, "service:" + service); - // com.z.buildingaccessibilityservices/android.accessibilityservice.AccessibilityService - try { - accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(), - android.provider.Settings.Secure.ACCESSIBILITY_ENABLED); - Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled); - } catch (Settings.SettingNotFoundException e) { - Log.e(TAG, "Error finding setting, default accessibility to not found: " + e.getMessage()); - } - TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':'); - - if (accessibilityEnabled == 1) { - Log.v(TAG, "***ACCESSIBILITY IS ENABLED*** -----------------"); - String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); - // com.z.buildingaccessibilityservices/com.z.buildingaccessibilityservices.TestService - if (settingValue != null) { - mStringColonSplitter.setString(settingValue); - while (mStringColonSplitter.hasNext()) { - String accessibilityService = mStringColonSplitter.next(); - - Log.v(TAG, "-------------- > accessibilityService :: " + accessibilityService + " " + service); - if (accessibilityService.equalsIgnoreCase(service)) { - Log.v(TAG, "We've found the correct setting - accessibility is switched on!"); - return true; - } - } + OkHttpClient okHttpClient = new OkHttpClient(); + Request request = new Request.Builder().url("http://"+host+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); + Call call = okHttpClient.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + Looper.prepare(); + Toast.makeText(MainActivity.this, "心跳状态错误,请检查配置是否正确!", Toast.LENGTH_SHORT).show(); + Looper.loop(); } - } else { - Log.v(TAG, "***ACCESSIBILITY IS DISABLED***"); - } - return false; - } - - - private boolean notificationListenerEnable() { - boolean enable = false; - String packageName = getPackageName(); - String flat= Settings.Secure.getString(getContentResolver(),"enabled_notification_listeners"); - if (flat != null) { - enable= flat.contains(packageName); - } - return enable; - } - private boolean gotoNotificationAccessSetting(Context context) { - try { - Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - return true; - } catch(ActivityNotFoundException e) { - try { - Intent intent = new Intent(); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - ComponentName cn = new ComponentName("com.android.settings","com.android.settings.Settings$NotificationAccessSettingsActivity"); - intent.setComponent(cn); - intent.putExtra(":settings:show_fragment", "NotificationAccessSettings"); - context.startActivity(intent); - return true; - } catch(Exception ex) { - ex.printStackTrace(); + @Override + public void onResponse(Call call, Response response) throws IOException { + Looper.prepare(); + Toast.makeText(MainActivity.this, "心跳返回:"+response.body().string(), Toast.LENGTH_LONG).show(); + Looper.loop(); } - return false; - } + }); } - - - - + //检测监听 public void checkPush(View v){ -// if (!btnStart.getText().equals("检测服务状态")){ -// Toast.makeText(MainActivity.this, "请先开启服务!", Toast.LENGTH_SHORT).show(); -// return; -// } Notification mNotification; NotificationManager mNotificationManager; @@ -335,41 +213,27 @@ public void checkPush(View v){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - //ChannelId为"1",ChannelName为"Channel1" NotificationChannel channel = new NotificationChannel("1", "Channel1", NotificationManager.IMPORTANCE_DEFAULT); - channel.enableLights(true); //是否在桌面icon右上角展示小红点 - channel.setLightColor(Color.GREEN); //小红点颜色 - channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知 + channel.enableLights(true); + channel.setLightColor(Color.GREEN); + channel.setShowBadge(true); mNotificationManager.createNotificationChannel(channel); - Notification.Builder builder = new Notification.Builder(this,"1"); //与channelId对应 + Notification.Builder builder = new Notification.Builder(this,"1"); mNotification = builder - // 设置小图标 .setSmallIcon(R.mipmap.ic_launcher) .setTicker("这是一条测试推送信息,如果程序正常,则会提示监听权限正常") - // 设置标题 .setContentTitle("V免签测试推送") - // 设置内容 .setContentText("这是一条测试推送信息,如果程序正常,则会提示监听权限正常") .build(); }else{ mNotification = new Notification.Builder(MainActivity.this) - // 设置小图标 .setSmallIcon(R.mipmap.ic_launcher) .setTicker("这是一条测试推送信息,如果程序正常,则会提示监听权限正常") - // 设置标题 .setContentTitle("V免签测试推送") - // 设置内容 .setContentText("这是一条测试推送信息,如果程序正常,则会提示监听权限正常") - - // 设置Notification提示铃声为系统默认铃声 - .setSound( - RingtoneManager.getActualDefaultRingtoneUri( - getBaseContext(), - RingtoneManager.TYPE_NOTIFICATION)) - .build(); } @@ -381,14 +245,12 @@ public void checkPush(View v){ } - private static boolean isNotificationListenerServiceEnabled(Context context) { - Set packageNames = NotificationManagerCompat.getEnabledListenerPackages(context); - if (packageNames.contains(context.getPackageName())) { - return true; - } - return false; - } + + + + + //各种权限的判断 private void toggleNotificationListenerService(Context context) { PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(new ComponentName(context, NeNotificationService2.class), @@ -399,33 +261,6 @@ private void toggleNotificationListenerService(Context context) { Toast.makeText(MainActivity.this, "监听服务启动中...", Toast.LENGTH_SHORT).show(); } - - - - - public static String md5(String string) { - if (TextUtils.isEmpty(string)) { - return ""; - } - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - byte[] bytes = md5.digest(string.getBytes()); - String result = ""; - for (byte b : bytes) { - String temp = Integer.toHexString(b & 0xff); - if (temp.length() == 1) { - temp = "0" + temp; - } - result += temp; - } - return result; - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return ""; - } - public boolean isNotificationListenersEnabled() { String pkgName = getPackageName(); final String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners"); @@ -468,6 +303,32 @@ protected boolean gotoNotificationAccessSetting() { } + + public static String md5(String string) { + if (TextUtils.isEmpty(string)) { + return ""; + } + MessageDigest md5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + byte[] bytes = md5.digest(string.getBytes()); + String result = ""; + for (byte b : bytes) { + String temp = Integer.toHexString(b & 0xff); + if (temp.length() == 1) { + temp = "0" + temp; + } + result += temp; + } + return result; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return ""; + } + + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -485,20 +346,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { String t = String.valueOf(new Date().getTime()); String sign = md5(t+tmp[1]); - //1.创建OkHttpClient对象 + OkHttpClient okHttpClient = new OkHttpClient(); - //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。 Request request = new Request.Builder().url("http://"+tmp[0]+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); - //3.创建一个call对象,参数就是Request请求对象 Call call = okHttpClient.newCall(request); - //4.请求加入调度,重写回调方法 call.enqueue(new Callback() { - //请求失败执行的方法 @Override public void onFailure(Call call, IOException e) { } - //请求成功执行的方法 @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "onResponse: "+response.body().string()); @@ -506,23 +362,20 @@ public void onResponse(Call call, Response response) throws IOException { } }); + //将扫描出的信息显示出来 txthost.setText(" 通知地址:"+tmp[0]); txtkey.setText(" 通讯密钥:"+tmp[1]); host = tmp[0]; key = tmp[1]; - //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作 SharedPreferences.Editor editor = getSharedPreferences("vone", MODE_PRIVATE).edit(); - //步骤2-2:将获取过来的值放入文件 editor.putString("host", host); editor.putString("key", key); - //步骤3:提交 editor.commit(); } } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); diff --git a/app/src/main/java/com/vone/vmq/MyData.java b/app/src/main/java/com/vone/vmq/MyData.java deleted file mode 100644 index 29c816d..0000000 --- a/app/src/main/java/com/vone/vmq/MyData.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.vone.vmq; - -import android.app.Application; - -public class MyData extends Application { - private String host; - private String key; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } -} diff --git a/app/src/main/java/com/vone/vmq/NeNotificationService.java b/app/src/main/java/com/vone/vmq/NeNotificationService.java deleted file mode 100644 index 10875b5..0000000 --- a/app/src/main/java/com/vone/vmq/NeNotificationService.java +++ /dev/null @@ -1,336 +0,0 @@ -package com.vone.vmq; - -import android.accessibilityservice.AccessibilityService; -import android.accessibilityservice.AccessibilityServiceInfo; -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Handler; -import android.os.Looper; -import android.os.PowerManager; -import android.text.TextUtils; -import android.util.Log; -import android.view.accessibility.AccessibilityEvent; -import android.widget.Toast; - -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Date; -import java.util.List; - -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -public class NeNotificationService extends AccessibilityService { - - public static String TAG = "NeNotificationService"; - - private String host = ""; - private String key = ""; - - private Thread newThread = null; //心跳线程 - - PowerManager.WakeLock mWakeLock = null; - - //申请设备电源锁 - @SuppressLint("InvalidWakeLockTag") - public void acquireWakeLock(Context context) - { - if (null == mWakeLock) - { - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "WakeLock"); - if (null != mWakeLock) - { - mWakeLock.acquire(); - } - } - } - //释放设备电源锁 - public void releaseWakeLock() - { - if (null != mWakeLock) - { - mWakeLock.release(); - mWakeLock = null; - } - } - - - - @Override - public void onAccessibilityEvent(AccessibilityEvent event) { - Log.d(TAG, "onAccessibilityEvent: "+event); - - if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) { - Log.d(TAG, "onAccessibilityEvent: 监控到新的推送"); - //应用包名:com.eg.android.AlipayGphone 推送内容: [vone通过扫码向你付款0.01元] //支付宝 - //应用包名:com.tencent.mm 推送内容: [微信支付: 微信支付收款0.01元(朋友到店)] //微信 - - Log.d(TAG,"onAccessibilityEvent: 应用包名:" + event.getPackageName()); - Log.d(TAG,"onAccessibilityEvent: 推送内容:" + event.getText()); - - /* - - List texts = event.getText(); - - if (event.getPackageName().equals("com.eg.android.AlipayGphone")){ - if (!texts.isEmpty()) { - for (CharSequence ctext : texts) { - String text = ctext.toString(); - if (text!=null){ - if (text.indexOf(":")==-1){ - if (text.indexOf("通过扫码向你付款")!=-1){ - String money = getSubString(text,"通过扫码向你付款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 "+money); - appPush(2,Double.valueOf(money)); - - }else if (text.indexOf("成功收款")!=-1){ - String money = getSubString(text,"成功收款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 "+money); - appPush(2,Double.valueOf(money)); - - } - } - } - } - } - - - - }else if(event.getPackageName().equals("com.tencent.mm")){ - if (!texts.isEmpty()) { - for (CharSequence ctext : texts) { - String text = ctext.toString(); - if (text!=null){ - //微信支付: 微信支付收款0.01元(朋友到店) - String[] tmp = text.split(":"); - if (tmp.length==2){ - if (tmp[0].equals("微信支付") || tmp[0].equals("微信收款助手") ){ - if (text.indexOf("微信支付收款")!=-1){ - String money = getSubString(text,"微信支付收款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信 到账 "+money); - appPush(1,Double.valueOf(money)); - }else if (text.indexOf("店员消息")!=-1){ - - String money = getSubString(text,"[店员消息]收款到账","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信店员 到账 "+money); - - appPush(1,Double.valueOf(money)); - } - } - } - } - } - } - - }else if(event.getPackageName().equals("com.vone.qrcode")){ - //测试推送 - if (!texts.isEmpty()) { - for (CharSequence ctext : texts) { - String text = ctext.toString(); - if (text.equals("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")){ - Handler handlerThree=new Handler(Looper.getMainLooper()); - handlerThree.post(new Runnable(){ - public void run(){ - Toast.makeText(getApplicationContext() ,"监听权限正常!",Toast.LENGTH_SHORT).show(); - } - }); - } - } - } - } - */ - - } - - } - - - @Override - protected void onServiceConnected() { - //设置监听配置 - AccessibilityServiceInfo info = new AccessibilityServiceInfo(); - info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED | - AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | - AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED; - info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; - - info.notificationTimeout = 10; - setServiceInfo(info); - - //读入保存的配置数据并显示 - SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE); - host = read.getString("host", ""); - key = read.getString("key", ""); - - - //开启心跳线程 - initAppHeart(); - - - Handler handlerThree = new Handler(Looper.getMainLooper()); - handlerThree.post(new Runnable(){ - public void run(){ - Toast.makeText(getApplicationContext() ,"监听服务开启成功!",Toast.LENGTH_LONG).show(); - } - }); - - } - - @Override - public void onInterrupt() { - Log.d("", "onInterrupt"); - - } - - - - public void initAppHeart(){ - Log.d(TAG, "run: init"); - if (newThread!=null){ - return; - } - acquireWakeLock(this); - newThread = new Thread(new Runnable() { - @Override - public void run() { - Log.d(TAG, "run: 123123"); - while (true){ - //这里写入子线程需要做的工作 - String t = String.valueOf(new Date().getTime()); - String sign = md5(t+key); - - - OkHttpClient okHttpClient = new OkHttpClient(); - Request request = new Request.Builder().url("http://"+host+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); - Call call = okHttpClient.newCall(request); - call.enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - final String error = e.getMessage(); - Handler handlerThree=new Handler(Looper.getMainLooper()); - handlerThree.post(new Runnable(){ - public void run(){ - Toast.makeText(getApplicationContext() ,"心跳状态错误,请检查配置是否正确!"+error,Toast.LENGTH_LONG).show(); - } - }); - } - //请求成功执行的方法 - @Override - public void onResponse(Call call, Response response) throws IOException { - Log.d(TAG, "onResponse heard: "+response.body().string()); - } - }); - try { - Thread.sleep(30*1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - } - }); - - newThread.start(); //启动线程 - } - - - public void appPush(int type,double price){ - //步骤1:创建一个SharedPreferences接口对象 - SharedPreferences read = getSharedPreferences("vone", MODE_WORLD_READABLE); - //步骤2:获取文件中的值 - host = read.getString("host", ""); - key = read.getString("key", ""); - - Log.d(TAG, "onResponse push: 开始:"+type+" "+price); - - String t = String.valueOf(new Date().getTime()); - String sign = md5(type+""+ price + t + key); - String url = "http://"+host+"/appPush?t="+t+"&type="+type+"&price="+price+"&sign="+sign; - Log.d(TAG, "onResponse push: 开始:"+url); - - //1.创建OkHttpClient对象 - OkHttpClient okHttpClient = new OkHttpClient(); - //2.创建Request对象,设置一个url地址,设置请求方式。 - Request request = new Request.Builder().url(url).method("GET",null).build(); - //3.创建一个call对象,参数就是Request请求对象 - Call call = okHttpClient.newCall(request); - //4.请求加入调度,重写回调方法 - call.enqueue(new Callback() { - //请求失败执行的方法 - @Override - public void onFailure(Call call, IOException e) { - Log.d(TAG, "onResponse push: 请求失败"); - - } - //请求成功执行的方法 - @Override - public void onResponse(Call call, Response response) throws IOException { - - Log.d(TAG, "onResponse push: "+response.body().string()); - - } - }); - } - - /** - * 取两个文本之间的文本值 - * - * @param text - * @param left - * @param right - * @return - */ - public static String getSubString(String text, String left, String right) { - String result = ""; - int zLen; - if (left == null || left.isEmpty()) { - zLen = 0; - } else { - zLen = text.indexOf(left); - if (zLen > -1) { - zLen += left.length(); - } else { - zLen = 0; - } - } - int yLen = text.indexOf(right, zLen); - if (yLen < 0 || right == null || right.isEmpty()) { - yLen = text.length(); - } - result = text.substring(zLen, yLen); - return result; - } - - - public static String md5(String string) { - if (TextUtils.isEmpty(string)) { - return ""; - } - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - byte[] bytes = md5.digest(string.getBytes()); - String result = ""; - for (byte b : bytes) { - String temp = Integer.toHexString(b & 0xff); - if (temp.length() == 1) { - temp = "0" + temp; - } - result += temp; - } - return result; - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return ""; - } - - - -} diff --git a/app/src/main/java/com/vone/vmq/NeNotificationService2.java b/app/src/main/java/com/vone/vmq/NeNotificationService2.java index 2badbd9..a9988e8 100644 --- a/app/src/main/java/com/vone/vmq/NeNotificationService2.java +++ b/app/src/main/java/com/vone/vmq/NeNotificationService2.java @@ -2,17 +2,15 @@ import android.annotation.SuppressLint; import android.app.Notification; -import android.content.Intent; +import android.content.Context; import android.content.SharedPreferences; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.PowerManager; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; -import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; -import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; @@ -20,10 +18,9 @@ import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import okhttp3.Call; import okhttp3.Callback; @@ -35,7 +32,91 @@ public class NeNotificationService2 extends NotificationListenerService { private String TAG = "NeNotificationService2"; private String host = ""; private String key = ""; + private Thread newThread = null; + private PowerManager.WakeLock mWakeLock = null; + + + //申请设备电源锁 + @SuppressLint("InvalidWakeLockTag") + public void acquireWakeLock(Context context) { + if (null == mWakeLock) + { + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "WakeLock"); + if (null != mWakeLock) + { + mWakeLock.acquire(); + } + } + } + //释放设备电源锁 + public void releaseWakeLock() { + if (null != mWakeLock) + { + mWakeLock.release(); + mWakeLock = null; + } + } + //心跳进程 + public void initAppHeart(){ + Log.d(TAG, "开始启动心跳线程"); + if (newThread!=null){ + return; + } + acquireWakeLock(this); + newThread = new Thread(new Runnable() { + @Override + public void run() { + Log.d(TAG, "心跳线程启动!"); + while (true){ + + SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE); + host = read.getString("host", ""); + key = read.getString("key", ""); + + //这里写入子线程需要做的工作 + String t = String.valueOf(new Date().getTime()); + String sign = md5(t+key); + + + OkHttpClient okHttpClient = new OkHttpClient(); + Request request = new Request.Builder().url("http://"+host+"/appHeart?t="+t+"&sign="+sign).method("GET",null).build(); + Call call = okHttpClient.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + final String error = e.getMessage(); + Handler handlerThree=new Handler(Looper.getMainLooper()); + handlerThree.post(new Runnable(){ + public void run(){ + Toast.makeText(getApplicationContext() ,"心跳状态错误,请检查配置是否正确!"+error,Toast.LENGTH_LONG).show(); + } + }); + } + //请求成功执行的方法 + @Override + public void onResponse(Call call, Response response) throws IOException { + Log.d(TAG, "onResponse heard: "+response.body().string()); + } + }); + try { + Thread.sleep(30*1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + }); + + newThread.start(); //启动线程 + } + + + + //当收到一条消息的时候回调,sbn是收到的消息 + @Override public void onNotificationPosted(StatusBarNotification sbn) { Log.d(TAG, "接受到通知消息"); SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE); @@ -46,108 +127,87 @@ public void onNotificationPosted(StatusBarNotification sbn) { Notification notification = sbn.getNotification(); String pkg = sbn.getPackageName(); if (notification != null) { - String notitime = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date(notification.when)); Bundle extras = notification.extras; if (extras != null) { String title = extras.getString(NotificationCompat.EXTRA_TITLE, ""); String content = extras.getString(NotificationCompat.EXTRA_TEXT, ""); Log.d(TAG, "**********************"); Log.d(TAG, "包名:" + pkg); - Log.d(TAG, "title:" + title); - Log.d(TAG, "content:" + content); + Log.d(TAG, "标题:" + title); + Log.d(TAG, "内容:" + content); Log.d(TAG, "**********************"); if (pkg.equals("com.eg.android.AlipayGphone")){ - String text = content; - if (text!=null){ - if (text.indexOf(":")==-1){ - if (text.indexOf("通过扫码向你付款")!=-1){ - String money = getSubString(text,"通过扫码向你付款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 "+money); - appPush(2,Double.valueOf(money)); - - }else if (text.indexOf("成功收款")!=-1){ - String money = getSubString(text,"成功收款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 "+money); - appPush(2,Double.valueOf(money)); - + if (content!=null && !content.equals("")) { + if (content.indexOf("通过扫码向你付款")!=-1 || content.indexOf("成功收款")!=-1){ + String money = getMoney(content); + if (money!=null){ + Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 " + money); + appPush(2, Double.valueOf(money)); } } - } - + } }else if(pkg.equals("com.tencent.mm")){ - String text = content; - - if (text!=null){ - //微信支付: 微信支付收款0.01元(朋友到店) - String[] tmp = text.split(":"); - if (tmp.length==2){ - if (tmp[0].equals("微信支付") || tmp[0].equals("微信收款助手") || tmp[0].equals("微信收款商业版")){ - if (text.indexOf("微信支付收款")!=-1){ - String money = getSubString(text,"微信支付收款","元"); - if (money.indexOf("支付")!=-1){ - money = getSubString(money+"元","微信支付收款","元"); - } - - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信 到账 "+money); - appPush(1,Double.valueOf(money)); - }else if (text.indexOf("店员消息")!=-1){ - - String money = getSubString(text,"[店员消息]收款到账","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信店员 到账 "+money); - appPush(1,Double.valueOf(money)); - }else if (text.indexOf("微信收款商业版")!=-1){ - - String money = getSubString(text,"商业版: 收款","元"); - Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信商业 到账 "+money); - - appPush(1,Double.valueOf(money)); - } + if (content!=null && !content.equals("")){ + if (title.equals("微信支付") || title.equals("微信收款助手") || title.equals("微信收款商业版")){ + String money = getMoney(content); + if (money!=null){ + Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信到账 "+ money); + appPush(1,Double.valueOf(money)); } + } } }else if(pkg.equals("com.vone.qrcode")){ - //测试推送 - String text = content; - if (text.equals("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")){ + + if (content.equals("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")){ Handler handlerThree=new Handler(Looper.getMainLooper()); handlerThree.post(new Runnable(){ public void run(){ - Toast.makeText(getApplicationContext() ,"监听权限正常!",Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext() ,"监听正常!",Toast.LENGTH_SHORT).show(); } }); } } + + + } } } + //当移除一条消息的时候回调,sbn是被移除的消息 + @Override + public void onNotificationRemoved(StatusBarNotification sbn) { + } + //当连接成功时调用,一般在开启监听后会回调一次该方法 @Override public void onListenerConnected() { - //当连接成功时调用,一般在开启监听后会回调一次该方法 - Handler handlerThree=new Handler(Looper.getMainLooper()); + //开启心跳线程 + initAppHeart(); + + Handler handlerThree = new Handler(Looper.getMainLooper()); handlerThree.post(new Runnable(){ public void run(){ Toast.makeText(getApplicationContext() ,"监听服务开启成功!",Toast.LENGTH_SHORT).show(); } }); - } - @Override - public void onNotificationRemoved(StatusBarNotification sbn) { - //当移除一条消息的时候回调,sbn是被移除的消息 + } + + + + public void appPush(int type,double price){ - //步骤1:创建一个SharedPreferences接口对象 - SharedPreferences read = getSharedPreferences("vone", MODE_WORLD_READABLE); - //步骤2:获取文件中的值 + SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE); host = read.getString("host", ""); key = read.getString("key", ""); @@ -158,21 +218,15 @@ public void appPush(int type,double price){ String url = "http://"+host+"/appPush?t="+t+"&type="+type+"&price="+price+"&sign="+sign; Log.d(TAG, "onResponse push: 开始:"+url); - //1.创建OkHttpClient对象 OkHttpClient okHttpClient = new OkHttpClient(); - //2.创建Request对象,设置一个url地址,设置请求方式。 Request request = new Request.Builder().url(url).method("GET",null).build(); - //3.创建一个call对象,参数就是Request请求对象 Call call = okHttpClient.newCall(request); - //4.请求加入调度,重写回调方法 call.enqueue(new Callback() { - //请求失败执行的方法 @Override public void onFailure(Call call, IOException e) { Log.d(TAG, "onResponse push: 请求失败"); } - //请求成功执行的方法 @Override public void onResponse(Call call, Response response) throws IOException { @@ -182,36 +236,23 @@ public void onResponse(Call call, Response response) throws IOException { }); } - /** - * 取两个文本之间的文本值 - * - * @param text - * @param left - * @param right - * @return - */ - public static String getSubString(String text, String left, String right) { - String result = ""; - int zLen; - if (left == null || left.isEmpty()) { - zLen = 0; - } else { - zLen = text.indexOf(left); - if (zLen > -1) { - zLen += left.length(); - } else { - zLen = 0; - } - } - int yLen = text.indexOf(right, zLen); - if (yLen < 0 || right == null || right.isEmpty()) { - yLen = text.length(); + public static String getMoney(String content){ + + int index = content.indexOf("]"); + if (index!=-1){ + content = content.substring(index+1); } - result = text.substring(zLen, yLen); - return result; - } + Pattern p = Pattern.compile("([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9])"); + Matcher m = p.matcher(content); + boolean result = m.find(); + String find_result = null; + if (result) { + find_result = m.group(1); + } + return find_result; + } public static String md5(String string) { if (TextUtils.isEmpty(string)) { return ""; @@ -235,4 +276,5 @@ public static String md5(String string) { return ""; } + } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 78432ad..6139f22 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -50,13 +50,13 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="doStart" - android:text="开启服务" /> + android:text="检测心跳" />