欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-06 09:35:37
前言 想在锁屏上面实现弹窗,第一个想法就是利用 windowmanager 设置 window 的 flag,通过设置 flag 的显示优先级来让窗口显示在锁屏的上面。...

前言

想在锁屏上面实现弹窗,第一个想法就是利用 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的时候能有所帮助,如果有疑问欢迎大家留言讨论。