Android屏幕保护KeyguardManager相关内容学习

  • Post author:
  • Post category:其他



前阵子收到客户要求,要做一款安卓手机和平板上使用的屏保,其实蛮奇怪的,电脑用屏保倒是见得多了,可是手机不使用的时候关掉屏幕不就OK了吗?话说现在的智能手机电池都不耐用的可怜,还装屏保岂不是很费电。原来客户是用于放在营业厅(手机相关),通过手机或者平板来使用相关设备投射到电子屏幕上展示广告的用途,24小时不断电,只是展示用,故电量不作考虑。要求在服务端上传欲展示的图片,PDA上可以进行获取更新图片,只要不断滚动他们的广告就可以了。起初并不是我来做的,同事已经都写的差不多了,他突然有别的项目很急,留给我来做,也好,以前没做过,顺便了解一下android屏保相关的知识,写下来做积累。

——————————————————————————————————-


首先接触到了KeyguardManager,用来对系统的屏保进行屏蔽

public class KeyguardManager extends Object


Class that can be used to lock and unlock the keyboard. Get an instance of this class by calling Context.getSystemService(java.lang.String) with argument Context.KEYGUARD_SERVICE. The actual class to control the keyboard locking is KeyguardManager.KeyguardLock.

一个用于锁屏和解锁的类,通过调用Context.getSystemService(Context.KEYGUARD_SERVICE)来获取实例。实际上用于操控锁屏的是KeyguardManager.KeyguardLock类


KeyguardManager 两个内部类分别是:


(1)


KeyguardManager.KeyguardLock

(l两个函数)

记得加权限


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

disableKeyguard()函数来解除锁屏

reenableKeyguard()反解除锁屏.reenableKeyguard()反解除锁屏的意思是:如果在调用disableKeyguard()函数之前是锁屏的,那么就进行锁屏,否则不进行任何操作。当然如果之前没调用disableKeyguard()函数,也不进行任何操作。


(2)


KeyguardManager.OnKeyguardExitResult(boolean success)

:返回true表示exitKeyguardSecurely()函数执行成功,否则表示失败<具体自己没用到,是个做判断和debug用的吧估计>

—————————————————————————————————–


而后用到的是开启和关闭屏幕唤醒的内容,PowerManager和WakeLock这部分之前用到过,不在详述,这次把这部分单独写成一个工具类,简化代码


  1. package

    com.eyu.screen.util;

  2. import

    android.content.Context;

  3. import

    android.os.PowerManager;

  4. import

    android.os.PowerManager.WakeLock;

  5. public


    class

    PowerManagerWakeLock {

  6. private


    static

    WakeLock wakeLock;

  7. /**开启 保持屏幕唤醒*/

  8. public


    static


    void

    acquire(Context context) {
  9. PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  10. wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE,

    “PowerManagerWakeLock”

    );
  11. wakeLock.acquire();
  12. }

  13. /**关闭 保持屏幕唤醒*/

  14. public


    static


    void

    release() {

  15. if

    (wakeLock !=

    null

    ) {
  16. wakeLock.release();
  17. wakeLock =

    null

    ;
  18. }
  19. }
  20. }
package com.eyu.screen.util;

import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;

public class PowerManagerWakeLock {

	private static WakeLock wakeLock;
	
	/**开启 保持屏幕唤醒*/
	public static void acquire(Context context) {
		PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
		wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "PowerManagerWakeLock");
        wakeLock.acquire();
	}
	
	/**关闭 保持屏幕唤醒*/
	public static void release() {       
        if (wakeLock != null) {
        	wakeLock.release();
        	wakeLock = null;
        }
    }
}


——————————————————————————————————————————————-


其实最主要的应该就是上面的内容,后续就是编写Service和发送广播的操作,并实现和服务端的通信。


做完之后抛开服务端和下载更新的内容,自己做了一个单机用的留底,基本思路和操作与公司项目的一致,只是图片需要手动添加而已,使用后会一直监听屏幕的状态,一旦屏幕灭掉会立刻唤醒,使用viewpager和定时器来控制图片自动的翻页,想彻底停掉就需要断掉后台的service,下面是小程序的截图,启动后会先做判断,如果sd卡指定目录没有图片的话,则加载资源文件,有图片加载SD卡中的。




