From e8ea004bc4d52d16dd5279ee79dd37d3e978cf4a Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Sat, 13 Nov 2021 18:01:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E5=85=B6=E4=BB=96APP=E9=80=9A=E7=9F=A5=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + app/build.gradle | 308 +++--- app/src/main/AndroidManifest.xml | 261 ++--- .../idormy/sms/forwarder/MainActivity.java | 677 ++++++++----- .../idormy/sms/forwarder/SettingActivity.java | 644 ++++++------ .../sms/forwarder/notify/NotifyHelper.java | 76 ++ .../sms/forwarder/notify/NotifyListener.java | 34 + .../idormy/sms/forwarder/sender/SendUtil.java | 4 +- .../sms/forwarder/service/BatteryService.java | 220 ++-- .../sms/forwarder/service/FrontService.java | 316 +++--- .../sms/forwarder/service/NotifyService.java | 52 + .../sms/forwarder/utils/PhoneUtils.java | 4 +- .../idormy/sms/forwarder/utils/SmsUtil.java | 1 - app/src/main/res/layout/activity_main.xml | 142 +-- app/src/main/res/layout/activity_setting.xml | 937 +++++++++--------- app/src/main/res/values-en/strings.xml | 1 + app/src/main/res/values/strings.xml | 29 +- gradle.properties | 2 +- settings.gradle | 1 + version.properties | 6 +- 20 files changed, 2104 insertions(+), 1612 deletions(-) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/notify/NotifyHelper.java create mode 100644 app/src/main/java/com/idormy/sms/forwarder/notify/NotifyListener.java create mode 100644 app/src/main/java/com/idormy/sms/forwarder/service/NotifyService.java diff --git a/README.md b/README.md index a79ae3bb..2678093f 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,7 @@ + https://github.com/xuexiangjys/XUpdateAPI (在线升级) + https://github.com/mailhu/emailkit (邮件发送) + https://github.com/alibaba/fastjson (Json解析) ++ https://github.com/lilongweidev/NotifyListenerDemo (手机通知服务) ## LICENSE diff --git a/app/build.gradle b/app/build.gradle index 4f2b40e3..af5a62ce 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,154 +1,154 @@ -apply plugin: 'com.android.application' - -def keyProps = new Properties() -def keyPropsFile = rootProject.file('keystore/keystore.properties') -if (keyPropsFile.exists()) { - keyProps.load(new FileInputStream(keyPropsFile)) -} - -// 读取version.properties -def versionProps = new Properties() -def versionPropsFile = rootProject.file('version.properties') -if (versionPropsFile.exists()) { - versionProps.load(new FileInputStream(versionPropsFile)) -} - -android { - buildToolsVersion '30.0.3' - compileSdkVersion 30 - compileOptions { - sourceCompatibility 1.8 - targetCompatibility 1.8 - } - defaultConfig { - applicationId "com.idormy.sms.forwarder" - minSdkVersion 23 - targetSdkVersion 30 - versionCode versionProps['versionCode'].toInteger() - versionName versionProps['versionName'] - testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - } - lintOptions { - checkReleaseBuilds false - } - signingConfigs { - release { - keyAlias keyProps['keyAlias'] - keyPassword keyProps['keyPassword'] - storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null - storePassword keyProps['storePassword'] - } - debug { - keyAlias keyProps['keyAlias'] - keyPassword keyProps['keyPassword'] - storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null - storePassword keyProps['storePassword'] - } - } - buildTypes { - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.release - } - debug { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.debug - } - } - //apk file name - android.applicationVariants.all { variant -> - variant.outputs.all { - //def date = new Date().format("yyyyMMdd" , TimeZone.getTimeZone("Asia/Shanghai")) - def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08")) - if (variant.buildType.name == 'debug') { - outputFileName = "SmsForwarder_debug_${date}_${versionName}.apk" - } - if (variant.buildType.name == 'release') { - outputFileName = "SmsForwarder_release_${date}_${versionName}.apk" - } - } - } -} - - -task upgradeVersion { - group 'help' - description '构建新版本' - doLast { - println("---自动升级版本号---\n") - String oldVersionCode = versionProps['versionCode'] - String oldVersionName = versionProps['versionName'] - if (oldVersionCode == null || oldVersionName == null || - oldVersionCode.isEmpty() || oldVersionName.isEmpty()) { - println("error:版本号不能为空") - return - } - versionProps['versionCode'] = String.valueOf(versionProps['versionCode'].toInteger() + 1) - String str = versionProps['versionName'].toString() - versionProps['versionName'] = str.substring(0, str.lastIndexOf('.') + 1) + - (str.substring(str.lastIndexOf('.') + 1).toInteger() + 1) - String tip = - "版本号从$oldVersionName($oldVersionCode)升级到${versionProps['versionName']}(${versionProps['versionCode']})" - println(tip) - - def writer = new FileWriter(versionPropsFile) - versionProps.store(writer, null) - writer.flush() - writer.close() - def tag = "v${versionProps['versionName']}" - cmdExecute("git pull") - cmdExecute("git add version.properties") - cmdExecute("git commit -m \"版本号升级为:$tag\"") - cmdExecute("git push origin") - cmdExecute("git tag $tag") - cmdExecute("git push origin $tag") - } -} - -void cmdExecute(String cmd) { - println "\n执行$cmd" - println cmd.execute().text -} - - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.1' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - - //okhttp - implementation 'com.squareup.okhttp3:okhttp:4.9.1' - implementation 'com.squareup.okio:okio:2.10.0' - - //fastjson - implementation "com.alibaba:fastjson:1.2.78" - - //友盟统计SDK - implementation 'com.umeng.umsdk:common:9.4.4'// 必选 - implementation 'com.umeng.umsdk:asms:1.4.1'// 必选 - implementation 'com.umeng.umsdk:apm:1.4.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选 - - //XUpdate - implementation 'com.github.xuexiangjys:XUpdate:2.1.0' - implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-easy:1.0.0' - implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-downloader-aria:1.0.0' - - //EmailKit - implementation 'com.github.mailhu:emailkit:4.2.2' - - //Lombok - //noinspection AnnotationProcessorOnCompilePath - compileOnly 'org.projectlombok:lombok:1.18.20' - annotationProcessor 'org.projectlombok:lombok:1.18.20' - - //RxJava - implementation 'io.reactivex.rxjava3:rxjava:3.1.1' - - //AndroidAsync - implementation 'com.koushikdutta.async:androidasync:3.1.0' -} +apply plugin: 'com.android.application' + +def keyProps = new Properties() +def keyPropsFile = rootProject.file('keystore/keystore.properties') +if (keyPropsFile.exists()) { + keyProps.load(new FileInputStream(keyPropsFile)) +} + +// 读取version.properties +def versionProps = new Properties() +def versionPropsFile = rootProject.file('version.properties') +if (versionPropsFile.exists()) { + versionProps.load(new FileInputStream(versionPropsFile)) +} + +android { + buildToolsVersion '30.0.3' + compileSdkVersion 30 + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + defaultConfig { + applicationId "com.idormy.sms.forwarder" + minSdkVersion 21 + targetSdkVersion 30 + versionCode versionProps['versionCode'].toInteger() + versionName versionProps['versionName'] + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + lintOptions { + checkReleaseBuilds false + } + signingConfigs { + release { + keyAlias keyProps['keyAlias'] + keyPassword keyProps['keyPassword'] + storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null + storePassword keyProps['storePassword'] + } + debug { + keyAlias keyProps['keyAlias'] + keyPassword keyProps['keyPassword'] + storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null + storePassword keyProps['storePassword'] + } + } + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + debug { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug + } + } + //apk file name + android.applicationVariants.all { variant -> + variant.outputs.all { + //def date = new Date().format("yyyyMMdd" , TimeZone.getTimeZone("Asia/Shanghai")) + def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08")) + if (variant.buildType.name == 'debug') { + outputFileName = "SmsForwarder_debug_${date}_${versionName}.apk" + } + if (variant.buildType.name == 'release') { + outputFileName = "SmsForwarder_release_${date}_${versionName}.apk" + } + } + } +} + + +task upgradeVersion { + group 'help' + description '构建新版本' + doLast { + println("---自动升级版本号---\n") + String oldVersionCode = versionProps['versionCode'] + String oldVersionName = versionProps['versionName'] + if (oldVersionCode == null || oldVersionName == null || + oldVersionCode.isEmpty() || oldVersionName.isEmpty()) { + println("error:版本号不能为空") + return + } + versionProps['versionCode'] = String.valueOf(versionProps['versionCode'].toInteger() + 1) + String str = versionProps['versionName'].toString() + versionProps['versionName'] = str.substring(0, str.lastIndexOf('.') + 1) + + (str.substring(str.lastIndexOf('.') + 1).toInteger() + 1) + String tip = + "版本号从$oldVersionName($oldVersionCode)升级到${versionProps['versionName']}(${versionProps['versionCode']})" + println(tip) + + def writer = new FileWriter(versionPropsFile) + versionProps.store(writer, null) + writer.flush() + writer.close() + def tag = "v${versionProps['versionName']}" + cmdExecute("git pull") + cmdExecute("git add version.properties") + cmdExecute("git commit -m \"版本号升级为:$tag\"") + cmdExecute("git push origin") + cmdExecute("git tag $tag") + cmdExecute("git push origin $tag") + } +} + +void cmdExecute(String cmd) { + println "\n执行$cmd" + println cmd.execute().text +} + + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.1' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + //okhttp + implementation 'com.squareup.okhttp3:okhttp:4.9.1' + implementation 'com.squareup.okio:okio:2.10.0' + + //fastjson + implementation "com.alibaba:fastjson:1.2.78" + + //友盟统计SDK + implementation 'com.umeng.umsdk:common:9.4.4'// 必选 + implementation 'com.umeng.umsdk:asms:1.4.1'// 必选 + implementation 'com.umeng.umsdk:apm:1.4.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选 + + //XUpdate + implementation 'com.github.xuexiangjys:XUpdate:2.1.0' + implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-easy:1.0.0' + implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-downloader-aria:1.0.0' + + //EmailKit + implementation 'com.github.mailhu:emailkit:4.2.2' + + //Lombok + //noinspection AnnotationProcessorOnCompilePath + compileOnly 'org.projectlombok:lombok:1.18.20' + annotationProcessor 'org.projectlombok:lombok:1.18.20' + + //RxJava + implementation 'io.reactivex.rxjava3:rxjava:3.1.1' + + //AndroidAsync + implementation 'com.koushikdutta.async:androidasync:3.1.0' +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d9cb87be..98dd45fa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,120 +1,143 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java b/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java index 8be2ef79..1a841b36 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java +++ b/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java @@ -1,247 +1,430 @@ -package com.idormy.sms.forwarder; - -import android.annotation.SuppressLint; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; - -import com.idormy.sms.forwarder.adapter.LogAdapter; -import com.idormy.sms.forwarder.model.vo.LogVo; -import com.idormy.sms.forwarder.utils.LogUtil; -import com.idormy.sms.forwarder.utils.NetUtil; -import com.idormy.sms.forwarder.utils.PhoneUtils; -import com.idormy.sms.forwarder.utils.SmsUtil; -import com.idormy.sms.forwarder.utils.aUtil; - -import java.util.ArrayList; -import java.util.List; - -public class MainActivity extends AppCompatActivity implements RefreshListView.IRefreshListener { - - private final String TAG = "MainActivity"; - // logVoList用于存储数据 - private List logVos = new ArrayList<>(); - private LogAdapter adapter; - private RefreshListView listView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - - LogUtil.init(this); - Log.d(TAG, "onCreate"); - - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - //检查权限是否获取 - PackageManager pm = getPackageManager(); - PhoneUtils.CheckPermission(pm, this); - - //获取SIM信息 - PhoneUtils.init(this); - - //短信&网络组件初始化 - SmsUtil.init(this); - NetUtil.init(this); - } - - @Override - protected void onStart() { - super.onStart(); - Log.d(TAG, "onStart"); - - //是否关闭页面提示 - TextView help_tip = findViewById(R.id.help_tip); - help_tip.setVisibility(MyApplication.showHelpTip ? View.VISIBLE : View.GONE); - - // 先拿到数据并放在适配器上 - initTLogs(); //初始化数据 - showList(logVos); - - // 为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法 - // 在这个方法中可以通过position参数判断出用户点击的是那一个子项 - listView.setOnItemClickListener((parent, view, position, id) -> { - if (position <= 0) return; - - LogVo logVo = logVos.get(position - 1); - logDetail(logVo); - }); - - listView.setOnItemLongClickListener((parent, view, position, id) -> { - if (position <= 0) return false; - - //定义AlertDialog.Builder对象,当长按列表项的时候弹出确认删除对话框 - AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); - builder.setTitle(R.string.delete_log_title); - builder.setMessage(R.string.delete_log_tips); - - //添加AlertDialog.Builder对象的setPositiveButton()方法 - builder.setPositiveButton(R.string.confirm, (dialog, which) -> { - Long id1 = logVos.get(position - 1).getId(); - Log.d(TAG, "id = " + id1); - LogUtil.delLog(id1, null); - initTLogs(); //初始化数据 - showList(logVos); - Toast.makeText(getBaseContext(), R.string.delete_log_toast, Toast.LENGTH_SHORT).show(); - }); - - //添加AlertDialog.Builder对象的setNegativeButton()方法 - builder.setNegativeButton(R.string.cancel, (dialog, which) -> { - }); - - builder.create().show(); - return true; - }); - } - - @Override - protected void onResume() { - super.onResume(); - //第一次打开,未授权无法获取SIM信息,尝试在此重新获取 - if (MyApplication.SimInfoList.isEmpty()) { - MyApplication.SimInfoList = PhoneUtils.getSimMultiInfo(); - } - Log.d(TAG, "SimInfoList = " + MyApplication.SimInfoList.size()); - } - - // 初始化数据 - private void initTLogs() { - logVos = LogUtil.getLog(null, null); - } - - private void showList(List logVosN) { - Log.d(TAG, "showList: " + logVosN); - if (adapter == null) { - // 将适配器上的数据传递给listView - listView = findViewById(R.id.list_view_log); - listView.setInterface(this); - adapter = new LogAdapter(MainActivity.this, R.layout.item_log, logVosN); - - listView.setAdapter(adapter); - } else { - adapter.onDateChange(logVosN); - } - } - - @Override - public void onRefresh() { - Handler handler = new Handler(); - handler.postDelayed(() -> { - // TODO Auto-generated method stub - //获取最新数据 - initTLogs(); - //通知界面显示 - showList(logVos); - //通知listview 刷新数据完毕; - listView.refreshComplete(); - }, 2000); - } - - - public void logDetail(LogVo logVo) { - AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); - builder.setTitle(R.string.details); - String simInfo = logVo.getSimInfo(); - if (simInfo != null) { - builder.setMessage(logVo.getFrom() + "\n\n" + logVo.getContent() + "\n\n" + logVo.getSimInfo() + "\n\n" + logVo.getRule() + "\n\n" + aUtil.utc2Local(logVo.getTime()) + "\n\nResponse:" + logVo.getForwardResponse()); - } else { - builder.setMessage(logVo.getFrom() + "\n\n" + logVo.getContent() + "\n\n" + logVo.getRule() + "\n\n" + aUtil.utc2Local(logVo.getTime()) + "\n\nResponse:" + logVo.getForwardResponse()); - } - //删除 - builder.setNegativeButton(R.string.del, (dialog, which) -> { - Long id = logVo.getId(); - Log.d(TAG, "id = " + id); - LogUtil.delLog(id, null); - initTLogs(); //初始化数据 - showList(logVos); - Toast.makeText(MainActivity.this, R.string.delete_log_toast, Toast.LENGTH_SHORT).show(); - dialog.dismiss(); - }); - builder.show(); - } - - public void toClone() { - Intent intent = new Intent(this, CloneActivity.class); - startActivity(intent); - } - - public void toSetting() { - Intent intent = new Intent(this, SettingActivity.class); - startActivity(intent); - } - - public void toAbout() { - Intent intent = new Intent(this, AboutActivity.class); - startActivity(intent); - } - - public void toRuleSetting(View view) { - Intent intent = new Intent(this, RuleActivity.class); - startActivity(intent); - } - - public void toSendSetting(View view) { - Intent intent = new Intent(this, SenderActivity.class); - startActivity(intent); - } - - public void cleanLog(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); - builder.setTitle(R.string.clear_logs_tips) - .setPositiveButton(R.string.confirm, (dialog, which) -> { - // TODO Auto-generated method stub - LogUtil.delLog(null, null); - initTLogs(); - adapter.add(logVos); - }); - builder.show(); - } - - //按返回键不退出回到桌面 - @Override - public void onBackPressed() { - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addCategory(Intent.CATEGORY_HOME); - startActivity(intent); - } - - @SuppressLint("NonConstantResourceId") - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle item selection - switch (item.getItemId()) { - case R.id.to_clone: - toClone(); - return true; - case R.id.to_setting: - toSetting(); - return true; - case R.id.to_about: - toAbout(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu_main, menu); - return true; - - } - -} +package com.idormy.sms.forwarder; + +import android.annotation.SuppressLint; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.PowerManager; +import android.service.notification.StatusBarNotification; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.NotificationManagerCompat; + +import com.idormy.sms.forwarder.adapter.LogAdapter; +import com.idormy.sms.forwarder.model.vo.LogVo; +import com.idormy.sms.forwarder.model.vo.SmsVo; +import com.idormy.sms.forwarder.notify.NotifyHelper; +import com.idormy.sms.forwarder.notify.NotifyListener; +import com.idormy.sms.forwarder.sender.SendUtil; +import com.idormy.sms.forwarder.service.FrontService; +import com.idormy.sms.forwarder.service.NotifyService; +import com.idormy.sms.forwarder.utils.LogUtil; +import com.idormy.sms.forwarder.utils.NetUtil; +import com.idormy.sms.forwarder.utils.PhoneUtils; +import com.idormy.sms.forwarder.utils.SmsUtil; +import com.idormy.sms.forwarder.utils.aUtil; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +public class MainActivity extends AppCompatActivity implements NotifyListener, RefreshListView.IRefreshListener { + + private final String TAG = "MainActivity"; + private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"; + // logVoList用于存储数据 + private List logVos = new ArrayList<>(); + private LogAdapter adapter; + private RefreshListView listView; + private Intent serviceIntent; + private static final int REQUEST_CODE = 9999; + + @Override + protected void onCreate(Bundle savedInstanceState) { + + LogUtil.init(this); + Log.d(TAG, "onCreate"); + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + //检查权限是否获取 + PackageManager pm = getPackageManager(); + PhoneUtils.CheckPermission(pm, this); + + //获取SIM信息 + PhoneUtils.init(this); + + //短信&网络组件初始化 + SmsUtil.init(this); + NetUtil.init(this); + + //应用通知 + NotifyHelper.getInstance().setNotifyListener(this); + + //前台服务 + serviceIntent = new Intent(MainActivity.this, FrontService.class); + serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startService(serviceIntent); + } + + @Override + protected void onStart() { + super.onStart(); + Log.d(TAG, "onStart"); + + //是否关闭页面提示 + TextView help_tip = findViewById(R.id.help_tip); + help_tip.setVisibility(MyApplication.showHelpTip ? View.VISIBLE : View.GONE); + + // 先拿到数据并放在适配器上 + initTLogs(); //初始化数据 + showList(logVos); + + // 为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法 + // 在这个方法中可以通过position参数判断出用户点击的是那一个子项 + listView.setOnItemClickListener((parent, view, position, id) -> { + if (position <= 0) return; + + LogVo logVo = logVos.get(position - 1); + logDetail(logVo); + }); + + listView.setOnItemLongClickListener((parent, view, position, id) -> { + if (position <= 0) return false; + + //定义AlertDialog.Builder对象,当长按列表项的时候弹出确认删除对话框 + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle(R.string.delete_log_title); + builder.setMessage(R.string.delete_log_tips); + + //添加AlertDialog.Builder对象的setPositiveButton()方法 + builder.setPositiveButton(R.string.confirm, (dialog, which) -> { + Long id1 = logVos.get(position - 1).getId(); + Log.d(TAG, "id = " + id1); + LogUtil.delLog(id1, null); + initTLogs(); //初始化数据 + showList(logVos); + Toast.makeText(getBaseContext(), R.string.delete_log_toast, Toast.LENGTH_SHORT).show(); + }); + + //添加AlertDialog.Builder对象的setNegativeButton()方法 + builder.setNegativeButton(R.string.cancel, (dialog, which) -> { + }); + + builder.create().show(); + return true; + }); + } + + @SuppressLint("ObsoleteSdkInt") + @Override + protected void onResume() { + super.onResume(); + //第一次打开,未授权无法获取SIM信息,尝试在此重新获取 + if (MyApplication.SimInfoList.isEmpty()) { + MyApplication.SimInfoList = PhoneUtils.getSimMultiInfo(); + } + Log.d(TAG, "SimInfoList = " + MyApplication.SimInfoList.size()); + + //开启读取通知栏权限 + if (!isNotificationListenerServiceEnabled(this)) { + openNotificationAccess(); + toggleNotificationListenerService(); + Toast.makeText(this, "请先勾选《短信转发器》的读取通知栏权限!", Toast.LENGTH_LONG).show(); + return; + } + + //省电优化设置为无限制 + if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + if (!isIgnoringBatteryOptimizations()) { + Toast.makeText(this, "请将省电优化设置为无限制,有利于防止《短信转发器》被杀!!", Toast.LENGTH_LONG).show(); + } + } + startService(serviceIntent); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + startService(serviceIntent); + } + + @Override + protected void onPause() { + //当界面返回到桌面之后.清除通知设置当中的数据.减少内存占有 + //if (applicationList != null) { + // applicationList.setAdapter(null); + // adapter = null; + //} + super.onPause(); + startService(serviceIntent); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE) { + if (isNotificationListenerServiceEnabled(this)) { + Toast.makeText(this, "通知服务已开启", Toast.LENGTH_SHORT).show(); + toggleNotificationListenerService(); + } else { + Toast.makeText(this, "通知服务未开启", Toast.LENGTH_SHORT).show(); + } + } + } + + // 权限判断相关 + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + public void toggleNotificationListenerService() { + PackageManager pm = getPackageManager(); + pm.setComponentEnabledSetting(new ComponentName(getApplicationContext(), NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + + pm.setComponentEnabledSetting(new ComponentName(getApplicationContext(), NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); + } + + private static boolean isNotificationListenerServiceEnabled(Context context) { + Set packageNames = NotificationManagerCompat.getEnabledListenerPackages(context); + return packageNames.contains(context.getPackageName()); + } + + /** + * 判断系统是否已经关闭省电优化 + * + * @return boolean + */ + @RequiresApi(api = Build.VERSION_CODES.M) + private boolean isIgnoringBatteryOptimizations() { + boolean isIgnoring = false; + PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (powerManager != null) { + isIgnoring = powerManager.isIgnoringBatteryOptimizations(getPackageName()); + } + if (!isIgnoring) { + Intent i = new Intent(android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); + startActivity(i); + } + return isIgnoring; + } + + private void openNotificationAccess() { + startActivity(new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS)); + } + + + // 初始化数据 + private void initTLogs() { + logVos = LogUtil.getLog(null, null); + } + + private void showList(List logVosN) { + Log.d(TAG, "showList: " + logVosN); + if (adapter == null) { + // 将适配器上的数据传递给listView + listView = findViewById(R.id.list_view_log); + listView.setInterface(this); + adapter = new LogAdapter(MainActivity.this, R.layout.item_log, logVosN); + + listView.setAdapter(adapter); + } else { + adapter.onDateChange(logVosN); + } + } + + @Override + public void onRefresh() { + Handler handler = new Handler(); + handler.postDelayed(() -> { + // TODO Auto-generated method stub + //获取最新数据 + initTLogs(); + //通知界面显示 + showList(logVos); + //通知listview 刷新数据完毕; + listView.refreshComplete(); + }, 2000); + } + + public void logDetail(LogVo logVo) { + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle(R.string.details); + String simInfo = logVo.getSimInfo(); + if (simInfo != null) { + builder.setMessage(logVo.getFrom() + "\n\n" + logVo.getContent() + "\n\n" + logVo.getSimInfo() + "\n\n" + logVo.getRule() + "\n\n" + aUtil.utc2Local(logVo.getTime()) + "\n\nResponse:" + logVo.getForwardResponse()); + } else { + builder.setMessage(logVo.getFrom() + "\n\n" + logVo.getContent() + "\n\n" + logVo.getRule() + "\n\n" + aUtil.utc2Local(logVo.getTime()) + "\n\nResponse:" + logVo.getForwardResponse()); + } + //删除 + builder.setNegativeButton(R.string.del, (dialog, which) -> { + Long id = logVo.getId(); + Log.d(TAG, "id = " + id); + LogUtil.delLog(id, null); + initTLogs(); //初始化数据 + showList(logVos); + Toast.makeText(MainActivity.this, R.string.delete_log_toast, Toast.LENGTH_SHORT).show(); + dialog.dismiss(); + }); + builder.show(); + } + + public void toClone() { + Intent intent = new Intent(this, CloneActivity.class); + startActivity(intent); + } + + public void toSetting() { + Intent intent = new Intent(this, SettingActivity.class); + startActivity(intent); + } + + public void toAbout() { + Intent intent = new Intent(this, AboutActivity.class); + startActivity(intent); + } + + public void toRuleSetting(View view) { + Intent intent = new Intent(this, RuleActivity.class); + startActivity(intent); + } + + public void toSendSetting(View view) { + Intent intent = new Intent(this, SenderActivity.class); + startActivity(intent); + } + + public void cleanLog(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle(R.string.clear_logs_tips) + .setPositiveButton(R.string.confirm, (dialog, which) -> { + // TODO Auto-generated method stub + LogUtil.delLog(null, null); + initTLogs(); + adapter.add(logVos); + }); + builder.show(); + } + + //按返回键不退出回到桌面 + @Override + public void onBackPressed() { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addCategory(Intent.CATEGORY_HOME); + startActivity(intent); + } + + @SuppressLint("NonConstantResourceId") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.to_clone: + toClone(); + return true; + case R.id.to_setting: + toSetting(); + return true; + case R.id.to_about: + toAbout(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_main, menu); + return true; + } + + /** + * 收到通知 + * + * @param type 通知类型 + */ + @Override + public void onReceiveMessage(int type) { + Log.d(TAG, "收到通知=" + type); + } + + /** + * 移除通知 + * + * @param type 通知类型 + */ + @Override + public void onRemovedMessage(int type) { + Log.d(TAG, "移除通知=" + type); + } + + /** + * 收到通知 + * + * @param sbn 状态栏通知 + */ + @Override + public void onReceiveMessage(StatusBarNotification sbn) { + if (sbn.getNotification() == null) return; + + //推送通知的应用包名 + String packageName = sbn.getPackageName(); + //通知标题 + String title = sbn.getNotification().extras.get("android.title").toString(); + //通知内容 + String text = sbn.getNotification().extras.get("android.text").toString(); + if (text.isEmpty() && sbn.getNotification().tickerText != null) { + text = sbn.getNotification().tickerText.toString(); + } + //通知时间 + String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINESE).format(new Date(sbn.getPostTime())); + + Log.d(TAG, String.format( + Locale.getDefault(), + "onNotificationPosted:\n应用包名:%s\n消息标题:%s\n消息内容:%s\n消息时间:%s\n", + packageName, title, text, time) + ); + + //不处理空消息 + if (title.isEmpty() && text.isEmpty()) return; + + SmsVo smsVo = new SmsVo(packageName, text, new Date(), title); + Log.d(TAG, "send_msg" + smsVo.toString()); + SendUtil.send_msg(this, smsVo, 1); + } + + /** + * 移除掉通知栏消息 + * + * @param sbn 状态栏通知 + */ + @Override + public void onRemovedMessage(StatusBarNotification sbn) { + Log.d(TAG, "移除掉通知栏消息"); + } + +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java b/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java index 3db70129..60abc6c2 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java +++ b/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java @@ -1,288 +1,356 @@ -package com.idormy.sms.forwarder; - -import android.annotation.SuppressLint; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.Log; -import android.view.View; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.Switch; -import android.widget.Toast; - -import androidx.appcompat.app.AppCompatActivity; - -import com.idormy.sms.forwarder.utils.KeepAliveUtils; -import com.idormy.sms.forwarder.utils.SettingUtil; - - -public class SettingActivity extends AppCompatActivity { - private final String TAG = "SettingActivity"; - - @Override - public void onCreate(Bundle savedInstanceState) { - Log.d(TAG, "onCreate"); - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_setting); - - EditText et_add_extra_device_mark = findViewById(R.id.et_add_extra_device_mark); - editAddExtraDeviceMark(et_add_extra_device_mark); - - EditText et_add_extra_sim1 = findViewById(R.id.et_add_extra_sim1); - editAddExtraSim1(et_add_extra_sim1); - - EditText et_add_extra_sim2 = findViewById(R.id.et_add_extra_sim2); - editAddExtraSim2(et_add_extra_sim2); - - EditText et_battery_level_alarm = findViewById(R.id.et_battery_level_alarm); - editBatteryLevelAlarm(et_battery_level_alarm); - - EditText et_retry_delay_time1 = findViewById(R.id.et_retry_delay_time1); - editRetryDelayTime(et_retry_delay_time1, 1); - EditText et_retry_delay_time2 = findViewById(R.id.et_retry_delay_time2); - editRetryDelayTime(et_retry_delay_time2, 2); - EditText et_retry_delay_time3 = findViewById(R.id.et_retry_delay_time3); - editRetryDelayTime(et_retry_delay_time3, 3); - EditText et_retry_delay_time4 = findViewById(R.id.et_retry_delay_time4); - editRetryDelayTime(et_retry_delay_time4, 4); - EditText et_retry_delay_time5 = findViewById(R.id.et_retry_delay_time5); - editRetryDelayTime(et_retry_delay_time5, 5); - - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template = findViewById(R.id.switch_sms_template); - switchSmsTemplate(switch_sms_template); - - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_enable_phone = findViewById(R.id.switch_enable_phone); - switchEnablePhone(switch_enable_phone); - - EditText textSmsTemplate = findViewById(R.id.text_sms_template); - editSmsTemplate(textSmsTemplate); - } - - //设置转发来电 - private void switchEnablePhone(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_enable_phone) { - switch_enable_phone.setChecked(SettingUtil.getSwitchEnablePhone()); - - switch_enable_phone.setOnCheckedChangeListener((buttonView, isChecked) -> { - SettingUtil.switchEnablePhone(isChecked); - Log.d(TAG, "onCheckedChanged:" + isChecked); - }); - } - - //设置设备名称 - private void editAddExtraDeviceMark(final EditText et_add_extra_device_mark) { - et_add_extra_device_mark.setText(SettingUtil.getAddExtraDeviceMark()); - - et_add_extra_device_mark.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - SettingUtil.setAddExtraDeviceMark(et_add_extra_device_mark.getText().toString()); - } - }); - } - - //设置SIM1备注 - private void editAddExtraSim1(final EditText et_add_extra_sim1) { - et_add_extra_sim1.setText(SettingUtil.getAddExtraSim1()); - - et_add_extra_sim1.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - SettingUtil.setAddExtraSim1(et_add_extra_sim1.getText().toString()); - } - }); - } - - //设置SIM2备注 - private void editAddExtraSim2(final EditText et_add_extra_sim2) { - et_add_extra_sim2.setText(SettingUtil.getAddExtraSim2()); - - et_add_extra_sim2.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - SettingUtil.setAddExtraSim2(et_add_extra_sim2.getText().toString()); - } - }); - } - - //设置低电量报警值 - private void editBatteryLevelAlarm(final EditText et_battery_level_alarm) { - et_battery_level_alarm.setText(String.valueOf(SettingUtil.getBatteryLevelAlarm())); - - et_battery_level_alarm.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - String batteryLevel = et_battery_level_alarm.getText().toString(); - if (!batteryLevel.isEmpty()) { - SettingUtil.setBatteryLevelAlarm(Integer.parseInt(batteryLevel)); - } else { - SettingUtil.setBatteryLevelAlarm(0); - } - } - }); - } - - - //接口请求失败重试 - private void editRetryDelayTime(final EditText et_retry_delay_time, final int index) { - et_retry_delay_time.setText(String.valueOf(SettingUtil.getRetryDelayTime(index))); - - et_retry_delay_time.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - String delayTime = et_retry_delay_time.getText().toString(); - if (!delayTime.isEmpty()) { - SettingUtil.setRetryDelayTime(index, Integer.parseInt(delayTime)); - } else { - SettingUtil.setRetryDelayTime(index, 0); - } - } - }); - } - - //设置转发时启用自定义模版 - private void switchSmsTemplate(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template) { - boolean isOn = SettingUtil.getSwitchSmsTemplate(); - switch_sms_template.setChecked(isOn); - - final LinearLayout layout_sms_template = findViewById(R.id.layout_sms_template); - layout_sms_template.setVisibility(isOn ? View.VISIBLE : View.GONE); - final EditText textSmsTemplate = findViewById(R.id.text_sms_template); - - switch_sms_template.setOnCheckedChangeListener((buttonView, isChecked) -> { - Log.d(TAG, "onCheckedChanged:" + isChecked); - layout_sms_template.setVisibility(isChecked ? View.VISIBLE : View.GONE); - SettingUtil.switchSmsTemplate(isChecked); - if (!isChecked) { - textSmsTemplate.setText("{{来源号码}}\n{{短信内容}}\n{{卡槽信息}}\n{{接收时间}}\n{{设备名称}}"); - } - }); - } - - //设置转发信息模版 - private void editSmsTemplate(final EditText textSmsTemplate) { - textSmsTemplate.setText(SettingUtil.getSmsTemplate()); - - textSmsTemplate.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - SettingUtil.setSmsTemplate(textSmsTemplate.getText().toString()); - } - }); - } - - //插入标签 - @SuppressLint("NonConstantResourceId") - public void toInsertLabel(View v) { - EditText textSmsTemplate = findViewById(R.id.text_sms_template); - textSmsTemplate.setFocusable(true); - textSmsTemplate.requestFocus(); - switch (v.getId()) { - case R.id.bt_insert_sender: - textSmsTemplate.append("{{来源号码}}"); - return; - case R.id.bt_insert_content: - textSmsTemplate.append("{{短信内容}}"); - return; - case R.id.bt_insert_extra: - textSmsTemplate.append("{{卡槽信息}}"); - return; - case R.id.bt_insert_time: - textSmsTemplate.append("{{接收时间}}"); - return; - case R.id.bt_insert_device_name: - textSmsTemplate.append("{{设备名称}}"); - return; - default: - } - } - - //恢复初始化配置 - public void initSetting(View view) { - - EditText et_add_extra_device_mark = findViewById(R.id.et_add_extra_device_mark); - et_add_extra_device_mark.setText(""); - editAddExtraDeviceMark(et_add_extra_device_mark); - - EditText et_add_extra_sim1 = findViewById(R.id.et_add_extra_sim1); - et_add_extra_sim1.setText(""); - editAddExtraSim1(et_add_extra_sim1); - - EditText et_add_extra_sim2 = findViewById(R.id.et_add_extra_sim2); - et_add_extra_sim2.setText(""); - editAddExtraSim2(et_add_extra_sim2); - - @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template = findViewById(R.id.switch_sms_template); - switch_sms_template.setChecked(false); - switchSmsTemplate(switch_sms_template); - - EditText textSmsTemplate = findViewById(R.id.text_sms_template); - textSmsTemplate.setText("{{来源号码}}\n{{短信内容}}\n{{卡槽信息}}\n{{接收时间}}\n{{设备名称}}"); - editSmsTemplate(textSmsTemplate); - - } - - public void batterySetting(View view) { - if (KeepAliveUtils.isIgnoreBatteryOptimization(this)) { - Toast.makeText(this, R.string.isIgnored, Toast.LENGTH_SHORT).show(); - } else { - KeepAliveUtils.ignoreBatteryOptimization(this); - } - } -} +package com.idormy.sms.forwarder; + +import android.annotation.SuppressLint; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.NotificationManagerCompat; + +import com.idormy.sms.forwarder.service.NotifyService; +import com.idormy.sms.forwarder.utils.KeepAliveUtils; +import com.idormy.sms.forwarder.utils.SettingUtil; + +import java.util.Set; + +public class SettingActivity extends AppCompatActivity { + private final String TAG = "SettingActivity"; + + private static final int REQUEST_CODE = 9527; + private TextView textView; + + @Override + public void onCreate(Bundle savedInstanceState) { + Log.d(TAG, "onCreate"); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_setting); + + EditText et_add_extra_device_mark = findViewById(R.id.et_add_extra_device_mark); + editAddExtraDeviceMark(et_add_extra_device_mark); + + EditText et_add_extra_sim1 = findViewById(R.id.et_add_extra_sim1); + editAddExtraSim1(et_add_extra_sim1); + + EditText et_add_extra_sim2 = findViewById(R.id.et_add_extra_sim2); + editAddExtraSim2(et_add_extra_sim2); + + EditText et_battery_level_alarm = findViewById(R.id.et_battery_level_alarm); + editBatteryLevelAlarm(et_battery_level_alarm); + + EditText et_retry_delay_time1 = findViewById(R.id.et_retry_delay_time1); + editRetryDelayTime(et_retry_delay_time1, 1); + EditText et_retry_delay_time2 = findViewById(R.id.et_retry_delay_time2); + editRetryDelayTime(et_retry_delay_time2, 2); + EditText et_retry_delay_time3 = findViewById(R.id.et_retry_delay_time3); + editRetryDelayTime(et_retry_delay_time3, 3); + EditText et_retry_delay_time4 = findViewById(R.id.et_retry_delay_time4); + editRetryDelayTime(et_retry_delay_time4, 4); + EditText et_retry_delay_time5 = findViewById(R.id.et_retry_delay_time5); + editRetryDelayTime(et_retry_delay_time5, 5); + + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template = findViewById(R.id.switch_sms_template); + switchSmsTemplate(switch_sms_template); + + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_enable_phone = findViewById(R.id.switch_enable_phone); + switchEnablePhone(switch_enable_phone); + + EditText textSmsTemplate = findViewById(R.id.text_sms_template); + editSmsTemplate(textSmsTemplate); + } + + //设置转发来电 + private void switchEnablePhone(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_enable_phone) { + switch_enable_phone.setChecked(SettingUtil.getSwitchEnablePhone()); + + switch_enable_phone.setOnCheckedChangeListener((buttonView, isChecked) -> { + SettingUtil.switchEnablePhone(isChecked); + Log.d(TAG, "onCheckedChanged:" + isChecked); + }); + } + + //设置设备名称 + private void editAddExtraDeviceMark(final EditText et_add_extra_device_mark) { + et_add_extra_device_mark.setText(SettingUtil.getAddExtraDeviceMark()); + + et_add_extra_device_mark.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + SettingUtil.setAddExtraDeviceMark(et_add_extra_device_mark.getText().toString()); + } + }); + } + + //设置SIM1备注 + private void editAddExtraSim1(final EditText et_add_extra_sim1) { + et_add_extra_sim1.setText(SettingUtil.getAddExtraSim1()); + + et_add_extra_sim1.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + SettingUtil.setAddExtraSim1(et_add_extra_sim1.getText().toString()); + } + }); + } + + //设置SIM2备注 + private void editAddExtraSim2(final EditText et_add_extra_sim2) { + et_add_extra_sim2.setText(SettingUtil.getAddExtraSim2()); + + et_add_extra_sim2.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + SettingUtil.setAddExtraSim2(et_add_extra_sim2.getText().toString()); + } + }); + } + + //设置低电量报警值 + private void editBatteryLevelAlarm(final EditText et_battery_level_alarm) { + et_battery_level_alarm.setText(String.valueOf(SettingUtil.getBatteryLevelAlarm())); + + et_battery_level_alarm.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + String batteryLevel = et_battery_level_alarm.getText().toString(); + if (!batteryLevel.isEmpty()) { + SettingUtil.setBatteryLevelAlarm(Integer.parseInt(batteryLevel)); + } else { + SettingUtil.setBatteryLevelAlarm(0); + } + } + }); + } + + + //接口请求失败重试 + private void editRetryDelayTime(final EditText et_retry_delay_time, final int index) { + et_retry_delay_time.setText(String.valueOf(SettingUtil.getRetryDelayTime(index))); + + et_retry_delay_time.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + String delayTime = et_retry_delay_time.getText().toString(); + if (!delayTime.isEmpty()) { + SettingUtil.setRetryDelayTime(index, Integer.parseInt(delayTime)); + } else { + SettingUtil.setRetryDelayTime(index, 0); + } + } + }); + } + + //设置转发时启用自定义模版 + private void switchSmsTemplate(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template) { + boolean isOn = SettingUtil.getSwitchSmsTemplate(); + switch_sms_template.setChecked(isOn); + + final LinearLayout layout_sms_template = findViewById(R.id.layout_sms_template); + layout_sms_template.setVisibility(isOn ? View.VISIBLE : View.GONE); + final EditText textSmsTemplate = findViewById(R.id.text_sms_template); + + switch_sms_template.setOnCheckedChangeListener((buttonView, isChecked) -> { + Log.d(TAG, "onCheckedChanged:" + isChecked); + layout_sms_template.setVisibility(isChecked ? View.VISIBLE : View.GONE); + SettingUtil.switchSmsTemplate(isChecked); + if (!isChecked) { + textSmsTemplate.setText("{{来源号码}}\n{{短信内容}}\n{{卡槽信息}}\n{{接收时间}}\n{{设备名称}}"); + } + }); + } + + //设置转发信息模版 + private void editSmsTemplate(final EditText textSmsTemplate) { + textSmsTemplate.setText(SettingUtil.getSmsTemplate()); + + textSmsTemplate.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + SettingUtil.setSmsTemplate(textSmsTemplate.getText().toString()); + } + }); + } + + //插入标签 + @SuppressLint("NonConstantResourceId") + public void toInsertLabel(View v) { + EditText textSmsTemplate = findViewById(R.id.text_sms_template); + textSmsTemplate.setFocusable(true); + textSmsTemplate.requestFocus(); + switch (v.getId()) { + case R.id.bt_insert_sender: + textSmsTemplate.append("{{来源号码}}"); + return; + case R.id.bt_insert_content: + textSmsTemplate.append("{{短信内容}}"); + return; + case R.id.bt_insert_extra: + textSmsTemplate.append("{{卡槽信息}}"); + return; + case R.id.bt_insert_time: + textSmsTemplate.append("{{接收时间}}"); + return; + case R.id.bt_insert_device_name: + textSmsTemplate.append("{{设备名称}}"); + return; + default: + } + } + + //恢复初始化配置 + public void initSetting(View view) { + + EditText et_add_extra_device_mark = findViewById(R.id.et_add_extra_device_mark); + et_add_extra_device_mark.setText(""); + editAddExtraDeviceMark(et_add_extra_device_mark); + + EditText et_add_extra_sim1 = findViewById(R.id.et_add_extra_sim1); + et_add_extra_sim1.setText(""); + editAddExtraSim1(et_add_extra_sim1); + + EditText et_add_extra_sim2 = findViewById(R.id.et_add_extra_sim2); + et_add_extra_sim2.setText(""); + editAddExtraSim2(et_add_extra_sim2); + + @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_sms_template = findViewById(R.id.switch_sms_template); + switch_sms_template.setChecked(false); + switchSmsTemplate(switch_sms_template); + + EditText textSmsTemplate = findViewById(R.id.text_sms_template); + textSmsTemplate.setText("{{来源号码}}\n{{短信内容}}\n{{卡槽信息}}\n{{接收时间}}\n{{设备名称}}"); + editSmsTemplate(textSmsTemplate); + + } + + public void batterySetting(View view) { + if (KeepAliveUtils.isIgnoreBatteryOptimization(this)) { + Toast.makeText(this, R.string.isIgnored, Toast.LENGTH_SHORT).show(); + } else { + KeepAliveUtils.ignoreBatteryOptimization(this); + } + } + + + /** + * 请求权限 + * + * @param view 控件 + */ + public void requestPermission(View view) { + if (!isNLServiceEnabled()) { + Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); + startActivityForResult(intent, REQUEST_CODE); + } else { + showMsg("通知服务已开启"); + toggleNotificationListenerService(); + } + } + + /** + * 是否启用通知监听服务 + * + * @return boolean + */ + public boolean isNLServiceEnabled() { + Set packageNames = NotificationManagerCompat.getEnabledListenerPackages(this); + return packageNames.contains(getPackageName()); + } + + /** + * 切换通知监听器服务 + */ + public void toggleNotificationListenerService() { + PackageManager pm = getPackageManager(); + pm.setComponentEnabledSetting(new ComponentName(getApplicationContext(), NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + + pm.setComponentEnabledSetting(new ComponentName(getApplicationContext(), NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE) { + if (isNLServiceEnabled()) { + showMsg("通知服务已开启"); + toggleNotificationListenerService(); + } else { + showMsg("通知服务未开启"); + } + } + } + + + private void showMsg(String msg) { + Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + } + +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyHelper.java b/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyHelper.java new file mode 100644 index 00000000..019bced3 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyHelper.java @@ -0,0 +1,76 @@ +package com.idormy.sms.forwarder.notify; + +import android.service.notification.StatusBarNotification; + +public class NotifyHelper { + + private static NotifyHelper instance; + + public static final int N_MESSAGE = 0; + public static final int N_CALL = 1; + public static final int N_QQ = 2; + public static final int N_WX = 3; + + private NotifyListener notifyListener; + + public static NotifyHelper getInstance() { + if (instance == null) { + instance = new NotifyHelper(); + } + return instance; + } + + /** + * 收到消息 + * + * @param type 消息类型 + */ + public void onReceive(int type) { + if (notifyListener != null) { + notifyListener.onReceiveMessage(type); + } + + } + + /** + * 收到消息 + * + * @param sbn 状态栏通知 + */ + public void onReceive(StatusBarNotification sbn) { + if (notifyListener != null) { + notifyListener.onReceiveMessage(sbn); + } + } + + /** + * 移除消息 + * + * @param type 消息类型 + */ + public void onRemoved(int type) { + if (notifyListener != null) { + notifyListener.onRemovedMessage(type); + } + } + + /** + * 移除消息 + * + * @param sbn 状态栏通知 + */ + public void onRemoved(StatusBarNotification sbn) { + if (notifyListener != null) { + notifyListener.onRemovedMessage(sbn); + } + } + + /** + * 设置回调方法 + * + * @param notifyListener 通知监听 + */ + public void setNotifyListener(NotifyListener notifyListener) { + this.notifyListener = notifyListener; + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyListener.java b/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyListener.java new file mode 100644 index 00000000..c35f862d --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/notify/NotifyListener.java @@ -0,0 +1,34 @@ +package com.idormy.sms.forwarder.notify; + +import android.service.notification.StatusBarNotification; + +public interface NotifyListener { + + /** + * 接收到通知栏消息 + * + * @param type + */ + void onReceiveMessage(int type); + + /** + * 移除掉通知栏消息 + * + * @param type + */ + void onRemovedMessage(int type); + + /** + * 接收到通知栏消息 + * + * @param sbn + */ + void onReceiveMessage(StatusBarNotification sbn); + + /** + * 移除掉通知栏消息 + * + * @param sbn + */ + void onRemovedMessage(StatusBarNotification sbn); +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java b/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java index c8e5d4ad..31ff28ed 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java +++ b/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java @@ -76,7 +76,7 @@ public class SendUtil { public static void sendMsgByRuleModelSenderId(final Handler handError, RuleModel ruleModel, SmsVo smsVo, Long senderId) throws Exception { if (senderId == null) { - throw new Exception("先新建并选择发送方"); + throw new Exception("先新建并选择发送通道"); } String testSim = smsVo.getSimInfo().substring(0, 4); @@ -92,7 +92,7 @@ public class SendUtil { List senderModels = SenderUtil.getSender(senderId, null); if (senderModels.isEmpty()) { - throw new Exception("未找到发送方"); + throw new Exception("未找到发送通道"); } for (SenderModel senderModel : senderModels diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.java b/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.java index 6e790e23..0a5aaf4c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.java +++ b/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.java @@ -1,111 +1,109 @@ -package com.idormy.sms.forwarder.service; - -import android.annotation.SuppressLint; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.os.IBinder; -import android.util.Log; - -import java.text.SimpleDateFormat; - -@SuppressWarnings("deprecation") -public class BatteryService extends Service { - - private static final String TAG = "BatteryReceiver"; - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - Log.i(TAG, "onCreate--------------"); - IntentFilter batteryFilter = new IntentFilter(); - batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - registerReceiver(batteryReceiver, batteryFilter); - } - - @Override - public void onStart(Intent intent, int startId) { - super.onStart(intent, startId); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.i(TAG, "onStartCommand--------------"); - return Service.START_STICKY; //保证service不被杀死 - } - - @Override - public void onDestroy() { - Log.i(TAG, "onDestroy--------------"); - super.onDestroy(); - this.unregisterReceiver(batteryReceiver); - - } - - // 接收电池信息更新的广播 - private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() { - @SuppressWarnings("unused") - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "BatteryReceiver--------------"); - String action = intent.getAction(); - Log.i(TAG, " 0 action:" + action); - Log.i(TAG, "ACTION_BATTERY_CHANGED"); - int status = intent.getIntExtra("status", 0); - int health = intent.getIntExtra("health", 0); - boolean present = intent.getBooleanExtra("present", false); - int level = intent.getIntExtra("level", 0); - int scale = intent.getIntExtra("scale", 0); - int icon_small = intent.getIntExtra("icon-small", 0); - int plugged = intent.getIntExtra("plugged", 0); - int voltage = intent.getIntExtra("voltage", 0); - int temperature = intent.getIntExtra("temperature", 0); - String technology = intent.getStringExtra("technology"); - - String statusString = ""; - switch (status) { - case BatteryManager.BATTERY_STATUS_UNKNOWN: - statusString = "unknown"; - break; - case BatteryManager.BATTERY_STATUS_CHARGING: - statusString = "charging"; - break; - case BatteryManager.BATTERY_STATUS_DISCHARGING: - statusString = "discharging"; - break; - case BatteryManager.BATTERY_STATUS_NOT_CHARGING: - statusString = "not charging"; - break; - case BatteryManager.BATTERY_STATUS_FULL: - statusString = "full"; - break; - } - String acString = ""; - - switch (plugged) { - case BatteryManager.BATTERY_PLUGGED_AC: - acString = "plugged ac"; - break; - case BatteryManager.BATTERY_PLUGGED_USB: - acString = "plugged usb"; - break; - } - - @SuppressLint("SimpleDateFormat") SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS "); - String date = sDateFormat.format(new java.util.Date()); - - Log.i(TAG, "battery: date=" + date + ",status " + statusString - + ",level=" + level + ",scale=" + scale - + ",voltage=" + voltage + ",acString=" + acString); - - } - }; -} +package com.idormy.sms.forwarder.service; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.IBinder; +import android.util.Log; + +import java.text.SimpleDateFormat; + +@SuppressWarnings("deprecation") +public class BatteryService extends Service { + + private static final String TAG = "BatteryReceiver"; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + Log.i(TAG, "onCreate--------------"); + IntentFilter batteryFilter = new IntentFilter(); + batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + registerReceiver(batteryReceiver, batteryFilter); + } + + @Override + public void onStart(Intent intent, int startId) { + super.onStart(intent, startId); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.i(TAG, "onStartCommand--------------"); + return Service.START_STICKY; //保证service不被杀死 + } + + @Override + public void onDestroy() { + Log.i(TAG, "onDestroy--------------"); + super.onDestroy(); + this.unregisterReceiver(batteryReceiver); + } + + // 接收电池信息更新的广播 + private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() { + @SuppressWarnings("unused") + @Override + public void onReceive(Context context, Intent intent) { + Log.i(TAG, "BatteryReceiver--------------"); + String action = intent.getAction(); + Log.i(TAG, " 0 action:" + action); + Log.i(TAG, "ACTION_BATTERY_CHANGED"); + int status = intent.getIntExtra("status", 0); + int health = intent.getIntExtra("health", 0); + boolean present = intent.getBooleanExtra("present", false); + int level = intent.getIntExtra("level", 0); + int scale = intent.getIntExtra("scale", 0); + int icon_small = intent.getIntExtra("icon-small", 0); + int plugged = intent.getIntExtra("plugged", 0); + int voltage = intent.getIntExtra("voltage", 0); + int temperature = intent.getIntExtra("temperature", 0); + String technology = intent.getStringExtra("technology"); + + String statusString = ""; + switch (status) { + case BatteryManager.BATTERY_STATUS_UNKNOWN: + statusString = "unknown"; + break; + case BatteryManager.BATTERY_STATUS_CHARGING: + statusString = "charging"; + break; + case BatteryManager.BATTERY_STATUS_DISCHARGING: + statusString = "discharging"; + break; + case BatteryManager.BATTERY_STATUS_NOT_CHARGING: + statusString = "not charging"; + break; + case BatteryManager.BATTERY_STATUS_FULL: + statusString = "full"; + break; + } + String acString = ""; + + switch (plugged) { + case BatteryManager.BATTERY_PLUGGED_AC: + acString = "plugged ac"; + break; + case BatteryManager.BATTERY_PLUGGED_USB: + acString = "plugged usb"; + break; + } + + @SuppressLint("SimpleDateFormat") SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS "); + String date = sDateFormat.format(new java.util.Date()); + + Log.i(TAG, "battery: date=" + date + ",status " + statusString + + ",level=" + level + ",scale=" + scale + + ",voltage=" + voltage + ",acString=" + acString); + } + }; +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/FrontService.java b/app/src/main/java/com/idormy/sms/forwarder/service/FrontService.java index 0757aead..5520d250 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/FrontService.java +++ b/app/src/main/java/com/idormy/sms/forwarder/service/FrontService.java @@ -1,142 +1,174 @@ -package com.idormy.sms.forwarder.service; - -import android.annotation.SuppressLint; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.os.Build; -import android.os.IBinder; -import android.util.Log; - -import androidx.annotation.Nullable; - -import com.idormy.sms.forwarder.MainActivity; -import com.idormy.sms.forwarder.MyApplication; -import com.idormy.sms.forwarder.R; -import com.idormy.sms.forwarder.model.vo.SmsVo; -import com.idormy.sms.forwarder.sender.SendUtil; -import com.idormy.sms.forwarder.sender.SenderUtil; -import com.idormy.sms.forwarder.utils.PhoneUtils; -import com.idormy.sms.forwarder.utils.SettingUtil; - -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - - -public class FrontService extends Service { - private static final String TAG = "FrontService"; - private static final String CHANNEL_ONE_ID = "com.idormy.sms.forwarder"; - private static final String CHANNEL_ONE_NAME = "com.idormy.sms.forwarderName"; - - @SuppressLint("IconColors") - @Override - public void onCreate() { - super.onCreate(); - Log.i(TAG, "onCreate"); - Notification.Builder builder = new Notification.Builder(this); - builder.setSmallIcon(R.drawable.ic_forwarder); - //OSUtils.ROM_TYPE romType = OSUtils.getRomType(); - //Log.d(TAG, "onCreate: " + romType); - //if (romType == OSUtils.ROM_TYPE.MIUI_ROM) { - builder.setContentTitle(getString(R.string.app_name)); - //} - builder.setContentText(getString(R.string.notification_content)); - Intent intent = new Intent(this, MainActivity.class); - @SuppressLint("UnspecifiedImmutableFlag") PendingIntent pendingIntent = PendingIntent.getActivity - (this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - builder.setContentIntent(pendingIntent); - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - //修改安卓8.1以上系统报错 - NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN); - notificationChannel.enableLights(false);//如果使用中的设备支持通知灯,则说明此通知通道是否应显示灯 - notificationChannel.setShowBadge(false);//是否显示角标 - notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - manager.createNotificationChannel(notificationChannel); - builder.setChannelId(CHANNEL_ONE_ID); - } - - Notification notification = builder.build(); - startForeground(1, notification); - - //检查权限是否获取 - //PackageManager pm = getPackageManager(); - //PhoneUtils.CheckPermission(pm, this); - - //Android8.1以下尝试启动主界面,以便动态获取权限 - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - // 手机重启,未打开app时,主动获取SIM卡信息 - if (MyApplication.SimInfoList.isEmpty()) { - PhoneUtils.init(this); - MyApplication.SimInfoList = PhoneUtils.getSimMultiInfo(); - } - - // 低电量预警 - final int[] alarmTimes = {0}; //通知次数,只通知2次 - Context context1 = this; - SenderUtil.init(context1); - new Timer().schedule(new TimerTask() { - @Override - public void run() { - int batteryLevel = getBatteryLevel(); - System.out.println("当前剩余电量:" + batteryLevel + "%"); - int batteryLevelAlarm = SettingUtil.getBatteryLevelAlarm(); - if (alarmTimes[0] <= 1 && batteryLevelAlarm > 0 && batteryLevelAlarm <= 100 && (batteryLevel == batteryLevelAlarm || batteryLevel == batteryLevelAlarm - 1)) { - try { - alarmTimes[0] = alarmTimes[0] + 1; - SmsVo smsVo = new SmsVo("88888888", - "当前剩余电量:" + batteryLevel + "%,已经到达低电量预警阈值,请及时充电!", - new Date(), - "低电量预警"); - Log.d(TAG, "send_msg" + smsVo.toString()); - SendUtil.send_msg(context1, smsVo, 1); - } catch (Exception e) { - Log.e(TAG, "getLog e:" + e.getMessage()); - } - } - - if (batteryLevelAlarm > 0 && batteryLevelAlarm <= 100 && batteryLevel > batteryLevelAlarm) { - alarmTimes[0] = 0; - } - } - }, 0, 10000); - } - - @Nullable - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.i(TAG, "flags: " + flags + " startId: " + startId); - return START_STICKY; //保证service不被杀死 - } - - //获取当前电量 - @SuppressLint("ObsoleteSdkInt") - private int getBatteryLevel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE); - return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); - } else { - Intent intent = new ContextWrapper(getApplicationContext()). - registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) / - intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - } - } -} +package com.idormy.sms.forwarder.service; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.BatteryManager; +import android.os.Build; +import android.os.IBinder; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationManagerCompat; + +import com.idormy.sms.forwarder.MainActivity; +import com.idormy.sms.forwarder.MyApplication; +import com.idormy.sms.forwarder.R; +import com.idormy.sms.forwarder.model.vo.SmsVo; +import com.idormy.sms.forwarder.sender.SendUtil; +import com.idormy.sms.forwarder.sender.SenderUtil; +import com.idormy.sms.forwarder.utils.PhoneUtils; +import com.idormy.sms.forwarder.utils.SettingUtil; + +import java.util.Date; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +public class FrontService extends Service { + private static final String TAG = "FrontService"; + private static final String CHANNEL_ONE_ID = "com.idormy.sms.forwarder"; + private static final String CHANNEL_ONE_NAME = "com.idormy.sms.forwarderName"; + private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"; + + @SuppressLint("IconColors") + @Override + public void onCreate() { + super.onCreate(); + Log.i(TAG, "onCreate"); + Notification.Builder builder = new Notification.Builder(this); + builder.setSmallIcon(R.drawable.ic_forwarder); + builder.setContentTitle(getString(R.string.app_name)); + builder.setContentText(getString(R.string.notification_content)); + Intent intent = new Intent(this, MainActivity.class); + @SuppressLint("UnspecifiedImmutableFlag") PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pendingIntent); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + //修改安卓8.1以上系统报错 + NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN); + notificationChannel.enableLights(false);//如果使用中的设备支持通知灯,则说明此通知通道是否应显示灯 + notificationChannel.setShowBadge(false);//是否显示角标 + notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.createNotificationChannel(notificationChannel); + builder.setChannelId(CHANNEL_ONE_ID); + } + + Notification notification = builder.build(); + startForeground(1, notification); + + //检查权限是否获取 + //PackageManager pm = getPackageManager(); + //PhoneUtils.CheckPermission(pm, this); + + //Android8.1以下尝试启动主界面,以便动态获取权限 + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + // 手机重启,未打开app时,主动获取SIM卡信息 + if (MyApplication.SimInfoList.isEmpty()) { + PhoneUtils.init(this); + MyApplication.SimInfoList = PhoneUtils.getSimMultiInfo(); + } + + // 低电量预警 + final int[] alarmTimes = {0}; //通知次数,只通知2次 + Context context1 = this; + SenderUtil.init(context1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + int batteryLevel = getBatteryLevel(); + System.out.println("当前剩余电量:" + batteryLevel + "%"); + int batteryLevelAlarm = SettingUtil.getBatteryLevelAlarm(); + if (alarmTimes[0] <= 1 && batteryLevelAlarm > 0 && batteryLevelAlarm <= 100 && (batteryLevel == batteryLevelAlarm || batteryLevel == batteryLevelAlarm - 1)) { + try { + alarmTimes[0] = alarmTimes[0] + 1; + SmsVo smsVo = new SmsVo("88888888", + "当前剩余电量:" + batteryLevel + "%,已经到达低电量预警阈值,请及时充电!", + new Date(), + "低电量预警"); + Log.d(TAG, "send_msg" + smsVo.toString()); + SendUtil.send_msg(context1, smsVo, 1); + } catch (Exception e) { + Log.e(TAG, "getLog e:" + e.getMessage()); + } + } + + if (batteryLevelAlarm > 0 && batteryLevelAlarm <= 100 && batteryLevel > batteryLevelAlarm) { + alarmTimes[0] = 0; + } + } + }, 0, 10000); + + if (!isNotificationListenerServiceEnabled(this)) { + openNotificationAccess(); + } + toggleNotificationListenerService(); + } + + @Override + public void onDestroy() { + //进行自动重启 + Intent intent = new Intent(FrontService.this, FrontService.class); + //重新开启服务 + startService(intent); + stopForeground(true); + super.onDestroy(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + //return super.onStartCommand(intent, flags, startId); + return START_STICKY; //保证service不被杀死 + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + //获取当前电量 + @SuppressLint("ObsoleteSdkInt") + private int getBatteryLevel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE); + return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); + } else { + Intent intent = new ContextWrapper(getApplicationContext()). + registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) / + intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + } + } + + private void toggleNotificationListenerService() { + PackageManager pm = getPackageManager(); + pm.setComponentEnabledSetting(new ComponentName(this, NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + + pm.setComponentEnabledSetting(new ComponentName(this, NotifyService.class), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); + } + + private static boolean isNotificationListenerServiceEnabled(Context context) { + Set packageNames = NotificationManagerCompat.getEnabledListenerPackages(context); + return packageNames.contains(context.getPackageName()); + } + + private void openNotificationAccess() { + startActivity(new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS)); + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/NotifyService.java b/app/src/main/java/com/idormy/sms/forwarder/service/NotifyService.java new file mode 100644 index 00000000..b2dd9515 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/service/NotifyService.java @@ -0,0 +1,52 @@ +package com.idormy.sms.forwarder.service; + +import android.content.ComponentName; +import android.os.Build; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import com.idormy.sms.forwarder.notify.NotifyHelper; + +@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) +public class NotifyService extends NotificationListenerService { + + public static final String TAG = "NotifyService"; + + /** + * 发布通知 + * + * @param sbn 状态栏通知 + */ + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + @Override + public void onNotificationPosted(StatusBarNotification sbn) { + if (sbn.getNotification() == null) return; + Log.d(TAG, sbn.getPackageName()); + NotifyHelper.getInstance().onReceive(sbn); + } + + /** + * 通知已删除 + * + * @param sbn 状态栏通知 + */ + @Override + public void onNotificationRemoved(StatusBarNotification sbn) { + Log.d(TAG, sbn.getPackageName()); + NotifyHelper.getInstance().onRemoved(sbn); + } + + /** + * 监听断开 + */ + @Override + public void onListenerDisconnected() { + Log.d(TAG, "通知侦听器断开连接 - 请求重新绑定"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestRebind(new ComponentName(this, NotificationListenerService.class)); + } + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/PhoneUtils.java b/app/src/main/java/com/idormy/sms/forwarder/utils/PhoneUtils.java index bf81e90c..ea4a3712 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/PhoneUtils.java +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/PhoneUtils.java @@ -545,12 +545,13 @@ public class PhoneUtils { boolean permission_read_call_log = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.READ_CALL_LOG", that.getPackageName())); boolean permission_read_contacts = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.READ_CONTACTS", that.getPackageName())); boolean permission_battery_stats = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.BATTERY_STATS", that.getPackageName())); + boolean permission_bind_notification_listener_service = (PackageManager.PERMISSION_GRANTED == pm.checkPermission("android.permission.BIND_NOTIFICATION_LISTENER_SERVICE", that.getPackageName())); if (!(permission_internet && permission_receive_boot && permission_foreground_service && permission_read_external_storage && permission_write_external_storage && permission_receive_sms && permission_read_sms && permission_send_sms && permission_read_call_log && permission_read_contacts && - permission_read_phone_state && permission_read_phone_numbers && permission_battery_stats)) { + permission_read_phone_state && permission_read_phone_numbers && permission_battery_stats && permission_bind_notification_listener_service)) { ActivityCompat.requestPermissions((Activity) that, new String[]{ Manifest.permission.INTERNET, Manifest.permission.RECEIVE_BOOT_COMPLETED, @@ -565,6 +566,7 @@ public class PhoneUtils { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.FOREGROUND_SERVICE, Manifest.permission.BATTERY_STATS, + Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE, }, 0x01); } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SmsUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SmsUtil.java index ebeb2fff..d4c02749 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/SmsUtil.java +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SmsUtil.java @@ -17,7 +17,6 @@ public class SmsUtil { @SuppressLint("StaticFieldLeak") static Context context; - public static void init(Context context1) { synchronized (hasInit) { if (hasInit) return; diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 70fa8800..059f7a07 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,72 +1,72 @@ - - - - - - - - - - - -