From 8bb3d566c98b6b782818fb03030275294868ceb1 Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Mon, 20 Nov 2023 09:34:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BF=A1=E9=B8=BD?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 12 +- .../outdoor/activity/HomeActivity.java | 62 ++++++- .../com/navinfo/outdoor/api/Constant.java | 8 + .../navinfo/outdoor/api/UserApplication.java | 91 +++++----- .../outdoor/fragment/TreasureFragment.java | 44 ++++- .../navinfo/outdoor/http/HttpInterface.java | 2 + .../outdoor/receiver/MessageReceiver.java | 156 ++++++++++++++++-- .../outdoor/service/ForegroundCoreService.kt | 26 +++ .../navinfo/outdoor/service/ForegroundNF.kt | 83 ++++++++++ .../navinfo/outdoor/util/WhiteListHelper.java | 144 ++++++++++++++++ 11 files changed, 559 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/com/navinfo/outdoor/service/ForegroundCoreService.kt create mode 100644 app/src/main/java/com/navinfo/outdoor/service/ForegroundNF.kt create mode 100644 app/src/main/java/com/navinfo/outdoor/util/WhiteListHelper.java diff --git a/app/build.gradle b/app/build.gradle index fe4365a..aa5f03b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,8 +37,8 @@ android { applicationId "com.navinfo.outdoor" minSdkVersion 24 targetSdkVersion 30 - versionCode 117 - versionName "8.231011-金山云测试版" + versionCode 118 + versionName "8.231110-通用测试版" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ndk { @@ -230,6 +230,6 @@ dependencies { implementation 'com.tencent.jg:jg:1.1' //推送保活库 implementation 'com.github.xuexiangjys.XPush:keeplive:1.0.0' - // Android应用白名单添加 https://github.com/WaseemSabir/BatteryPermissionHelper - implementation 'com.waseemsabir:betterypermissionhelper:1.0.3' +// // Android应用白名单添加 https://github.com/WaseemSabir/BatteryPermissionHelper +// implementation 'com.waseemsabir:betterypermissionhelper:1.0.3' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 92bfda8..021f688 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ - + @@ -51,6 +51,8 @@ + + + + 0) { + if (mTab.getSelectedTabPosition()!=0) { + mTab.getTabAt(0).select(); // 默认选中第一个选项 + } + // 地图定位到指定位置,发送Event + Map map = new HashMap<>(); + map.put("geom", geom); + map.put("zoom", zoom); + Message msg = Message.obtain(); + msg.obj = map; + msg.what = Constant.EVENT_WHAT_NOTIFYCATION_RECOMMAND_TASK; + EventBus.getDefault().post(msg); + } + } else if (intentFrom.equals("normalNotification")) { + String title = intent.getStringExtra(Constant.NOTIFYCATION_TITLE); + String content = intent.getStringExtra(Constant.NOTIFYCATION_CONTENT); + if (title != null && content != null) { + // 显示对话框 + MessageDialog.show(HomeActivity.this, title, content, "确定") + .setCancelable(false); + } + } + } + } } private void initUM() { @@ -182,7 +232,7 @@ public class HomeActivity extends BaseActivity { Log.i("TAGEE", "click dismissNotification: " + msg.getRaw().toString()); } }; - UserApplication.instance.setNotificationClickHandler(notificationClickHandler); +// UserApplication.instance.setNotificationClickHandler(notificationClickHandler); } @Override diff --git a/app/src/main/java/com/navinfo/outdoor/api/Constant.java b/app/src/main/java/com/navinfo/outdoor/api/Constant.java index 2c0c487..a096f1a 100644 --- a/app/src/main/java/com/navinfo/outdoor/api/Constant.java +++ b/app/src/main/java/com/navinfo/outdoor/api/Constant.java @@ -44,6 +44,7 @@ public class Constant { public static String LOG_FOLDER = ROOT_FOLDER + "/log"; public static String GPS_LOG_FOLDER = ROOT_FOLDER + "/gps_log"; public static int TelLength = 0; + public static String PUSH_TOKEN = null; public static Map mockGPSMap; // 是否模拟定位,如果模拟定位,该map不为空 public static void initRootFolder(String userId) { @@ -156,6 +157,7 @@ public class Constant { public static final int EVENT_WHAT_START_DRAW_LINE=63;// 开始绘制参考线 public static final int EVENT_WHAT_FINISH_DRAW_LINE=64;// 完成绘制参考线 public static final int SWITCH_RECORFER_ITEM=65;//记录界面请求数据提醒 + public static final int EVENT_WHAT_NOTIFYCATION_RECOMMAND_TASK=66;//记录界面请求数据提醒 public static final String INTENT_POI_VIDEO_TYPE = "poi_video_type"; public static int NUMBER = 200; //任务个数 public static int LIMIT_TYPE = -1; //权限类型,普通任务-0,专属任务-1 @@ -282,4 +284,10 @@ public class Constant { public static NAV_TYPE currentNaviType; // 当前的导航方式 public static boolean NAV_NEAREST_POI = false; + + public static String NOTIFYCATION_INTENT_FROM = "NOTIFYCATION_INTENT_FROM"; + public static String NOTIFYCATION_TASK_GEOM = "NOTIFYCATION_TASK_GEOM"; + public static String NOTIFYCATION_TASK_ZOOM = "NOTIFYCATION_TASK_ZOOM"; + public static String NOTIFYCATION_TITLE = "NOTIFYCATION_TITLE"; + public static String NOTIFYCATION_CONTENT = "NOTIFYCATION_CONTENT"; } diff --git a/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java b/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java index b841cf3..d48fa05 100644 --- a/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java +++ b/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java @@ -29,12 +29,6 @@ import com.tencent.map.navi.TencentNavi; import com.tencent.navi.surport.utils.DeviceUtils; import com.tencent.tencentmap.mapsdk.maps.TencentMapInitializer; import com.umeng.commonsdk.UMConfigure; -import com.umeng.message.IUmengRegisterCallback; -import com.umeng.message.MsgConstant; -import com.umeng.message.PushAgent; -import com.umeng.message.UmengMessageHandler; -import com.umeng.message.UmengNotificationClickHandler; -import com.umeng.message.entity.UMessage; import com.umeng.umcrash.UMCrash; import com.umeng.umcrash.UMCrashCallback; @@ -50,7 +44,7 @@ import okhttp3.OkHttpClient; public class UserApplication extends Application { public static UserApplication userApplication; public static ExecutorService fixedThreadPool; - public static PushAgent instance; +// public static PushAgent instance; @Override public void onCreate() { @@ -80,7 +74,8 @@ public class UserApplication extends Application { @Override public void onSuccess(Object data, int flag) { //token在设备卸载重装的时候有可能会变 - Log.d("TPush", "注册成功,设备token为:" + data); +// Log.d("TPush", "注册成功,设备token为:" + data); + // 推送注册成功,将当前用户token上传给服务器 } @@ -107,49 +102,49 @@ public class UserApplication extends Application { return "注册友盟异常查看功能"; } }); - instance = PushAgent.getInstance(this); - instance.register(new IUmengRegisterCallback() { - @Override - public void onSuccess(String s) { - //注册成功会返回deviceToken deviceToken是推送消息的唯一标志 - Constant.DEVICE_TOKEN = s; - Log.i("TAGEE", "Success 注册成功:deviceToken:--> " + Constant.DEVICE_TOKEN); - } - - @Override - public void onFailure(String s, String s1) { - Log.e("TAGEE", "Failure 注册失败:--> " + "code:" + s + ", desc:" + s1); - } - }); - instance.onAppStart(); - UmengMessageHandler msgHandler = new UmengMessageHandler() { - //处理通知栏消息 - @Override - public void dealWithNotificationMessage(Context context, UMessage msg) { - super.dealWithNotificationMessage(context, msg); - Log.i("TAGEE", "dealWithNotificationMessage:" + msg.getRaw().toString()); - Constant.NOTIFICATION=msg.getRaw().toString(); - } - - //自定义通知样式,此方法可以修改通知样式等 - @Override - public Notification getNotification(Context context, UMessage msg) { - Log.i("TAGEE", "getNotification: "+msg.getRaw().toString()); - return super.getNotification(context, msg); - } - - //处理透传消息 - @Override - public void dealWithCustomMessage(Context context, UMessage msg) { - super.dealWithCustomMessage(context, msg); - Log.i("TAGEE", "dealWithCustomMessage:" + msg.getRaw().toString()); - } - }; - instance.setMessageHandler(msgHandler); +// instance = PushAgent.getInstance(this); +// instance.register(new IUmengRegisterCallback() { +// @Override +// public void onSuccess(String s) { +// //注册成功会返回deviceToken deviceToken是推送消息的唯一标志 +// Constant.DEVICE_TOKEN = s; +// Log.i("TAGEE", "Success 注册成功:deviceToken:--> " + Constant.DEVICE_TOKEN); +// } +// +// @Override +// public void onFailure(String s, String s1) { +// Log.e("TAGEE", "Failure 注册失败:--> " + "code:" + s + ", desc:" + s1); +// } +// }); +// instance.onAppStart(); +// UmengMessageHandler msgHandler = new UmengMessageHandler() { +// //处理通知栏消息 +// @Override +// public void dealWithNotificationMessage(Context context, UMessage msg) { +// super.dealWithNotificationMessage(context, msg); +// Log.i("TAGEE", "dealWithNotificationMessage:" + msg.getRaw().toString()); +// Constant.NOTIFICATION=msg.getRaw().toString(); +// } +// +// //自定义通知样式,此方法可以修改通知样式等 +// @Override +// public Notification getNotification(Context context, UMessage msg) { +// Log.i("TAGEE", "getNotification: "+msg.getRaw().toString()); +// return super.getNotification(context, msg); +// } +// +// //处理透传消息 +// @Override +// public void dealWithCustomMessage(Context context, UMessage msg) { +// super.dealWithCustomMessage(context, msg); +// Log.i("TAGEE", "dealWithCustomMessage:" + msg.getRaw().toString()); +// } +// }; +// instance.setMessageHandler(msgHandler); //App处于前台时不显示通知 //instance.setNotificationOnForeground(false); //设置显示通知的数量 - instance.setDisplayNotificationNumber(0); +// instance.setDisplayNotificationNumber(0); //服务端控制声音 //instance.setNotificationPlaySound(MsgConstant.NOTIFICATION_PLAY_SERVER); //通知免打扰时段 diff --git a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java index 8d3c70b..55d0941 100644 --- a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java @@ -78,11 +78,13 @@ import com.navinfo.outdoor.http.OkGoBuilder; import com.navinfo.outdoor.http.UploadCallBack; import com.navinfo.outdoor.room.ChargingPileEntity; import com.navinfo.outdoor.room.PoiEntity; +import com.navinfo.outdoor.util.Base64; import com.navinfo.outdoor.util.FlushTokenUtil; import com.navinfo.outdoor.util.Geohash; import com.navinfo.outdoor.util.GeometryTools; import com.navinfo.outdoor.util.LocationLifeCycle; import com.navinfo.outdoor.util.MapManager; +import com.navinfo.outdoor.util.Md5Util; import com.navinfo.outdoor.util.MyTecentLocationSource; import com.navinfo.outdoor.util.NaviUtils; import com.navinfo.outdoor.util.NetWorkUtils; @@ -285,7 +287,7 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen treasureBuilder.append(TimestampUtil.time()).append(",").append("onFinish-获取到当前位置,"); dismissLoadingDialog(); refreshFilterData(); - //上传用户位置金纬度 + //上传用户位置经纬度 iniUserLocation(); //得到电话区号,电话位数 initPhone(); @@ -293,6 +295,8 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen initUM(); //检查是否有没有填完的页面 initSharePre(); + // 获取最新的推荐任务,如果存在则显示推荐任务按钮 + initRecommandTaskInfo(); } @Override @@ -1180,6 +1184,32 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen } }); } + } else if (data.what == Constant.EVENT_WHAT_NOTIFYCATION_RECOMMAND_TASK) { + // 显示推荐任务 + Map dataMap = (Map) data.obj; + String geom = dataMap.get("geom").toString(); + Geometry geometry = GeometryTools.createGeometry(geom); + int zoom = Integer.parseInt(dataMap.get("zoom").toString()); + // 跳转到该位置 + // 地图中心点位置设置为当前用户所在位置 + CameraUpdate cameraSigma = + CameraUpdateFactory.newCameraPosition(new CameraPosition( + new LatLng(geometry.getCoordinate().y, geometry.getCoordinate().x), //中心点坐标,地图目标经纬度 + zoom, //目标缩放级别 + 0, //目标倾斜角[0.0 ~ 45.0] (垂直地图时为0) + 0)); //目标旋转角 0~360° (正北方为0) + tencentMap.animateCamera(cameraSigma, new TencentMap.CancelableCallback() { + @Override + public void onFinish() { + // 重新刷新数据 + refreshFilterData(); + } + + @Override + public void onCancel() { + + } + }); } } @@ -2031,4 +2061,16 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen removableHashMap.put(geo, markers); } } + + /** + * 获取最新的推荐任务数据 + * */ + private void initRecommandTaskInfo() { + if (Constant.PUSH_TOKEN!=null) { + HttpParams httpParams = new HttpParams(); + httpParams.put("pushId", Constant.PUSH_TOKEN); + long time = System.currentTimeMillis(); + httpParams.put("datetime", time); + } + } } \ No newline at end of file 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 fb7cc7d..2fa6014 100644 --- a/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java +++ b/app/src/main/java/com/navinfo/outdoor/http/HttpInterface.java @@ -64,6 +64,7 @@ public class HttpInterface { public static String EXAM_CONTENT = null;//发现 -能力测评获取试题接口 //172.23.139.4:8002/findAndMessage/1/submitExam public static String EXAM_SUBMIT = null;//发现 -能力测评提交试卷 post + public static String RECOMMAND_TASK = null;//TreasureFragment获取最新的推荐任务信息 post /* 登录 * Path=/m4/userlogin/ @@ -169,6 +170,7 @@ public class HttpInterface { USER_DETAIL_BY_USER_ID = IP + USER_PATH + "user/" + userId + "/getUserDetailByUserid/" + userId; //获取用户信息 //172.21.98.90:9999/m4/user/userGuide/1/insertUserGuide INSERT_USER_GUIDE = IP + USER_PATH + "userGuide/" + userId + "/insertUserGuide";//引导页完成接口 + RECOMMAND_TASK = IP + USER_PATH + "user/" + userId + "/lastRecommandTask";//获取用户推荐信息 /* 发现 * Path=/m4/msgList/ diff --git a/app/src/main/java/com/navinfo/outdoor/receiver/MessageReceiver.java b/app/src/main/java/com/navinfo/outdoor/receiver/MessageReceiver.java index 5ac12bd..439bfe9 100644 --- a/app/src/main/java/com/navinfo/outdoor/receiver/MessageReceiver.java +++ b/app/src/main/java/com/navinfo/outdoor/receiver/MessageReceiver.java @@ -1,11 +1,27 @@ package com.navinfo.outdoor.receiver; +import android.Manifest; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Build; import android.util.Log; import android.widget.Toast; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; + +import com.bumptech.glide.Glide; import com.elvishew.xlog.XLog; +import com.navinfo.outdoor.R; +import com.navinfo.outdoor.activity.HomeActivity; +import com.navinfo.outdoor.api.Constant; import com.tencent.android.tpush.NotificationAction; import com.tencent.android.tpush.XGPushBaseReceiver; import com.tencent.android.tpush.XGPushClickedResult; @@ -16,6 +32,10 @@ import com.tencent.android.tpush.XGPushTextMessage; import org.json.JSONException; import org.json.JSONObject; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + public class MessageReceiver extends XGPushBaseReceiver { public static final String UPDATE_LISTVIEW_ACTION = "com.qq.xgdemo.activity.UPDATE_LISTVIEW"; public static final String TEST_ACTION = "com.qq.xgdemo.activity.TEST_ACTION"; @@ -28,25 +48,126 @@ public class MessageReceiver extends XGPushBaseReceiver { */ @Override public void onTextMessage(Context context, XGPushTextMessage message) { - String text = "onTextMessage:" + message.toString(); - // 获取自定义key-value - String customContent = message.getCustomContent(); - if (customContent != null && customContent.length() != 0) { - try { - JSONObject obj = new JSONObject(customContent); - // key1为前台配置的key - if (!obj.isNull("key")) { - String value = obj.getString("key"); - XLog.d("get custom value:" + value); +// String text = "onTextMessage:" + message.toString(); +// // 获取自定义key-value +// String customContent = message.getCustomContent(); +// if (customContent != null && customContent.length() != 0) { +// try { +// JSONObject obj = new JSONObject(customContent); +// // key1为前台配置的key +// if (!obj.isNull("key")) { +// String value = obj.getString("key"); +// XLog.d("get custom value:" + value); +// } +// // ... +// } catch (JSONException e) { +// e.printStackTrace(); +// } +// } +// // APP自主处理消息的过程... +// XLog.d(text); +// show(context, text); + + // 获取透传信息内容 + String msgContent = message.getContent(); + // 使用json解析msgContent + try { + JSONObject msgJson = new JSONObject(msgContent); + // 获取当前json的id,如果id大于等于0,则根据Content内容尝试展示提示信息 + int id = msgJson.optInt("id", -1); + if (id >= 0) { + int type = msgJson.optInt("type", -1); + if (type == 0) { // 显示推荐任务 + String imgUrl = msgJson.optString("img", ""); + String wkt = msgJson.optString("geom", ""); + int zoom = msgJson.optInt("zoom", 17); + // 获取推荐任务的大图 + try { + Bitmap bigBitmap = Glide.with(context).asBitmap().load(imgUrl).submit().get(16000, TimeUnit.MILLISECONDS); + if (bigBitmap==null) { + bigBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher); + } + if (bigBitmap!=null) { + // 显示notifycation + createNotificationForBigImage(context, + msgJson.optString("title", "推荐任务"), + msgJson.optString("content", "为你准备的推荐任务"), + bigBitmap, wkt, zoom, id); + } + } catch (ExecutionException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (TimeoutException e) { + throw new RuntimeException(e); + } + } else if (type == 1) { + // 显示普通通知 + String title = msgJson.optString("title", "通知"); + String content = msgJson.optString("content", ""); + // 展示普通notification + createNotificationForNormal(context, title, content, id); } - // ... - } catch (JSONException e) { - e.printStackTrace(); + } else { + // id小于0,说明当前没有可推送的任务 + } + } catch (JSONException e) { + throw new RuntimeException(e); } - // APP自主处理消息的过程... - XLog.d(text); - show(context, text); + } + + private void createNotificationForNormal(Context context, String contentTitle, String contentText, int id) { + String mNormalChannelId = "normalNotification"; + String mNormalChannelName = "普通通知"; + NotificationManager mManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(mNormalChannelId, mNormalChannelName, NotificationManager.IMPORTANCE_DEFAULT); + mManager.createNotificationChannel(channel); + } + Intent intent = new Intent(context, HomeActivity.class); + intent.putExtra(Constant.NOTIFYCATION_INTENT_FROM, "normalNotification"); + intent.putExtra(Constant.NOTIFYCATION_TITLE, contentTitle); + intent.putExtra(Constant.NOTIFYCATION_CONTENT, contentText); + PendingIntent pendingIntent = PendingIntent.getActivity(context, id, intent, PendingIntent.FLAG_CANCEL_CURRENT); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, mNormalChannelId) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setStyle(new NotificationCompat.BigTextStyle().bigText(contentText)) + .setSmallIcon(R.mipmap.ic_launcher) + .setSilent(false) + .setAutoCancel(true) + .setContentIntent(pendingIntent) + .addAction(R.mipmap.ic_launcher, "去看看", pendingIntent); + mManager.notify(2, mBuilder.build()); + } + + private void createNotificationForBigImage(Context context, String contentTitle, String contentText, Bitmap bigPic, + String wkt, int zoom, int id) { + String mBigImageChannelId = "recommendTaskId"; + String mBigImageChannelName = "推荐任务"; + NotificationManager mManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(mBigImageChannelId, mBigImageChannelName, NotificationManager.IMPORTANCE_DEFAULT); + mManager.createNotificationChannel(channel); + } + Intent intent = new Intent(context, HomeActivity.class); + intent.putExtra(Constant.NOTIFYCATION_INTENT_FROM, "recommandTask"); + intent.putExtra(Constant.NOTIFYCATION_TASK_GEOM, wkt); + intent.putExtra(Constant.NOTIFYCATION_TASK_ZOOM, zoom); + PendingIntent pendingIntent = PendingIntent.getActivity(context, id, intent, 0); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, mBigImageChannelId) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setStyle(new NotificationCompat.BigPictureStyle().bigPicture(bigPic)) + .setSmallIcon(R.mipmap.ic_launcher) + .setSilent(false) + .setLargeIcon(bigPic) + .setAutoCancel(true) + .setContentIntent(pendingIntent) + .addAction(R.mipmap.ic_launcher, "去看看", pendingIntent); + mManager.notify(1, mBuilder.build()); + // 用户点击该提醒后跳转到主界面,并自动定位到指定位置 } /** @@ -102,6 +223,7 @@ public class MessageReceiver extends XGPushBaseReceiver { // 在这里拿token String token = message.getToken(); text = "注册成功1. token:" + token; + Constant.PUSH_TOKEN =token; } else { text = message + "注册失败,错误码:" + errorCode; } @@ -270,7 +392,7 @@ public class MessageReceiver extends XGPushBaseReceiver { } private void show(Context context, String text) { - Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); +// Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/navinfo/outdoor/service/ForegroundCoreService.kt b/app/src/main/java/com/navinfo/outdoor/service/ForegroundCoreService.kt new file mode 100644 index 0000000..d7d15c8 --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/service/ForegroundCoreService.kt @@ -0,0 +1,26 @@ +package com.navinfo.outdoor.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder + +class ForegroundCoreService : Service() { + override fun onBind(intent: Intent?): IBinder? = null + private val mForegroundNF:ForegroundNF by lazy {ForegroundNF(this)} + override fun onCreate() { + super.onCreate() + mForegroundNF.startForegroundNotification() + } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + if(null == intent){ + //服务被系统kill掉之后重启进来的 + return START_NOT_STICKY + } + mForegroundNF.startForegroundNotification() + return super.onStartCommand(intent, flags, startId) + } + override fun onDestroy() { + mForegroundNF.stopForegroundNotification() + super.onDestroy() + } +} diff --git a/app/src/main/java/com/navinfo/outdoor/service/ForegroundNF.kt b/app/src/main/java/com/navinfo/outdoor/service/ForegroundNF.kt new file mode 100644 index 0000000..c2389ee --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/service/ForegroundNF.kt @@ -0,0 +1,83 @@ +package com.navinfo.outdoor.service + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.os.Build +import androidx.core.app.NotificationCompat +import com.navinfo.outdoor.R +import com.navinfo.outdoor.activity.HomeActivity + +//初始化前台通知,停止前台通知 +class ForegroundNF(private val service: ForegroundCoreService) : ContextWrapper(service) { + companion object { + private const val START_ID = 101 + private const val CHANNEL_ID = "app_foreground_service" + private const val CHANNEL_NAME = "前台保活服务" + } + private var mNotificationManager: NotificationManager? = null + + private var mCompatBuilder: NotificationCompat.Builder?=null + + private val compatBuilder: NotificationCompat.Builder? + get() { + if (mCompatBuilder == null) { + val notificationIntent = Intent(this, HomeActivity::class.java) + notificationIntent.action = Intent.ACTION_MAIN + notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER) + notificationIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + //动作意图 + val pendingIntent = PendingIntent.getActivity( + this, (Math.random() * 10 + 10).toInt(), + notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT + ) + val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this,CHANNEL_ID) + //标题 + notificationBuilder.setContentTitle("地图寻宝3") + //通知内容 + notificationBuilder.setContentText("地图寻宝3正在运行中") + //状态栏显示的小图标 + notificationBuilder.setSmallIcon(R.mipmap.ic_launcher) + //通知内容打开的意图 + notificationBuilder.setContentIntent(pendingIntent) + mCompatBuilder = notificationBuilder + } + return mCompatBuilder + } + + init { + createNotificationChannel() + } + + //创建通知渠道 + private fun createNotificationChannel() { + mNotificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + //针对8.0+系统 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + CHANNEL_NAME, + NotificationManager.IMPORTANCE_LOW + ) + channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC + channel.setShowBadge(false) + mNotificationManager?.createNotificationChannel(channel) + } + } + + //开启前台通知 + fun startForegroundNotification() { + service.startForeground(START_ID, compatBuilder?.build()) + } + + //停止前台服务并清除通知 + fun stopForegroundNotification() { + mNotificationManager?.cancelAll() + service.stopForeground(true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/outdoor/util/WhiteListHelper.java b/app/src/main/java/com/navinfo/outdoor/util/WhiteListHelper.java new file mode 100644 index 0000000..ee40c2a --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/util/WhiteListHelper.java @@ -0,0 +1,144 @@ +package com.navinfo.outdoor.util; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.PowerManager; +import android.provider.Settings; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; + +/** + * Android实现添加到系统白名单的工具类 + * */ +public class WhiteListHelper { + final static String IS_HUAWEI = "isHuawei"; //华为 + final static String IS_XIAOMI = "isXiaomi"; //小米 + final static String IS_OPPO = "isOppo"; //oppo + final static String IS_VIVO = "isVivo"; //vivo + final static String IS_MEIZU = "isMeizu"; //魅族 + final static String IS_SAMSUNG = "isSamsung"; //三星 + final static String IS_LETV = "isLetv"; //乐视 + final static String IS_SMARTISAN = "isSmartisan"; //锤子 + + /** + * 判断当前应用是否在系统白名单内 + * */ + @RequiresApi(Build.VERSION_CODES.M) + public boolean isIgnoringBatteryOptimizations(Context context){ + boolean isIgnoring = false; + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + + if (powerManager != null) + isIgnoring = powerManager.isIgnoringBatteryOptimizations("包名"); + + return isIgnoring; + } + + /** + * 请求系统白名单 + * */ + public void requestIgnoreBatteryOptimizations(Context context){ + try { + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + "com.navinfo.outdoor")); + context.startActivity(intent); + }catch (Exception e){ + e.printStackTrace(); + } + } + + /** + * 跳转到指定应用的首页 + */ + public void showActivity(String packageName,Context context){ + Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); + context.startActivity(intent); + } + /** + * 跳转到指定应用的指定页面 + * */ + public void showActivity(String packageName,String activityDir,Context context){ + Intent intent = new Intent(); + intent.setComponent(new ComponentName(packageName, activityDir)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + //判断手机厂商 + public String checkPhoneFirm(){ + String phoneState = Build.BRAND.toLowerCase(); //获取手机厂商 + if (phoneState.equals("huawei") || phoneState.equals("honor")) + return WhiteListHelper.IS_HUAWEI; + else if (phoneState.equals("xiaomi") && Build.BRAND != null) + return WhiteListHelper.IS_XIAOMI; + else if (phoneState.equals("oppo") && Build.BRAND != null) + return WhiteListHelper.IS_OPPO; + else if (phoneState.equals("vivo") && Build.BRAND != null) + return WhiteListHelper.IS_VIVO; + else if (phoneState.equals("meizu") && Build.BRAND != null) + return WhiteListHelper.IS_MEIZU; + else if (phoneState.equals("samsung") && Build.BRAND != null) + return WhiteListHelper.IS_SAMSUNG; + else if (phoneState.equals("letv") && Build.BRAND != null) + return WhiteListHelper.IS_LETV; + else if (phoneState.equals("smartisan") && Build.BRAND != null) + return WhiteListHelper.IS_SMARTISAN; + + return ""; + } + + //前往设置白名单管理界面 + public void gotoWhiteListSetting(Context context){ + if (checkPhoneFirm().equals(WhiteListHelper.IS_HUAWEI)){ + try { + showActivity("com.huawei.systemmanager","com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity",context); + }catch (Exception e){ + showActivity("com.huawei.systemmanager", + "com.huawei.systemmanager.optimize.bootstart.BootStartActivity",context); + } + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_XIAOMI)){ + showActivity("com.miui.securitycenter", + "com.miui.permcenter.autostart.AutoStartManagementActivity",context); + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_OPPO)){ + //oppo:操作步骤:权限隐私 -> 自启动管理 -> 允许应用自启动 + try { + showActivity("com.coloros.phonemanager",context); + } catch (Exception e) { + try { + showActivity("com.oppo.safe",context); + } catch (Exception e2) { + try { + showActivity("com.coloros.oppoguardelf", context); + } catch (Exception e3) { + showActivity("com.coloros.safecenter", context); + } + } + } + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_VIVO)){ + //vivo:操作步骤:权限管理 -> 自启动 -> 允许应用自启动 + showActivity("com.iqoo.secure", context); + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_MEIZU)){ + //魅族:操作步骤:权限管理 -> 后台管理 -> 点击应用 -> 允许后台运行 + showActivity("com.meizu.safe", context); + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_SAMSUNG)){ + //三星:操作步骤:自动运行应用程序 -> 打开应用开关 -> 电池管理 -> 未监视的应用程序 -> 添加应用 + try { + showActivity("com.samsung.android.sm_cn",context); + } catch (Exception e) { + showActivity("com.samsung.android.sm",context); + } + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_LETV)){ + //乐视:操作步骤:自启动管理 -> 允许应用自启动 + showActivity("com.letv.android.letvsafe","com.letv.android.letvsafe.AutobootManageActivity", context); + }else if (checkPhoneFirm().equals(WhiteListHelper.IS_SMARTISAN)){ + //锤子:操作步骤:权限管理 -> 自启动权限管理 -> 点击应用 -> 允许被系统启动 + showActivity("com.smartisanos.security", context ); + } + } +}