Service的代码:


  1. package

    com.eyu.screen.UI;

  2. import

    com.eyu.screen.util.PowerManagerWakeLock;

  3. import

    android.app.KeyguardManager;

  4. import

    android.app.Service;

  5. import

    android.content.BroadcastReceiver;

  6. import

    android.content.Context;

  7. import

    android.content.Intent;

  8. import

    android.content.IntentFilter;

  9. import

    android.os.IBinder;

  10. public


    class

    ScreenSaverS

    extends

    Service {

  11. @Override

  12. public

    IBinder onBind(Intent intent) {

  13. // TODO Auto-generated method stub

  14. return


    null

    ;
  15. }

  16. public


    void

    onCreate() {

  17. // 屏蔽系统的屏保
  18. KeyguardManager manager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
  19. KeyguardManager.KeyguardLock lock = manager
  20. .newKeyguardLock(

    “KeyguardLock”

    );
  21. lock.disableKeyguard();

  22. // 注册一个监听屏幕开启和关闭的广播
  23. IntentFilter filter =

    new

    IntentFilter();
  24. filter.addAction(Intent.ACTION_SCREEN_ON);
  25. filter.addAction(Intent.ACTION_SCREEN_OFF);
  26. registerReceiver(screenReceiver, filter);
  27. }
  28. BroadcastReceiver screenReceiver =

    new

    BroadcastReceiver() {

  29. @Override

  30. public


    void

    onReceive(Context context, Intent intent) {

  31. // TODO Auto-generated method stub
  32. String action = intent.getAction();

  33. if

    (action.equals(Intent.ACTION_SCREEN_ON)) {
  34. }

    else


    if

    (action.equals(Intent.ACTION_SCREEN_OFF)) {


    //如果接受到关闭屏幕的广播

  35. if

    (!ScreenSaverShowA.isShow) {

  36. //开启屏幕唤醒,常亮
  37. PowerManagerWakeLock.acquire(ScreenSaverS.

    this

    );
  38. }
  39. PowerManagerWakeLock.acquire(ScreenSaverS.

    this

    );
  40. Intent intent2 =

    new

    Intent(ScreenSaverS.

    this

    ,
  41. ScreenSaverShowA.

    class

    );
  42. intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  43. startActivity(intent2);
  44. PowerManagerWakeLock.release();
  45. }
  46. }
  47. };

  48. public


    void

    onDestroy() {
  49. PowerManagerWakeLock.release();
  50. unregisterReceiver(screenReceiver);
  51. };
  52. }
package com.eyu.screen.UI;

import com.eyu.screen.util.PowerManagerWakeLock;
import android.app.KeyguardManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;

public class ScreenSaverS extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	public void onCreate() {
		// 屏蔽系统的屏保
		KeyguardManager manager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
		KeyguardManager.KeyguardLock lock = manager
				.newKeyguardLock("KeyguardLock");
		lock.disableKeyguard();

		// 注册一个监听屏幕开启和关闭的广播
		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_SCREEN_ON);
		filter.addAction(Intent.ACTION_SCREEN_OFF);
		registerReceiver(screenReceiver, filter);
	}

	BroadcastReceiver screenReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			String action = intent.getAction();
			if (action.equals(Intent.ACTION_SCREEN_ON)) {

			} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {//如果接受到关闭屏幕的广播
				if (!ScreenSaverShowA.isShow) {
					//开启屏幕唤醒,常亮
					PowerManagerWakeLock.acquire(ScreenSaverS.this);
				}
				PowerManagerWakeLock.acquire(ScreenSaverS.this);
				Intent intent2 = new Intent(ScreenSaverS.this,
						ScreenSaverShowA.class);
				intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				startActivity(intent2);
				PowerManagerWakeLock.release();
			}
		}
	};

	public void onDestroy() {
		PowerManagerWakeLock.release();
		unregisterReceiver(screenReceiver);

	};

}


