热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android屏幕锁屏弹窗的正确姿势DEMO详解

本文给大家分享android屏幕锁屏弹窗的正确姿势DEMO详解,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起看看吧

在上篇文章给大家介绍了Android程序开发仿新版QQ锁屏下弹窗功能。今天通过本文给大家分享android锁屏弹窗的正确姿势。

最近在做一个关于屏幕锁屏悬浮窗的功能,于是在网上搜索了很多安卓屏幕锁屏的相关资料,鉴于网上的资料比较零碎,所以我在这里进行整理总结。本文将从以下两点对屏幕锁屏进行解析:

1. 如何监听系统屏幕锁屏

2. 如何在锁屏界面弹出悬浮窗

如何监听系统屏幕锁屏

经过总结,监听系统的锁屏可以通过以下两种方式:

1) 代码直接判定

2) 接收广播

1) 代码直接判定

代码判断方式,也有两种方法:

a) 通过PowerManager的isScreenOn方法,代码如下:

PowerManager pm = (PowerManager) 
context.getSystemService(Context.POWER_SERVICE);
//如果为true,则表示屏幕“亮”了,否则屏幕“暗”了。
boolean isScreenOn = pm.isScreenOn();

这里需要解释一下:

屏幕“亮”,表示有两种状态:a、未锁屏 b、目前正处于解锁状态 。这两种状态屏幕都是亮的;

屏幕“暗”,表示目前屏幕是黑的 。

b) 通过KeyguardManager的inKeyguardRestrictedInputMode方法,代码如下:

KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
boolean flag = mKeyguardManager.inKeyguardRestrictedInputMode();

对flag进行一下说明,经过试验,总结为:

如果flag为true,表示有两种状态:a、屏幕是黑的 b、目前正处于锁屏状态 。

如果flag为false,表示目前未锁屏

注明:上面的两种方法,也可以通过反射机制来调用。

反射代码如下:

private static Method mReflectScreenState;
try {
mReflectScreenState = PowerManager.class.getMethod(isScreenOn, new Class[] {});
PowerManager pm = (PowerManager) context.getSystemService(Activity.POWER_SERVICE);
boolean isScreenOn= (Boolean) mReflectScreenState.invoke(pm);
} catch (Exception e) {
e.printStackTrace()
}

2) 接收广播

当安卓系统锁屏或者屏幕亮起,或是屏幕解锁的时候,系统内部都会发送相应的广播,我们只需要对广播进行监听就可以了
注册广播的伪代码如下:

private ScreenBroadcastReceiver mScreenReceiver;
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { 
// 开屏
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 
// 锁屏
} else if (Intent.ACTION_USER_PRESENT.equals(action)) { 
// 解锁
}
}
}
private void startScreenBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
context.registerReceiver(mScreenReceiver, filter);
}

如何在锁屏界面弹出悬浮窗

竟然知道了对于系统屏幕监听的方法,那么接下来就是要在屏幕锁屏的时候,弹出悬浮框了,这个的实现方式有两种:

1) 使用WindowManager

2) 使用Activity

目前情况是,使用这两种方式在真机上都可以实现,如果网友们发现有问题,可以在博客中留言

1) 使用WindowManager

代码如下:

private void init(Context mContext) {
this.mCOntext= mContext;
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
// 更新浮动窗口位置参数 靠边
DisplayMetrics dm = new DisplayMetrics();
// 获取屏幕信息
mWindowManager.getDefaultDisplay().getMetrics(dm);
mScreenWidth = dm.widthPixels;
mScreenHeight = dm.heightPixels;
this.mWmParams = new WindowManager.LayoutParams();
// 设置window type
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mWmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
} else {
mWmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
// 设置图片格式,效果为背景透明
mWmParams.format = PixelFormat.RGBA_8888;
// 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 调整悬浮窗显示的停靠位置为左侧置�?
mWmParams.gravity = Gravity.LEFT | Gravity.TOP;
mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
// 以屏幕左上角为原点,设置x、y初始值,相对于gravity
mWmParams.x = 0;
mWmParams.y = mScreenHeight / 2;
// 设置悬浮窗口长宽数据
mWmParams.width = LayoutParams.WRAP_CONTENT;
mWmParams.height = LayoutParams.WRAP_CONTENT;
addView(createView(mContext));
mWindowManager.addView(this, mWmParams);
mTimer = new Timer();
hide();
}

WindowManager的主要配置就是上面的那些代码,这里需要说明一下,type的类型有如下值:

