背景介绍
最近在做IM相关的项目,产品需求是用户在线,但用户手机是息屏状态或在解锁页面的情况下收到新的消息,需要在自动点亮屏幕并显示通知样式的内容,点击消息跳转到具体的聊天界面,就像QQ或微信锁屏状态下的消息处理。
解决思路(只贴重要代码)
1.首先需要在锁屏页显示具体的消息内容,需要一个activity,此activity需要亮屏
@Override protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
//| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
setContentView(R.layout.activity_alarmhandler);
initView();
initData();
initEvent();
}
@Override protected void onNewIntent(Intent intent) {
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
handlerMessage(intent);
//if (!powerManager.isScreenOn()) {
//点亮屏幕
PowerManager.WakeLock wl = powerManager.newWakeLock(
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");
wl.acquire(10000);
wl.release();
//}
}
顺便贴下该activity的manifest,对android:taskAffinity不熟悉的同学可以自己找资料了解下,这就不科普了
<!--锁屏页面消息显示 为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task-->
<activity
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:taskAffinity=""
android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
android:name=".ui.AlarmHandlerActivity"/>
2.有新消息到来,在消息处理器中用EventBus将消息告知具体activity;
KeyguardManager mKeyguardManager = (KeyguardManager) IMApp.getInstance().getSystemService(Context.KEYGUARD_SERVICE);
boolean flag = mKeyguardManager.inKeyguardRestrictedInputMode();
if (flag) {
//如果flag为true,表示有两种状态:a、屏幕是黑的 b、目前正处于解锁状态
if (!SettingBean.getInstance().isMessageShowContentEnable()) {
text = IMApp.getInstance()
.getString(R.string.you_has_map_new_msg);
}
String sessionId = wrapper.conversation.getSessionId();
long time = wrapper.conversation.getTime();
ChatType chatType= wrapper.message.getChatType();
MsgData msgData = new MsgData();
msgData.setMsgContainer(text);
msgData.setMsgSender(userName);
msgData.setDate(String.valueOf(time));
msgData.setSessionId(sessionId);
msgData.setChatType(chatType.getValue());
}
3.在MainActivity绑定一个service,当EventBus收到新消息时通过service发送一个本地广播
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (AlarmHandlerService.MyBinder) service;
mBinder.getService().setDataCallback(new AlarmHandlerService.DataCallback() {
@Override public void dataChanged(MsgData msgData) {
Log.d("alrict", "dataChanged: 锁屏收到消息");
}
});
}
@Override public void onServiceDisconnected(ComponentName name) {
mBinder = null;
}
};
Intent intent = new Intent(MainActivity.this, AlarmHandlerService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(SreenOffMsgEvent event) {
Log.d("llw", "onEventMainThread:锁屏状态下收到一条新消息 ");
if (mBinder != null) {
mBinder.setData(event.getMsgData());
}
}
在service中处理
重点代码 intent.addFlags(0x01000000); 为什么要设置这个flag,因为在Android8.0以后,自定义静态广播不可以在后台发送,而加这个flags,可以打破这个限制,这个是硬件编码上的一个flag值,具体没研究过
public class AlarmHandlerService extends Service {
private String TAG = "AlarmHandlerService";
private MsgData data;
private DataCallback dataCallback = null;
private AlarmHandlerReceive mHandlerReceive;
private LocalBroadcastManager mLocalBroadcastManager;
@Override public void onCreate() {
super.onCreate();
}
@Nullable @Override public IBinder onBind(Intent intent) {
IntentFilter filter = new IntentFilter("com.xxx.xxx");
mHandlerReceive = new AlarmHandlerReceive();
//注册本地接收器
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.registerReceiver(mHandlerReceive,filter);
return new MyBinder();
}
public class MyBinder extends Binder {
public AlarmHandlerService getService() {
return AlarmHandlerService.this;
}
public void setData(MsgData data) {
AlarmHandlerService.this.data = data;
Intent intent = new Intent();
intent.setAction("com.xxx.xxx");
intent.putExtra("msgData", data);
intent.addFlags(0x01000000);
mLocalBroadcastManager.sendBroadcast(intent);
}
}
public DataCallback getDataCallback() {
return dataCallback;
}
public void setDataCallback(DataCallback dataCallback) {
this.dataCallback = dataCallback;
}
public interface DataCallback {
void dataChanged(MsgData msgData);
}
@Override public void onDestroy() {
super.onDestroy();
mLocalBroadcastManager.unregisterReceiver(mHandlerReceive);
}
}
4.在receiver中处理
覆盖锁屏显示这个功能在小米手机上需要“锁屏显示”权限,目前只能用户自己开启,无法通过代码申请
public class AlarmHandlerReceive extends BroadcastReceiver {
private String TAG = "AlarmHandler";
@Override public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: 收到广播");
//覆盖锁屏显示这个功能在小米手机上需要“锁屏显示”权限,目前只能用户自己开启,无法通过代码申请
MsgData msgData = intent.getParcelableExtra("msgData");
//拿到锁屏管理者
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (km != null && km.isKeyguardLocked()) { //为true就是锁屏状态下
//启动Activity
Intent alarmIntent = new Intent(context, AlarmHandlerActivity.class);
alarmIntent.putExtra("msgData", msgData);
//activity需要新的任务栈
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmIntent);
}
}
}
5.锁屏界面的代码就是第一点,xml就不贴了
如果有朋友有更好的方案,麻烦告知一声,谢谢!
至此