屏保展示页面代码:

  1. <SPAN style=

    “FONT-SIZE: 12px”

    >

    package

    com.eyu.screen.UI;

  2. import

    java.io.File;

  3. import

    java.util.Timer;

  4. import

    java.util.TimerTask;

  5. import

    com.eyu.screen.R;

  6. import

    com.eyu.screen.adapter.ScreenSaverShowAdapter;

  7. import

    com.eyu.screen.util.FolderUtil;

  8. import

    android.annotation.SuppressLint;

  9. import

    android.app.Activity;

  10. import

    android.graphics.Bitmap;

  11. import

    android.graphics.BitmapFactory;

  12. import

    android.graphics.drawable.Drawable;

  13. import

    android.os.Bundle;

  14. import

    android.os.Handler;

  15. import

    android.os.Message;

  16. import

    android.support.v4.view.ViewPager;

  17. import

    android.util.Log;

  18. import

    android.view.View;

  19. import

    android.view.View.OnClickListener;

  20. @SuppressLint

    (

    “HandlerLeak”

    )

  21. public


    class

    ScreenSaverShowA

    extends

    Activity {

  22. public


    static


    boolean

    isShow =

    false

    ;

  23. private

    ViewPager viewPager;

  24. private

    Bitmap[] bmps =

    null

    ;

  25. private

    Drawable[] drawables =

    new

    Drawable[

    5

    ];

  26. @Override

  27. protected


    void

    onCreate(Bundle savedInstanceState) {

  28. // TODO Auto-generated method stub

  29. super

    .onCreate(savedInstanceState);
  30. setContentView(R.layout.screenshow);
  31. isShow =

    true

    ;
  32. initControl();
  33. autoSwitch();
  34. }

  35. @Override

  36. protected


    void

    onDestroy() {

  37. // TODO Auto-generated method stub
  38. isShow =

    false

    ;

  39. //将bitmap回收,尽量避免OOM

  40. if

    (bmps !=

    null

    ) {

  41. for

    (

    int

    i =

    0

    ; i < bmps.length; i++) {
  42. bmps[i].recycle();
  43. }
  44. }

    else

    {

  45. return

    ;
  46. }

  47. super

    .onDestroy();
  48. }

  49. private


    void

    initControl() {
  50. findViewById(R.id.btn_jiesuo).setOnClickListener(

    new

    OnClick());
  51. viewPager = (ViewPager) findViewById(R.id.viewpager);
  52. File f =

    new

    File(FolderUtil.getSaveFolder());
  53. File[] files = f.listFiles();

    // 得到所有子目录
  54. bmps =

    new

    Bitmap[files.length];

  55. //如果文件夹为空,则从资源文件加载图片

  56. if

    (files.length ==

    0

    ) {
  57. drawables[

    0

    ] = getResources().getDrawable(R.drawable.bg_01);
  58. drawables[

    1

    ] = getResources().getDrawable(R.drawable.bg_02);
  59. drawables[

    2

    ] = getResources().getDrawable(R.drawable.bg_03);
  60. drawables[

    3

    ] = getResources().getDrawable(R.drawable.bg_04);
  61. drawables[

    4

    ] = getResources().getDrawable(R.drawable.bg_05);
  62. ScreenSaverShowAdapter adapter =

    new

    ScreenSaverShowAdapter(
  63. ScreenSaverShowA.

    this

    , drawables);
  64. viewPager.setAdapter(adapter);
  65. }

    else

    {

  66. //文件夹不为空则循环遍历加载sd卡指定目录中图片

  67. for

    (

    int

    i =

    0

    ; i < files.length; i++) {
  68. String path = files[i].getAbsolutePath();
  69. bmps[i] = BitmapFactory.decodeFile(path);
  70. Log.d(

    “PDA”

    ,

    “====H===”

    + path);
  71. }
  72. ScreenSaverShowAdapter adapter =

    new

    ScreenSaverShowAdapter(
  73. ScreenSaverShowA.

    this

    , bmps);
  74. viewPager.setAdapter(adapter);
  75. }
  76. }

  77. /** 图片定时自动切换 */

  78. private


    void

    autoSwitch() {

  79. int

    interval =

    3000

    ;
  80. Timer timer =

    new

    Timer();
  81. TimerTask task =

    new

    TimerTask() {

  82. @Override

  83. public


    void

    run() {

  84. // TODO Auto-generated method stub
  85. Message message =

    new

    Message();
  86. handler.sendMessage(message);
  87. }
  88. };
  89. timer.schedule(task, interval, interval);
  90. }
  91. Handler handler =

    new

    Handler() {

  92. @Override

  93. public


    void

    handleMessage(Message msg) {

  94. int

    currentPage = viewPager.getCurrentItem();

  95. int

    tempNum = bmps.length ==

    0

    ? drawables.length : bmps.length;

  96. int

    nextPage = (currentPage +

    1

    ) % tempNum;
  97. viewPager.setCurrentItem(nextPage);

  98. super

    .handleMessage(msg);
  99. }
  100. };

  101. class

    OnClick

    implements

    OnClickListener {

  102. @Override

  103. public


    void

    onClick(View v) {

  104. // TODO Auto-generated method stub
  105. ScreenSaverShowA.

    this

    .finish();
  106. }
  107. }
  108. }
  109. </SPAN>
