android锁屏开发难题,系统锁出现后如何自动取消的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android锁屏开发难题,系统锁出现后如何自动取消的问题相关的知识,希望对你有一定的参考价值。

做锁屏的都会遇到的问题

某种情况下,尽管我们的程序disable了keyguard。但在某些情况下,比如Notification来了之后,再次锁屏

我们会看到,系统锁又出现了。

这个时候,360和小米,都可以自动关掉那个锁屏界面,只显示自已的锁屏面。虽然有点不舒服(因为先看到了系统锁屏,然后系统锁屏消失,再看到自已的锁屏)。

但是这基本上已经是极限了,也就是说我们无法彻底阻止系统锁的偶然出现(这种情况是因为锁的顺序乱了)

我们能做的只能是当系统锁出现的时候,我们取消它。

现在的问题是,我试了很多方法,不知道怎么才能取消息。我也不知道小米和360是怎么做到的

哪位兄弟能解释一下不

(1)看看能不能捕获到锁屏的广播(类似监听通话广播)
(2)看看能不能监听锁屏状态(类似监听通话状态改变)
之前,我做个万能钥匙,给android手机解锁用的,不过要注册设备管理器的权限。
你也可以注册设备管理器权限,然后监听设备状态,如果设备状态改变(变成加锁),你就调用解锁方法。
参考技术A

    额额                                     

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

            // 以屏幕左上角为原点,设置xy初始值,相对于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的声明需要加上以下属性:

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

而对于布局文件,要显示的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();  
  

最后,是添加如下权限

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>  
<uses-permission android:name="android.permission.WAKE_LOCK"/>  

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

屏幕锁屏的弹窗就总结到这,如果有什么不同的观点,欢迎在博客进行留言
参考博客:http://blog.csdn.net/maosidiaoxian/article/details/40587935

以上是关于android锁屏开发难题,系统锁出现后如何自动取消的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何开发windows操作系统 锁屏和自动解锁代码如何实现

android开发 怎样锁屏并设置解锁密码

android2.2的锁屏界面,如何在开机时默认显示横屏

远程桌面连接断开后服务器自动锁屏

windows锁屏中,怎么实现自动解锁,进入界面

安卓如何双重锁屏