Android如何实现锁屏状态下弹窗

作者:单刀土豆 时间:2021-05-27 03:38:41 

前言

想在锁屏上面实现弹窗,第一个想法就是利用 WindowManager 设置 Window Flag,通过设置 Flag 的显示优先级来让窗口显示在锁屏的上面。

接下来就是试验可能相关的 Window Type 属性,验证该方案是否可行。

在尝试各个 Window Type 属性之前需要明确各个 Type 所需要的权限,下面是 com.android.internal.policy.impl.PhoneWindowManager.checkAddPermission 的源码:


public int checkAddPermission(WindowManager.LayoutParams attrs) {
 int type = attrs.type;

if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
     || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
   return WindowManagerImpl.ADD_OKAY;
 }
 String permission = null;
 switch (type) {
   case TYPE_TOAST:
     // XXX right now the app process has complete control over
     // this... should introduce a token to let the system
     // monitor/control what they are doing.
     break;
   case TYPE_INPUT_METHOD:
   case TYPE_WALLPAPER:
     // The window manager will check these.
     break;
   case TYPE_PHONE:
   case TYPE_PRIORITY_PHONE:
   case TYPE_SYSTEM_ALERT:
   case TYPE_SYSTEM_ERROR:
   case TYPE_SYSTEM_OVERLAY:
     permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
     break;
   default:
     permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 }
 if (permission != null) {
   if (mContext.checkCallingOrSelfPermission(permission)
       != PackageManager.PERMISSION_GRANTED) {
     return WindowManagerImpl.ADD_PERMISSION_DENIED;
   }
 }
 return WindowManagerImpl.ADD_OKAY;
}

明显不适合的 TypeTYPE_TOAST, TYPE_INPUT_METHOD, TYPE_WALLPAPER; 可能适合的 TypeTYPE_PHONE, TYPE_PRIORITY_PHONE, TYPE_SYSTEM_ALERT, TYPE_SYSTEM_ERROR, TYPE_SYSTEM_OVERLAY; 其它类型的 Type

需要系统签名权限:


android.Manifest.permission.INTERNAL_SYSTEM_WINDOW

而申请该权限需要系统签名,所以我们是无法获取权限的。

TYPE_PHONE