package com.eyu.screen.UI;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import com.eyu.screen.R;
import com.eyu.screen.adapter.ScreenSaverShowAdapter;
import com.eyu.screen.util.FolderUtil;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;

@SuppressLint("HandlerLeak")
public class ScreenSaverShowA extends Activity {
	public static boolean isShow = false;
	private ViewPager viewPager;
	private Bitmap[] bmps = null;
	private Drawable[] drawables = new Drawable[5];

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.screenshow);
		isShow = true;
		initControl();
		autoSwitch();
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub

		isShow = false;
		//将bitmap回收,尽量避免OOM
		if (bmps != null) {
			for (int i = 0; i < bmps.length; i++) {
				bmps[i].recycle();
			}
		} else {
			return;
		}
		super.onDestroy();

	}

	private void initControl() {
		findViewById(R.id.btn_jiesuo).setOnClickListener(new OnClick());
		viewPager = (ViewPager) findViewById(R.id.viewpager);
		File f = new File(FolderUtil.getSaveFolder());
		File[] files = f.listFiles();// 得到所有子目录
		bmps = new Bitmap[files.length];
		
		//如果文件夹为空,则从资源文件加载图片
		if (files.length == 0) {
			drawables[0] = getResources().getDrawable(R.drawable.bg_01);
			drawables[1] = getResources().getDrawable(R.drawable.bg_02);
			drawables[2] = getResources().getDrawable(R.drawable.bg_03);
			drawables[3] = getResources().getDrawable(R.drawable.bg_04);
			drawables[4] = getResources().getDrawable(R.drawable.bg_05);
			ScreenSaverShowAdapter adapter = new ScreenSaverShowAdapter(
					ScreenSaverShowA.this, drawables);
			viewPager.setAdapter(adapter);
		} else {
			//文件夹不为空则循环遍历加载sd卡指定目录中图片
			for (int i = 0; i < files.length; i++) {
				String path = files[i].getAbsolutePath();
				bmps[i] = BitmapFactory.decodeFile(path);
				Log.d("PDA", "====H===" + path);

			}
			ScreenSaverShowAdapter adapter = new ScreenSaverShowAdapter(
					ScreenSaverShowA.this, bmps);
			viewPager.setAdapter(adapter);

		}

	}

	/** 图片定时自动切换 */
	private void autoSwitch() {
		int interval = 3000;
		Timer timer = new Timer();
		TimerTask task = new TimerTask() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				Message message = new Message();
				handler.sendMessage(message);
			}
		};
		timer.schedule(task, interval, interval);
	}

	Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			int currentPage = viewPager.getCurrentItem();
			int tempNum = bmps.length == 0 ? drawables.length : bmps.length;
			int nextPage = (currentPage + 1) % tempNum;
			viewPager.setCurrentItem(nextPage);
			super.handleMessage(msg);
		}

	};

	class OnClick implements OnClickListener {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			ScreenSaverShowA.this.finish();
		}

	}
}


总结和注意:


1.系统屏保的屏蔽方法以及屏幕唤醒的知识参考API就可以了,比较简单的新知识


2.如果很多张图片来加载的话,很可能出现令人最头疼的OOM,由于屏保就需求全屏显示,所以图片缩放的方式不合适,没想到好办法。不过为了避免反复解锁过程中出现OOM,在onDestroy()方法中对图片进行了recycle。


3.在模拟器上运行没有发现问题,但可能在不同的机型上会出现问题,比如有些手机将安卓的源码改掉了,甚至不允许使用屏蔽系统屏保的方法。还是原生态的android系统最好了,都瞎改什么呢。