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

前言

想在锁屏上面实现弹窗,第一个想法就是利用 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()) {
  // 处于锁屏状态
}

总结

以上就是在Android中实现锁屏状态下弹窗效果的全部内容,希望本文的内容对大家开发Android的时候能有所帮助,如果有疑问欢迎大家留言讨论。

(0)

相关推荐

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

    在上篇文章给大家介绍了Android程序开发仿新版QQ锁屏下弹窗功能.今天通过本文给大家分享android锁屏弹窗的正确姿势. 最近在做一个关于屏幕锁屏悬浮窗的功能,于是在网上搜索了很多安卓屏幕锁屏的相关资料,鉴于网上的资料比较零碎,所以我在这里进行整理总结.本文将从以下两点对屏幕锁屏进行解析: 1. 如何监听系统屏幕锁屏 2. 如何在锁屏界面弹出悬浮窗 如何监听系统屏幕锁屏 经过总结,监听系统的锁屏可以通过以下两种方式: 1) 代码直接判定 2) 接收广播 1) 代码直接判定 代码判断方式,也

  • Android开发实现消除屏幕锁的方法

    本文实例讲述了Android开发实现消除屏幕锁的方法.分享给大家供大家参考,具体如下: 实现屏幕无锁--->当我们开机或者超过锁屏幕时间或按电源键之后屏幕没有锁的一种状态. 经过查询许多资料以及分析代码,我们可以发现最主要的屏幕功能还是在framework/base/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java中. 里面有一个handleshow方法: 真正的去锁屏实现有一个 handlehide方法,

  • Android编程实现的一键锁屏程序详解

    本文实例讲述了Android编程实现的一键锁屏程序.分享给大家供大家参考,具体如下: 据笔者了解,所有的Android手机都用电源键来手动锁屏.笔者使用手机时,一天之内手动锁屏的次数绝对不少于30次.如果都用电源键来进行的话,那么电源键的使用寿命一定不会长久. 虽然现在有很多的桌面软件都集成了一键锁屏,但是要安装这些软件就必须安装它们的其他组件,这点让人很不爽,因为他们会定期自动更新,或者在后台运行一些我不想要的东西.所以我决定自己写一个锁屏程序. 经过在android开发文档里面的查找,我发现

  • Android唤醒、解锁屏幕代码实例

    解锁.唤醒屏幕用到KeyguardManager,KeyguardLock,PowerManager,PowerManager.WakeLock   所需权限: 复制代码 代码如下: <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /&

  • android禁止锁屏保持常亮(示例代码)

    在播放video的时候在mediaplayer mMediaPlayer.setScreenOnWhilePlaying(true); 已经设置了,在原生的android没有问题和在defy上也没有问题,一到三星的galaxy上就有问题,不知道三星他们改了哪些地方.一般的话设置了播放视频屏幕没有自动.但是在三星上就出了问题. 只好再找找.一般的话设置有两种方法. 如下: 复制代码 代码如下: 1. getWindow().addFlags(WindowManager.LayoutParams.F

  • Android实现屏幕锁定源码详解

    最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

  • Android编程之自定义锁屏实例分析

    本文实例讲述了Android编程之自定义锁屏.分享给大家供大家参考,具体如下: 花了半天时间研究下了自定义锁屏,发现其实实现并不是很神秘.不过有些地方还是值得注意. 首先说流程,锁屏界面一般是在关闭屏幕时启用,打开屏幕时展现在我们面前,所以我们知道了锁屏的时机,恰好屏幕开关会发出相应的广播,所以我们也可以像系统一样捕获到屏幕开关的事件. 广播对应的两个action 引用 android.intent.action.SCREEN_ON android.intent.action.SCREEN_OF

  • Android编程实现一键锁屏的方法

    本文实例讲述了Android编程实现一键锁屏的方法.分享给大家供大家参考,具体如下: 这里要用到下面两个类: DeviceAdminReceiver 设备管理组件.这个类提供了一个方便解释由系统发出的意图的动作.你的设备管理应用程序必须包含一个DeviceAdminReceiver的子类.本程序中,就代表一个手机上的设备管理器. DevicePolicyManager 一个管理设备上规范的类. 大多数客户端必须声明一个用户当前已经启用的DeviceAdminReceiver. 这个DeviceP

  • 轻松实现Android锁屏功能

    锁屏需要引入设备超级管理员.在文档Android开发文档的Administration中有详细的说明.Android设备管理系统功能和控制访问. 主要有一下几个步骤: 1  创建广播接收者,实现DeviceAdminReceiver package com.andy.lockscreen; import android.app.admin.DeviceAdminReceiver; /** * @author Zhang,Tianyou * @version 2014年11月20日 下午9:51:

  • Android系统永不锁屏永不休眠的方法

    开发Android程序时,有时候在程序运行的时候,不能让系统休眠,否则有一些运行会停止,因此我们需要设置禁止休眠,有两种方式:        一种是添加权限,              一种是代码中设置, 建议使用第一种方式,这样,在安装程序的时候会进行提醒: 第一种方式: 在Manifest.xml文件里面用user-permission声明 名称为:android.permission.WAKE_LOCK 第二种方式: getWindow().setFlags(WindowManager.L

随机推荐