From ea4b004637fa5545d208747c4cc7efb980187b70 Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Thu, 25 Aug 2022 13:52:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E4=BD=9C=E5=BC=8A?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 + .../outdoor/activity/HomeActivity.java | 234 ++++++++++++++++++ .../outdoor/activity/UserActivity.java | 108 ++++++++ .../fragment/ChargingStationFragment.java | 2 +- .../navinfo/outdoor/http/HttpInterface.java | 2 +- .../navinfo/outdoor/util/PoiSaveUtils.java | 4 +- app/src/main/res/layout/activity_user.xml | 32 ++- app/src/main/res/layout/edit_phone.xml | 65 +++++ 8 files changed, 435 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/layout/edit_phone.xml diff --git a/app/build.gradle b/app/build.gradle index f9703c1..77302d7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,5 +143,7 @@ dependencies { implementation 'com.github.Hu12037102:ImageCompress:2.3.0' //webp 转换 implementation 'com.wanghong.webpnative:webpnative:0.1.0' + // 自动发送邮件 https://github.com/teprinciple/MailSender + implementation 'com.teprinciple:mailsender:1.2.0' } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/outdoor/activity/HomeActivity.java b/app/src/main/java/com/navinfo/outdoor/activity/HomeActivity.java index 28530cc..f65d675 100644 --- a/app/src/main/java/com/navinfo/outdoor/activity/HomeActivity.java +++ b/app/src/main/java/com/navinfo/outdoor/activity/HomeActivity.java @@ -1,6 +1,8 @@ package com.navinfo.outdoor.activity; +import com.github.lazylibrary.util.ShellUtils; import com.google.gson.Gson; +import com.hjq.permissions.XXPermissions; import com.kongzue.dialog.interfaces.OnDialogButtonClickListener; import com.kongzue.dialog.util.BaseDialog; import com.kongzue.dialog.util.DialogSettings; @@ -26,9 +28,13 @@ import androidx.viewpager.widget.ViewPager; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.provider.Settings; import android.util.Log; import android.view.View; import android.widget.Toast; @@ -36,6 +42,8 @@ import android.widget.Toast; import com.navinfo.outdoor.R; import com.google.android.material.tabs.TabLayout; import com.gyf.immersionbar.ImmersionBar; +import com.teprinciple.mailsender.Mail; +import com.teprinciple.mailsender.MailSender; import com.umeng.message.PushAgent; import com.umeng.message.UmengNotificationClickHandler; import com.umeng.message.entity.UMessage; @@ -44,10 +52,23 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.jetbrains.annotations.NotNull; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Objects; +import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; +import io.reactivex.ObservableOnSubscribe; +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; +import io.reactivex.schedulers.Schedulers; + /** * 首页 * tabLayout + viewPager @@ -62,6 +83,8 @@ public class HomeActivity extends BaseActivity { public boolean handleMessage(@NonNull Message msg) { if (msg.what == 0x100) { isBack = false; + } else if (msg.what == 0x101) { + checkMockLocation(); } return false; } @@ -77,6 +100,9 @@ public class HomeActivity extends BaseActivity { super.onCreate(savedInstanceState); if (Constant.USHERED != null) { Constant.initRootFolder(Constant.USHERED); + // 检测用户是否为虚拟定位 + boolean result = handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random())); + Log.d("HomeActivity", "作弊检查:"+result); } else { finish(); } @@ -94,6 +120,7 @@ public class HomeActivity extends BaseActivity { protected void onResume() { super.onResume(); initUM(); +// Toast.makeText(this, "作弊检查:"+result, Toast.LENGTH_SHORT).show(); } private void initUM() { @@ -269,6 +296,213 @@ public class HomeActivity extends BaseActivity { } } + /** + * 检查是否为模拟定位 + * */ + private void checkMockLocation() { + Log.d("HomeActivity", "checkMockLocation开始:"); + Observable.create(new ObservableOnSubscribe>() { + @Override + public void subscribe(ObservableEmitter> emitter) throws Exception { + emitter.onNext(new HashMap<>()); + emitter.onComplete(); + } + }).subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(Schedulers.computation()) + .doOnNext(new Consumer>() { + @Override + public void accept(Map stringBooleanMap) throws Exception { + if (isInstallVirtual(HomeActivity.this)) { + stringBooleanMap.put("安装有虚拟定位软件", true); + }else { + Log.d("HomeActivity", "不安装有虚拟定位软件:"); + } + } + }).doOnNext(new Consumer>() { + @Override + public void accept(Map stringBooleanMap) throws Exception { + if (isOpenMockLocationSetting()) { + stringBooleanMap.put("打开了虚拟定位设置", true); + }else { + Log.d("HomeActivity", "不打开了虚拟定位设置:"); + } + } + }).doOnNext(new Consumer>() { + @Override + public void accept(Map stringBooleanMap) throws Exception { + if (isRunInVirtual()) { + stringBooleanMap.put("程序运行在虚拟环境中", true); + }else { + Log.d("HomeActivity", "不程序运行在虚拟环境中:"); + } + } + }).doOnNext(new Consumer>() { + @Override + public void accept(Map stringBooleanMap) throws Exception { + if (checkPkg(HomeActivity.this)) { + stringBooleanMap.put("存在应用双开", true); + } else { + Log.d("HomeActivity", "不存在应用双开:"); + } + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer>() { + @Override + public void accept(Map stringBooleanMap) throws Exception { + Log.d("HomeActivity", "checkMockLocation结果:"+stringBooleanMap.isEmpty()); + if (!stringBooleanMap.isEmpty()) { + StringBuilder stringBuilder = new StringBuilder("检查到您疑似存在以下违规行为:\n"); + for (String key: stringBooleanMap.keySet() + ) { + stringBuilder.append(key).append("\n"); + } + stringBuilder.append("请及时修正,否则可能会影响到您的收益,如有疑问可联系管理员!"); + + DialogSettings.style = DialogSettings.STYLE.STYLE_IOS; + DialogSettings.cancelable = false; + MessageDialog.show(HomeActivity.this, "提示", stringBuilder, "确定").setOkButton(new OnDialogButtonClickListener() { + @Override + public boolean onClick(BaseDialog baseDialog, View v) { + // 将违规行为通知给运营人员 + // 创建邮箱 + Mail mail = new Mail(); + mail.setMailServerHost("smtp.163.com"); + mail.setMailServerPort("25"); + mail.setFromAddress("xiaoyan159@163.com"); + mail.setPassword("YGPSXLMRPMADRHPS"); + ArrayList toAddressList = new ArrayList<>(); + toAddressList.add("xiaoyan159@qq.com"); + mail.setToAddress(toAddressList); + mail.setSubject("疑似违规记录"); + mail.setContent(stringBuilder.append("用户名:").append(Constant.USER_NAME).append("\n") + .append("身份证号:").append(Constant.ID_NUMBER).append("\n") + .append("姓名:").append(Constant.NAME).append("\n") + .append("手机号:").append(Constant.MOBILE).toString()); +// mail.attachFiles = arrayListOf(file); + + // 发送邮箱 + MailSender.getInstance().sendMail(mail, new MailSender.OnMailSendListener() { + @Override + public void onSuccess() { + // 发送成功,无需再报告 + } + + @Override + public void onError(@NonNull Throwable throwable) { + handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random())); + } + }); + baseDialog.doDismiss(); + return false; + } + }); + } else { + handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random())); + } + } + }); + } + + private boolean isInstallVirtual(Context context) { + Map packageNames = getVirtualPackageNames(); + PackageManager packageManager = context.getPackageManager(); + List pinfo = packageManager.getInstalledPackages(0); + for (int i = 0; i < pinfo.size(); i++) { + if (packageNames.get(pinfo.get(i).packageName) != null) { + return true; + } + } + return false; + } + + private Map getVirtualPackageNames() { + Map packageNames = new HashMap<>(); + packageNames.put("com.lerist.fakelocation", "com.lerist.fakelocation");// Fake-location虚拟定位 + packageNames.put("top.a1024bytes.mockloc.ca.pro", "top.a1024bytes.mockloc.ca.pro");// 天下任我行 + packageNames.put("com.qgwapp.shadowside", "com.qgwapp.shadowside");// 任我行免ROOT + packageNames.put("net.superal", "net.superal");// 超级神行者 + packageNames.put("com.deniu.daniu", "com.deniu.daniu");// 大牛 + packageNames.put("com.deniu.multi", "com.deniu.multi");// 大牛助手 + packageNames.put("com.txy.anywhere", "com.txy.anywhere");// 天下游 + packageNames.put("de.robv.android.xposed.installer", "de.robv.android.xposed.installer");// Xposed + packageNames.put("github.tornaco.xposedmoduletest", "github.tornaco.xposedmoduletest");// 应用管理Xposed + return packageNames; + } + + /** + * 是否开启虚拟定位设置 + * */ + private boolean isOpenMockLocationSetting() { + return Settings.Secure.getInt(getContentResolver(),Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0; + } + + private boolean isRunInVirtual() { + // 获取当前应用的uid + String filter = getUid(this); + ShellUtils.CommandResult commandResult = ShellUtils.execCommand("ps", false); + Log.d("HomeActivity: commandResult", commandResult.errorMsg+":::"+commandResult.successMsg+":::"+commandResult.result); + if (commandResult==null&&commandResult.successMsg==null) { + return false; + } + String result = commandResult.successMsg; + if (result == null || result.isEmpty()) { + return false; + } + String[] lines = result.split("\n"); + if (lines == null || lines.length <= 0) { + return false; + } + int exitDirCount = 0; + for (int i = 0; i < lines.length; i++) { + if (lines[i].contains(filter)) { + int pkgStartIndex = lines[i].lastIndexOf(" "); + String processName = lines[i].substring(pkgStartIndex <= 0 + ? 0 : pkgStartIndex + 1, lines[i].length()); + File dataFile = new File(String.format("/data/data/%s", + processName, Locale.CHINA)); + if (dataFile.exists()) { + exitDirCount++; + } + } + } + return exitDirCount > 1; + } + + /** + * 应用列表检查,防止应用多开 + * */ + private boolean checkPkg(Context context) { + try { + if (context == null) { + return false; + } + int count = 0; + String packageName = context.getPackageName(); + PackageManager pm = context.getPackageManager(); + List pkgs = pm.getInstalledPackages(0); + for (PackageInfo info : pkgs) { + if (packageName.equals(info.packageName)) { + count++; + } + } + return count > 1; + } catch (Exception ignore) {} + return false; + } + + private String getUid(Context context) { + String uid = ""; + try { + PackageManager pm = context.getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo("com.navinfo.outdoor", PackageManager.GET_META_DATA); + uid = String.valueOf(ai.uid); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return uid; + } + @Override public void onBackPressed() { if (!BackHandlerHelper.handleBackPress(this)) { diff --git a/app/src/main/java/com/navinfo/outdoor/activity/UserActivity.java b/app/src/main/java/com/navinfo/outdoor/activity/UserActivity.java index 98ad00d..f0b6e56 100644 --- a/app/src/main/java/com/navinfo/outdoor/activity/UserActivity.java +++ b/app/src/main/java/com/navinfo/outdoor/activity/UserActivity.java @@ -1,10 +1,12 @@ package com.navinfo.outdoor.activity; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; +import android.os.CountDownTimer; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -23,6 +25,8 @@ import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.kongzue.dialog.interfaces.OnDialogButtonClickListener; import com.kongzue.dialog.util.BaseDialog; +import com.kongzue.dialog.util.DialogSettings; +import com.kongzue.dialog.v3.CustomDialog; import com.kongzue.dialog.v3.MessageDialog; import com.lzy.okgo.model.HttpParams; import com.lzy.okgo.model.Progress; @@ -31,6 +35,7 @@ import com.navinfo.outdoor.api.Constant; import com.navinfo.outdoor.base.BaseActivity; import com.navinfo.outdoor.bean.CityBean; import com.navinfo.outdoor.bean.JsonBean; +import com.navinfo.outdoor.bean.MessageCodeBean; import com.navinfo.outdoor.bean.UserBean; import com.navinfo.outdoor.http.Callback; import com.navinfo.outdoor.http.HttpInterface; @@ -68,6 +73,9 @@ public class UserActivity extends BaseActivity implements View.OnClickListener { private StringBuilder userBuilder; private String region_text; private SharedPreferences spNavinfo; + private Button btnPhoneEdit; + private String sessionId; + private CountDownTimer timer; @Override protected int getLayout() { @@ -124,6 +132,8 @@ public class UserActivity extends BaseActivity implements View.OnClickListener { etPhone = findViewById(R.id.et_phone); etPhone.setEnabled(false); etPhone.setOnClickListener(this); + btnPhoneEdit = findViewById(R.id.btn_phone_edit); + btnPhoneEdit.setOnClickListener(this); etQq = findViewById(R.id.edit_qq); etQq.setOnClickListener(this); etMailbox = findViewById(R.id.edit_mailbox); @@ -204,9 +214,107 @@ public class UserActivity extends BaseActivity implements View.OnClickListener { userBuilder.append(TimestampUtil.time()).append(",").append("点击了微信 去提交的按钮 ,"); ToastUtils.Message(UserActivity.this,"此功能未开通"); break; + case R.id.btn_phone_edit: + // 用户修改手机号 + DialogSettings.style = DialogSettings.STYLE.STYLE_IOS; + DialogSettings.cancelable = false; + CustomDialog.show(UserActivity.this, R.layout.edit_phone, new CustomDialog.OnBindView() { + @Override + public void onBind(CustomDialog dialog, View v) { + EditText edtPhoneNew = v.findViewById(R.id.edt_phone_new); + EditText edtConfirmCode = v.findViewById(R.id.edt_phone_confirm_code); + TextView btnConfirmCode = v.findViewById(R.id.tv_confirm_code); + Button btnFinish = v.findViewById(R.id.btm_finish); + btnConfirmCode.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String newPhone=edtPhoneNew.getText().toString(); + if (newPhone.length()!=11 || !newPhone.startsWith("1")) { + Toast.makeText(UserActivity.this, "请检查手机号是否正确!", Toast.LENGTH_SHORT).show(); + return; + } + if (newPhone.equals(Constant.MOBILE)) { + Toast.makeText(UserActivity.this, "与原有手机号相同!", Toast.LENGTH_SHORT).show(); + return; + } + // 发送请求拉取新的验证码 + getConfirmCode(UserActivity.this, newPhone, btnConfirmCode); + } + }); + btnFinish.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 发送修改手机号请求 + + } + }); + } + }); + break; } } + private void getConfirmCode(Activity context, String phone, TextView btnPhoneConfirmCode) { + HttpParams httpParams = new HttpParams(); + httpParams.put("mobile", phone); + httpParams.put("type", 3); + showLoadingDialog(); + OkGoBuilder okGoBuilder = OkGoBuilder.getInstance() + .time(30) + .Builder(context) + .url(HttpInterface.USER_MESSAGE) + .cls(MessageCodeBean.class) + .token(null) + .params(httpParams); + okGoBuilder.getRequest(new Callback() { + @Override + public void onSuccess(MessageCodeBean response, int id) { + dismissLoadingDialog(); + if (response.getCode() == 200) { + sessionId = response.getBody(); + registerNote(btnPhoneConfirmCode); + ToastUtils.Message(context, "验证码已发送"); + } else { + ToastUtils.Message(context, response.getMessage()); + } + } + + @Override + public void onError(Throwable e, int id) { + dismissLoadingDialog(); + String message = e.getMessage(); + assert message != null; + if (message.equals("timeout") || message.equals("Read time out")) { + ToastUtils.Message(context, "请求超时"); + } else { + ToastUtils.Message(context, message); + } + } + + }); + } + + private void registerNote(TextView btnConfirm) { + if (timer != null) { + timer.cancel(); + timer = null; + } + btnConfirm.setEnabled(false); + timer = new CountDownTimer(60 * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + btnConfirm.setText(millisUntilFinished / 1000 + "秒后重新获取验证码"); + } + + @Override + public void onFinish() { + btnConfirm.setEnabled(true); + btnConfirm.setText("重新获取"); + } + }; + timer.start(); + } + private void netWork() { userBuilder.append(TimestampUtil.time()).append(",").append("点击了保存的按钮 ,"); String userphone = etPhone.getText().toString().trim(); diff --git a/app/src/main/java/com/navinfo/outdoor/fragment/ChargingStationFragment.java b/app/src/main/java/com/navinfo/outdoor/fragment/ChargingStationFragment.java index ddc0e5c..93b7de4 100644 --- a/app/src/main/java/com/navinfo/outdoor/fragment/ChargingStationFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/fragment/ChargingStationFragment.java @@ -1500,7 +1500,7 @@ public class ChargingStationFragment extends BaseDrawerFragment implements View. getActivity().runOnUiThread(new Runnable() { @Override public void run() { - ToastUtils.Message(getActivity(), taskNameBean.getMessage()); + ToastUtils.Message(getActivity(), taskNameBean.getMessage()+""); editNameContent.setTextColor(Color.RED); btnSaveLocal.setEnabled(false); btnUploading.setEnabled(false); diff --git a/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java b/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java index 9ed77b3..e9e9f93 100644 --- a/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java +++ b/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java @@ -64,7 +64,7 @@ public class HttpInterface { ///m4/user/user/register public static String USER_REGISTER = IP + USER_PATH + "user/register";//注册接口 ///m4/user/ phone/message - public static String USER_MESSAGE = IP + USER_PATH + "phone/message";//获取验证码 type 1:注册获取 2:更新 + public static String USER_MESSAGE = IP + USER_PATH + "phone/message";//获取验证码 type 1:注册获取 2:更新 3: 修改手机号 ///m4/user/user/forgetPassword public static String USER_FORGET_PASSWORD = IP + USER_PATH + "user/forgetPassword";//忘记密码 diff --git a/app/src/main/java/com/navinfo/outdoor/util/PoiSaveUtils.java b/app/src/main/java/com/navinfo/outdoor/util/PoiSaveUtils.java index ed2c9ec..d9a9a8f 100644 --- a/app/src/main/java/com/navinfo/outdoor/util/PoiSaveUtils.java +++ b/app/src/main/java/com/navinfo/outdoor/util/PoiSaveUtils.java @@ -438,8 +438,8 @@ public class PoiSaveUtils { if (execute.code() != 200) { return execute.code(); } - if (execute.body().string() != null) { - String string = execute.body().string(); + String string = execute.body().string(); + if (string != null) { Gson gson = new Gson(); ChargingPileSaveBean chargingPileSaveBean = gson.fromJson(string, ChargingPileSaveBean.class); if (chargingPileSaveBean.getCode() != 200) { diff --git a/app/src/main/res/layout/activity_user.xml b/app/src/main/res/layout/activity_user.xml index 012228d..2884b49 100644 --- a/app/src/main/res/layout/activity_user.xml +++ b/app/src/main/res/layout/activity_user.xml @@ -67,6 +67,7 @@ android:layout_marginStart="20dp" android:layout_centerVertical="true" style="@style/user_text_style" /> + + \ No newline at end of file