435 lines
16 KiB
Java
435 lines
16 KiB
Java
package com.xwad.os.service;
|
||
|
||
import android.app.NotificationChannel;
|
||
import android.app.NotificationManager;
|
||
import android.app.PendingIntent;
|
||
import android.app.Service;
|
||
import android.content.BroadcastReceiver;
|
||
import android.content.Context;
|
||
import android.content.Intent;
|
||
import android.content.IntentFilter;
|
||
import android.os.Binder;
|
||
import android.os.Build;
|
||
import android.os.IBinder;
|
||
import android.text.TextUtils;
|
||
import android.util.Log;
|
||
|
||
import androidx.annotation.Nullable;
|
||
import androidx.core.app.NotificationCompat;
|
||
import androidx.core.app.NotificationManagerCompat;
|
||
|
||
import com.blankj.utilcode.util.NetworkUtils;
|
||
import com.google.gson.JsonObject;
|
||
import com.tencent.mmkv.MMKV;
|
||
import com.xwad.os.BuildConfig;
|
||
import com.xwad.os.R;
|
||
import com.xwad.os.activity.main.MainActivity;
|
||
import com.xwad.os.config.CommonConfig;
|
||
import com.xwad.os.manager.RemoteManager;
|
||
import com.xwad.os.utils.ActivationUtil;
|
||
import com.xwad.os.utils.LenovoCsdkUtil;
|
||
import com.xwad.os.utils.Utils;
|
||
import com.xwad.os.websocket.JWebSocketClient;
|
||
|
||
import org.java_websocket.handshake.ServerHandshake;
|
||
|
||
import java.net.URI;
|
||
import java.util.concurrent.TimeUnit;
|
||
|
||
import io.reactivex.rxjava3.core.Observable;
|
||
import io.reactivex.rxjava3.disposables.Disposable;
|
||
import io.reactivex.rxjava3.functions.Consumer;
|
||
|
||
/**
|
||
* 【有道云笔记】学生项目-用户端websocket对接.md
|
||
* https://note.youdao.com/s/Pbv87efV
|
||
* <p>
|
||
* 【有道云笔记】学生项目-设备端websocket对接.md
|
||
* https://note.youdao.com/s/Ea0tebj8
|
||
* <p>
|
||
* 【有道云笔记】学生项目-管理端websocket对接.md
|
||
* https://note.youdao.com/s/MazEq49Q
|
||
* <p>
|
||
* 老人在线websocket重构了,按照这个重新对接,跟之前售后差不多是一样的。
|
||
* <p>
|
||
* 1.设备未激活 不链接websocket 形成不了关联,设备激活后,才链接websocket
|
||
* 2.已激活的设备,设备若已链接websocket,用户确认绑定后,断开websocket 等待5秒 再重新链接websocket 以刷新用户关联
|
||
* 3.设备用户解除绑定后,断开websocket 等待5秒 再重新链接websocket 以刷新用户关联
|
||
*/
|
||
public class SocketService extends Service implements NetworkUtils.OnNetworkStatusChangedListener {
|
||
private static final String TAG = "JWebSocketClientService";
|
||
|
||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||
|
||
public JWebSocketClient mJWebSocketClient;
|
||
// private SocketServiceBinder mBinder = new SocketServiceBinder();
|
||
|
||
@Override
|
||
public void onDisconnected() {
|
||
Log.i(TAG, "网络断开连接");
|
||
}
|
||
|
||
@Override
|
||
public void onConnected(NetworkUtils.NetworkType networkType) {
|
||
Log.i(TAG, "网络已连接");
|
||
}
|
||
|
||
//用于Activity和service通讯
|
||
public class SocketServiceBinder extends Binder {
|
||
public SocketService getService() {
|
||
return SocketService.this;
|
||
}
|
||
}
|
||
|
||
// private ServiceConnection mServiceConnection = new ServiceConnection() {
|
||
// @Override
|
||
// public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||
// Log.e(TAG, "onServiceConnected: componentName = " + componentName);
|
||
// boolean isServiceRunning = ServiceAliveUtils.isServiceAlive(SocketService.this, ManagerService.class.getName());
|
||
// Log.e(TAG, "onServiceConnected: isServiceRunning = " + isServiceRunning);
|
||
// if (!isServiceRunning) {
|
||
// startService(new Intent(SocketService.this, ManagerService.class));
|
||
// }
|
||
// }
|
||
//
|
||
// @Override
|
||
// public void onServiceDisconnected(ComponentName componentName) {
|
||
// Log.e(TAG, "onServiceDisconnected: ");
|
||
// // 断开链接
|
||
// startService(new Intent(SocketService.this, ManagerService.class));
|
||
// // 重新绑定
|
||
// bindService(new Intent(SocketService.this, ManagerService.class), mServiceConnection, Context.BIND_IMPORTANT);
|
||
// }
|
||
// };
|
||
|
||
@Nullable
|
||
@Override
|
||
public IBinder onBind(Intent intent) {
|
||
return null;
|
||
}
|
||
|
||
@Override
|
||
public void onCreate() {
|
||
super.onCreate();
|
||
Log.e(TAG, "onCreate: ");
|
||
|
||
NetworkUtils.registerNetworkStatusChangedListener(this);
|
||
registerScreenLockReceiver();
|
||
registerJxwRegisterRefreshReceiver();
|
||
|
||
if (ActivationUtil.getInstance().isActivation()) {
|
||
//初始化websocket
|
||
initSocketClient();
|
||
startLoop();
|
||
} else {
|
||
Log.e(TAG, "onCreate: 未激活不连接");
|
||
}
|
||
|
||
// boolean isServiceRunning = ServiceAliveUtils.isServiceAlive(this, MainService.class.getName());
|
||
// Log.e(TAG, "onCreate: isServiceRunning = " + isServiceRunning);
|
||
// if (!isServiceRunning) {
|
||
// startService(new Intent(this, MainService.class));
|
||
// }
|
||
// bindService(new Intent(this, ManagerService.class), mServiceConnection, Context.BIND_IMPORTANT);
|
||
|
||
mNotificationManagerCompat = NotificationManagerCompat.from(this);
|
||
createNotificationChannel();
|
||
// showNotification();
|
||
sendSimpleNotification();
|
||
}
|
||
|
||
@Override
|
||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||
Log.e(TAG, "onStartCommand: ");
|
||
return START_STICKY;
|
||
}
|
||
|
||
@Override
|
||
public void onDestroy() {
|
||
super.onDestroy();
|
||
NetworkUtils.unregisterNetworkStatusChangedListener(this);
|
||
dispose();
|
||
closeConnect();
|
||
if (mScreenLockReceiver != null) {
|
||
unregisterReceiver(mScreenLockReceiver);
|
||
}
|
||
if (mJxwRegisterReceiver != null) {
|
||
unregisterReceiver(mJxwRegisterReceiver);
|
||
}
|
||
// unbindService(mServiceConnection);
|
||
}
|
||
|
||
private static final String CHANNEL_ID = "CHANNEL_ID";
|
||
private static final String CHANNEL_NAME = "系统通知";
|
||
private static final String CHANNEL_DESCRIPTION = "学习课堂通知";
|
||
|
||
private void createNotificationChannel() {
|
||
// Create the NotificationChannel, but only on API 26+ because
|
||
// the NotificationChannel class is new and not in the support library
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||
CharSequence name = CHANNEL_NAME;
|
||
String description = CHANNEL_DESCRIPTION;
|
||
int importance = NotificationManager.IMPORTANCE_DEFAULT;
|
||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
|
||
channel.setDescription(description);
|
||
// Register the channel with the system; you can't change the importance
|
||
// or other notification behaviors after this
|
||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||
notificationManager.createNotificationChannel(channel);
|
||
}
|
||
}
|
||
|
||
private NotificationManagerCompat mNotificationManagerCompat;
|
||
private int NotificationID = 1;
|
||
|
||
private void sendSimpleNotification() {
|
||
Intent intent = new Intent(this, MainActivity.class);
|
||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CHANNEL_ID")
|
||
.setSmallIcon(R.mipmap.ic_launcher)
|
||
.setContentTitle("学习课堂正在运行")
|
||
// .setContentText("测试内容")
|
||
.setAutoCancel(false)
|
||
.setShowWhen(false)
|
||
.setContentIntent(pendingIntent)
|
||
.setOngoing(true)
|
||
.setOnlyAlertOnce(true)
|
||
.setPriority(NotificationCompat.PRIORITY_MAX);
|
||
// notificationId is a unique int for each notification that you must define
|
||
// mNotificationManagerCompat.notify(NotificationID, builder.build());
|
||
startForeground(NotificationID, builder.build());
|
||
}
|
||
|
||
private ScreenLockReceiver mScreenLockReceiver;
|
||
|
||
private void registerScreenLockReceiver() {
|
||
if (null == mScreenLockReceiver) {
|
||
mScreenLockReceiver = new ScreenLockReceiver();
|
||
}
|
||
IntentFilter filter = new IntentFilter();
|
||
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
|
||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
|
||
filter.addAction(Intent.ACTION_USER_PRESENT);
|
||
filter.addAction(Intent.ACTION_SHUTDOWN);
|
||
filter.addAction(Intent.ACTION_FACTORY_RESET);
|
||
filter.addAction(Intent.ACTION_MASTER_CLEAR);
|
||
registerReceiver(mScreenLockReceiver, filter);
|
||
}
|
||
|
||
private class ScreenLockReceiver extends BroadcastReceiver {
|
||
@Override
|
||
public void onReceive(Context context, Intent intent) {
|
||
String action = intent.getAction();
|
||
Log.e(TAG, "onReceive:" + action);
|
||
if (TextUtils.isEmpty(action)) {
|
||
Log.e(TAG, "onReceive: is NULL");
|
||
return;
|
||
}
|
||
switch (action) {
|
||
case Intent.ACTION_BOOT_COMPLETED:
|
||
case Intent.ACTION_USER_PRESENT:
|
||
|
||
case Intent.ACTION_SCREEN_ON:
|
||
sendMsgScreen();
|
||
break;
|
||
case Intent.ACTION_SCREEN_OFF:
|
||
case Intent.ACTION_SHUTDOWN:
|
||
case Intent.ACTION_FACTORY_RESET:
|
||
case Intent.ACTION_MASTER_CLEAR:
|
||
sendMsgScreen();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
public static final String JXW_REGISTER_SUCCESS = "com.zzj.regist_success";
|
||
|
||
private JxwRegisterReceiver mJxwRegisterReceiver;
|
||
|
||
private void registerJxwRegisterRefreshReceiver() {
|
||
if (mJxwRegisterReceiver == null) {
|
||
mJxwRegisterReceiver = new JxwRegisterReceiver();
|
||
}
|
||
IntentFilter filter = new IntentFilter();
|
||
filter.addAction(JXW_REGISTER_SUCCESS);
|
||
registerReceiver(mJxwRegisterReceiver, filter);
|
||
}
|
||
|
||
public class JxwRegisterReceiver extends BroadcastReceiver {
|
||
@Override
|
||
public void onReceive(Context context, Intent intent) {
|
||
String action = intent.getAction();
|
||
Log.e("JxwRegisterReceiver", "onReceive: " + action);
|
||
if (JXW_REGISTER_SUCCESS.equals(action)) {
|
||
mMMKV.encode(JXW_REGISTER_SUCCESS, true);
|
||
mMMKV.encode(CommonConfig.UIUI_ACTIVATION_KEY, ActivationUtil.getInstance().ACTIVATED_KEY);
|
||
initSocketClient();
|
||
startLoop();
|
||
}
|
||
}
|
||
}
|
||
|
||
private Disposable mDisposable;
|
||
|
||
private void dispose() {
|
||
if (mDisposable != null && !mDisposable.isDisposed()) {
|
||
mDisposable.dispose();
|
||
mDisposable = null;
|
||
}
|
||
}
|
||
|
||
private void startLoop() {
|
||
if (mDisposable != null && !mDisposable.isDisposed()) {
|
||
mDisposable.dispose();
|
||
mDisposable = null;
|
||
}
|
||
mDisposable = Observable.interval(30, TimeUnit.SECONDS)
|
||
.subscribe(new Consumer<Long>() {
|
||
@Override
|
||
public void accept(Long s) throws Exception {
|
||
Log.d(TAG, "startLoop accept: " + s);
|
||
Log.i(TAG, "心跳包检测websocket连接状态");
|
||
if (!ActivationUtil.getInstance().isActivation()) {
|
||
dispose();
|
||
}
|
||
//每隔一定的时间,对长连接进行一次心跳检测
|
||
if (Utils.isScreenOn(SocketService.this)) {
|
||
if (mJWebSocketClient != null) {
|
||
if (mJWebSocketClient.isOpen()) {
|
||
Log.i(TAG, "websocket已连接");
|
||
sendPingMsg();
|
||
} else if (mJWebSocketClient.isClosed()) {
|
||
Log.i(TAG, "websocket重连中");
|
||
reconnectWs();
|
||
}
|
||
} else {
|
||
//如果client已为空,重新初始化连接
|
||
initSocketClient();
|
||
}
|
||
} else {
|
||
Log.i(TAG, "websocket息屏不重连");
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 初始化websocket连接
|
||
*/
|
||
private void initSocketClient() {
|
||
URI uri = URI.create(BuildConfig.WEBSOCKET_URL + "?sn=" + RemoteManager.getInstance().getSerial());
|
||
mJWebSocketClient = new JWebSocketClient(uri) {
|
||
@Override
|
||
public void onMessage(String message) {
|
||
Log.i(TAG, "onMessage: 收到服务器发来的消息:" + message);
|
||
}
|
||
|
||
@Override
|
||
public void onOpen(ServerHandshake handshakedata) {
|
||
super.onOpen(handshakedata);
|
||
Log.i(TAG, "onOpen: websocket连接成功");
|
||
sendPingMsg();
|
||
}
|
||
|
||
@Override
|
||
public void onClose(int code, String reason, boolean remote) {
|
||
super.onClose(code, reason, remote);
|
||
Log.e(TAG, "onClose: websocket连接关闭:" + reason);
|
||
mJWebSocketClient = null;
|
||
}
|
||
|
||
@Override
|
||
public void onError(Exception ex) {
|
||
super.onError(ex);
|
||
Log.e(TAG, "onError: websocket连接错误:" + ex.getMessage());
|
||
mJWebSocketClient = null;
|
||
}
|
||
};
|
||
connect();
|
||
}
|
||
|
||
/**
|
||
* 连接websocket
|
||
*/
|
||
private void connect() {
|
||
try {
|
||
//connectBlocking多出一个等待操作,会先连接再发送,否则未连接发送会报错
|
||
Log.i(TAG, "connect: websocket连接中");
|
||
mJWebSocketClient.connectBlocking();
|
||
} catch (Exception e) {
|
||
Log.i(TAG, "connect: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 开启重连
|
||
*/
|
||
private void reconnectWs() {
|
||
Log.e(TAG, "reconnectWs: ");
|
||
try {
|
||
Log.i(TAG, "reconnectWs: 开启重连");
|
||
mJWebSocketClient.reconnectBlocking();
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 断开连接
|
||
*/
|
||
private void closeConnect() {
|
||
Log.e(TAG, "closeConnect: ");
|
||
try {
|
||
if (null != mJWebSocketClient) {
|
||
mJWebSocketClient.close();
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
} finally {
|
||
mJWebSocketClient = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送消息
|
||
*/
|
||
public void sendPingMsg() {
|
||
JsonObject jsonObject = new JsonObject();
|
||
jsonObject.addProperty("sn", RemoteManager.getInstance().getSerial());
|
||
jsonObject.addProperty("type", "ping");
|
||
if (null != mJWebSocketClient) {
|
||
Log.i(TAG, "sendPingMsg: 发送的消息:" + jsonObject.toString());
|
||
mJWebSocketClient.send(jsonObject.toString());
|
||
}
|
||
}
|
||
|
||
public void sendMsgScreen() {
|
||
JsonObject jsonObject = new JsonObject();
|
||
jsonObject.addProperty("sn", RemoteManager.getInstance().getSerial());
|
||
if (Utils.isScreenOn(SocketService.this)) {
|
||
jsonObject.addProperty("type", "device_open_screen");
|
||
} else {
|
||
jsonObject.addProperty("type", "device_close_screen");
|
||
//熄屏状态
|
||
}
|
||
if (null != mJWebSocketClient) {
|
||
Log.i(TAG, "sendMsgScreen: 发送的消息" + jsonObject.toString());
|
||
try {
|
||
mJWebSocketClient.send(jsonObject.toString());
|
||
} catch (Exception e) {
|
||
Log.i(TAG, "sendMsgScreen: sendMsg Exception: " + e.getLocalizedMessage());
|
||
}
|
||
} else {
|
||
Log.i(TAG, "sendMsgScreen: 未连接");
|
||
initSocketClient();
|
||
}
|
||
}
|
||
|
||
|
||
}
|