/**
* Window type: phone. These are non-application windows providing
* user interaction with the phone (in particular incoming calls).
* These windows are normally placed above all applications, but behind
* the status bar.
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PHONE       = FIRST_SYSTEM_WINDOW+2;

TYPE_PHONE 类型的窗口可以显示在其它 APP 的上面,但不能显示在锁屏的上面,所以 PASS。

TYPE_PRIORITY_PHONE


/**
* Window type: priority phone UI, which needs to be displayed even if
* the keyguard is active. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PRIORITY_PHONE   = FIRST_SYSTEM_WINDOW+7;

TYPE_PRIORITY_PHONE 类型的窗口可以显示在其它 APP 的上面,但不能显示在锁屏的上面,所以 PASS。而且实际的行为和注释并不相符,该类型的窗口是可以获取交互事件的,具体原因待查。

TYPE_SYSTEM_ALERT


/**
* Window type: system window, such as low power alert. These windows
* are always on top of application windows.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;

TYPE_SYSTEM_ALERT 类型的窗口可以显示在其它 APP 的上面,但不能显示在锁屏的上面,所以 PASS。

TYPE_SYSTEM_OVERLAY


/**
* Window type: system overlay windows, which need to be displayed
* on top of everything else. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;

TYPE_SYSTEM_OVERLAY 类型的窗口可以显示在所有其它窗口的上面,包括锁屏,而且不会影响它下面窗口的交互事件响应,但是该属性窗口不能获得焦点,无法进行交互(如果该窗口可以获取焦点,那么就可以用来抓取用户的锁屏密码,出于安全考虑,系统是不会允许的),所以只能用来简单的展示内容,如果需要交互的锁屏弹窗,那么该属性 PASS。

TYPE_SYSTEM_ERROR


/**
* Window type: internal system error windows, appear on top of
* everything they can.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;

在原生 ROM 5.1 下试验是可以显示出来的,但根据注释来看(appear on top of everything they can)不是在所有情况下都可以显示在锁屏上面的,而且像 MIUI 和 Flyme 等 ROM 默认是屏蔽浮窗权限的,考虑到这点,利用 WindowManager 添加浮窗的方式实现锁屏弹窗的方案基本 PASS。

使用 Activity 的方式实现

首先需要对 Activity 进行如下设置


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);
}

其中最主要也是必须要设置的就是:FLAG_SHOW_WHEN_LOCKED,顾名思义就是锁屏下显示该 Activity。而其它几个 Flag 包括:解锁、保持屏幕常亮、点亮屏幕可以根据具体的需求选择设置。

在 AndroidManifest.xml 中声明 Activity

同样该 Activity 也需要在 AndroidManifest.xml 中声明,声明时需注意添加 android:excludeFromRecents="true" 属性,是为了将该 Activity 从最近任务列表中去除,否则用户会觉得很奇怪。还有因为这个 Activity 会整个盖在锁屏上面,而且就算设置成背景透明,锁屏界面也不会显示在下面(系统主要是出于安全考虑),所以需要考虑下该 Activity 的背景,这里为了显示不要太突兀将主题设为壁纸。


<activity android:name=".LockScreenActivity"
    android:launchMode="singleInstance"
    android:excludeFromRecents="true"
    android:theme="@android:style/Theme.Wallpaper.NoTitleBar"/>

启动 Activity

由于该 Activity 是为了在锁屏的情况下显示的,所以启动 Activity 时不要忘了判断手机是否处于锁屏状态,可以通过下面这种方式判断锁屏状态:


KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (km.inKeyguardRestrictedInputMode()) {
 // 处于锁屏状态
}

总结

来源:http://www.jianshu.com/p/1e4131a30bad

标签:android,锁屏,弹窗
0
投稿

猜你喜欢

  • C语言文件操作大全

    2022-10-17 06:25:01
  • android利用剪切板传递数据

    2022-06-24 06:37:40
  • Android三种菜单实例分析

    2023-09-09 05:17:20
  • java 线程创建多线程详解

    2021-08-06 22:02:22
  • RocketMQ producer同步发送单向发送源码解析

    2022-11-20 01:55:55
  • Kotlin伴随对象的初始化方法示例讲解

    2022-07-24 05:53:06
  • 浅谈java中BigDecimal的equals与compareTo的区别

    2023-09-02 07:20:22
  • Java中的Unsafe在安全领域的使用总结和复现(实例详解)

    2023-07-30 10:58:42
  • Java并发之不可思议的死循环详解

    2023-10-20 03:11:34
  • java 抛出异常处理的方法

    2023-05-12 21:55:54
  • Java Web开发之基于Session的购物商店实现方法

    2023-06-09 20:46:35
  • 基于Nacos实现Spring Cloud Gateway实现动态路由的方法

    2022-04-14 07:18:56
  • java实现随机验证码图片生成

    2022-12-08 02:27:00
  • c#使用Dataset读取XML文件动态生成菜单的方法

    2022-07-14 22:52:20
  • 教你java面试时如何聊单例模式

    2022-04-14 05:32:57
  • java volatile关键字的含义详细介绍

    2021-11-01 16:52:17
  • C# WinForm实现自动更新程序的方法详解

    2021-12-12 16:19:54
  • Android Flutter实现兴趣标签选择功能

    2021-07-05 14:29:17
  • Java如何去掉指定字符串的开头的指定字符

    2022-05-23 13:28:31
  • 在Winform框架界面中改变并存储界面皮肤样式的方法

    2021-06-08 09:08:24
  • asp之家 软件编程 m.aspxhome.com