应用程序窗口。
public static final int FIRST_APPLICATION_WINDOW = 1; 
所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。 
public static final int TYPE_BASE_APPLICATION =1;
普通应用功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。
public static final int TYPE_APPLICATION = 2;
用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。
它用于让系统显示些信息,直到应用程序可以开启自己的窗口。 
public static final int TYPE_APPLICATION_STARTING = 3; 
应用程序窗口结束。
public static final int LAST_APPLICATION_WINDOW = 99;
子窗口。子窗口的Z序和坐标空间都依赖于他们的宿主窗口。
public static final int FIRST_SUB_WINDOW = 1000;
面板窗口,显示于宿主窗口上层。
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
媒体窗口,例如视频。显示于宿主窗口下层。
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1;
应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上)
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2;
对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3;
媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕)
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW +4;
子窗口结束。( End of types of sub-windows )
public static final int LAST_SUB_WINDOW = 1999;
系统窗口。非应用程序创建。
public static final int FIRST_SYSTEM_WINDOW = 2000;
状态栏。只能有一个状态栏;它位于屏幕顶端,其他窗口都位于它下方。
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
搜索栏。只能有一个搜索栏;它位于屏幕上方。
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
public static final int TYPE_PHOnE= FIRST_SYSTEM_WINDOW+2;
系统提示。它总是出现在应用程序窗口之上。
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW +3;
锁屏窗口。
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW +4;
信息窗口。用于显示toast。
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW +5;
系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW +6;
电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。
public static final int TYPE_PRIORITY_PHOnE= FIRST_SYSTEM_WINDOW +7;
系统对话框。(例如音量调节框)。
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW +8;
锁屏时显示的对话框。
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW +9;
系统内部错误提示,显示于所有内容之上。
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW +10;
内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW +11;
内部输入法对话框,显示于当前输入法窗口之上。
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW +12;
墙纸窗口。
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW +13;
状态栏的滑动面板。
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW +14;
系统窗口结束。
public static final int LAST_SYSTEM_WINDOW = 2999;

如果想让悬浮窗在所以锁屏之上,使用TYPE_SYSTEM_ERROR,因为它显示在所有内容之上。

2) 使用Activity

Activity的设置

Activity需要进行以下设置,才可以在锁屏状态下弹窗。
首先是onCreate方法,需要添加4个标志,如下:

protected void onCreate(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); 
// 自己的代码 
} 

四个标志位顾名思义,分别是锁屏状态下显示,解锁,保持屏幕长亮,打开屏幕。这样当Activity启动的时候,它会解锁并亮屏显示。
然后在AndroidManifest.xml文件当中,对该activity的声明需要加上以下属性:

 

而对于布局文件,要显示的view居中,背景透明。由于上面已经设置了背景为壁纸的背景,所以显示的是桌面的背景。如果背景设为默认的白色,则导致弹窗后面是一片白色,看起来很丑。如果背景设置为透明,则弹窗后面会显示出解锁后的界面(即使有锁屏密码,也是会显示解锁后的界面的),一样很影响视觉效果。

在广播中启动锁屏弹窗

我们设置的是锁屏下才弹窗的,非锁屏下就不适合弹出这个窗口了(你可以试一下,效果会很怪)。一般是注册一个广播接收器,在接收到指定广播之后判断是否需要弹窗,所以在BroadcastReceiver的接收代码中需要先判断是否为锁屏状态下:

@Override 
public void onReceive(Context context, Intent intent) { 
Log.d(LOG_TAG, intent.getAction()); 
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); 
if (km.inKeyguardRestrictedInputMode()) { 
Intent alarmIntent = new Intent(context, AlarmActivity.class); 
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
context.startActivity(alarmIntent); 
} 
} 

这里用到的是KeyguardManager类,用来管理锁屏的,4.1之后该类的API新增了一个isKeyguardLocked()的方法判断是否锁屏,但在4.1之前,我们只能用inKeyguardRestrictedInputMode()方法,如果为true,即为锁屏状态。需要注意的是,在广播中启动Activity的context可能不是Activity对象,所以需要添加NEW_TASK的标志,否则启动时可能会报错。我们就可以结合之前的系统发送广播后进行相应的悬浮窗的弹出处理。

复写onNewIntent方法

再次亮起屏幕,如果该Activity并未退出,但是被手动按了锁屏键,当前面的广播接收器再次去启动它的时候,屏幕并不会被唤起,所以我们需要在activity当中添加唤醒屏幕的代码,这里用的是电源锁。可以添加在onNewIntent(Intent intent),因为它会被调用。也可以添加在其他合适的生命周期方法。添加代码如下:

PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE); 
if (!pm.isScreenOn()) { 
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | 
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"); 
wl.acquire(); 
wl.release(); 
} 

最后,是添加如下权限

 
 

第一条是解锁屏幕需要的,第二条是申请电源锁需要的。

以上所说是小编给大家介绍的Android屏幕锁屏弹窗的正确姿势DEMO详解,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对网站的支持!


推荐阅读
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • MySQL中枚举类型的所有可能值获取方法
    本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 本文详细探讨了在Android 8.0设备上使用ChinaCock的TCCBarcodeScanner进行扫码时出现的应用闪退问题,并提供了解决方案。通过调整配置文件,可以有效避免这一问题。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍如何在应用程序中使用文本输入框创建密码输入框,并通过设置掩码来隐藏用户输入的内容。我们将详细解释代码实现,并提供专业的补充说明。 ... [详细]
  • 本文介绍如何通过SQL查询从JDE(JD Edwards)系统中提取所有字典数据,涵盖关键表的关联和字段选择。具体包括F0004和F0005系列表的数据提取方法。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
author-avatar
无神ABC_958
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有