最近研究了一下锁屏,要实现锁屏大体的实现思路是自定义一个后台service监听手机屏幕开关事件,监听到屏幕关闭的时候替换系统锁屏并调用自定义的锁屏界面,自定义锁屏界面需要屏蔽返回键和home键,以及屏蔽状态栏下拉。
系统屏幕开关的时候会发出相应的广播,我们可以接收对应的广播来调用自己的锁屏界面。屏幕开关的时候会发出以下两个广播事件。
android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
替换系统锁屏要调用KeyguardManager类相应方法去解除屏幕锁定,这里需要在配置文件中添加
屏蔽系统锁屏代码
mKeyguardManager= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mKeyguardLock= mKeyguardManager.newKeyguardLock("");
mKeyguardLock.disableKeyguard();
以下是自定义service代码,service中动态注册了监听屏幕开关事件
public class LockService extends Service {
private String TAG = "LockService";
private Intent zdLockIntent = null;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onCreate() {
super.onCreate();
zdLockIntent = new Intent(LockService.this, ShowLockActivity.class);
zdLockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/* 注册广播 */
IntentFilter mScreenOnFilter = new IntentFilter("android.intent.action.SCREEN_ON");
LockService.this.registerReceiver(mScreenOnReceiver, mScreenOnFilter);
/* 注册广播 */
IntentFilter mScreenOffFilter = new IntentFilter("android.intent.action.SCREEN_OFF");
LockService.this.registerReceiver(mScreenOffReceiver, mScreenOffFilter);
}
public void onDestroy() {
Log.i(TAG, "----------------- onDestroy------");
super.onDestroy();
this.unregisterReceiver(mScreenOnReceiver);
this.unregisterReceiver(mScreenOffReceiver);
// 在此重新启动,使服务常驻内存
startService(new Intent(this, LockService.class));
}
private KeyguardManager mKeyguardManager = null;
private KeyguardManager.KeyguardLock mKeyguardLock = null;
// 屏幕变亮的广播,我们要隐藏默认的锁屏界面
private BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.SCREEN_ON")) {
Log.i(TAG, "----------------- android.intent.action.SCREEN_ON------");
}
}
};
// 屏幕变暗/变亮的广播 , 我们要调用KeyguardManager类相应方法去解除屏幕锁定
private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.SCREEN_OFF") || action.equals("android.intent.action.SCREEN_ON")) {
mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mKeyguardLock = mKeyguardManager.newKeyguardLock("");
mKeyguardLock.disableKeyguard();
startActivity(zdLockIntent);
}
}
};
}
public class LockLayer {
private Activity mActivty;
private WindowManager mWindowManager;
private View mLockView;
private LayoutParams mLockViewLayoutParams;
private boolean isLocked;
// 这个值具体用于实现全屏
private final static int FLAG_APKTOOL_VALUE = 1280;
public LockLayer(Activity act) {
mActivty = act;
init();
}
private void init() {
isLocked = false;
mWindowManager = mActivty.getWindowManager();
mLockViewLayoutParams = new LayoutParams();
mLockViewLayoutParams.width = LayoutParams.MATCH_PARENT;
mLockViewLayoutParams.height = LayoutParams.MATCH_PARENT;
// 这一行实现屏蔽Home
mLockViewLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
mLockViewLayoutParams.flags = FLAG_APKTOOL_VALUE;
}
public synchronized void lock() {
if (mLockView != null && !isLocked) {
mWindowManager.addView(mLockView, mLockViewLayoutParams);
}
isLocked = true;
}
public synchronized void unlock() {
if (mWindowManager != null && isLocked) {
mWindowManager.removeView(mLockView);
}
isLocked = false;
}
public synchronized void setLockView(View v) {
mLockView = v;
}
}
public class RoundSpinView extends View {
private String TAG = "RoundSpinView";
private Activity act;
private Context ctx;
private Paint mPaint = new Paint();
// 图片列表列表
private BigStone[] mStones;
// 中心点stone
private BigStone centerStones;
// 数目
private static final int STONE_COUNT = 4;
// 圆心坐标
private int mPointX = 0, mPointY = 0;
// 半径
private int mRadius = 0;
// 每两个点间隔的角度
private int mDegreeDelta;
//
private Bitmap lockscre_pressed_bit ;
private Bitmap lockscreen_normal_bit;
private Bitmap select_bg_bit;
private int[] normal_img = { R.drawable.ic_lockscreen_message_normal, R.drawable.ic_lockscreen_unlock_normal, R.drawable.ic_lockscreen_phone_normal, R.drawable.ic_tab_theme_normal };
private int[] select_img = { R.drawable.ic_lockscreen_message_activated, R.drawable.ic_lockscreen_unlock_activated, R.drawable.ic_lockscreen_phone_activated, R.drawable.ic_tab_theme_selected };
private Bitmap[] normal_img_bitmap = new Bitmap[STONE_COUNT];
private Bitmap[] select_img_bitmap = new Bitmap[STONE_COUNT];
public RoundSpinView(Context context,Activity act, int px, int py, int radius) {
super(context);
this.ctx = context;
this.act = act;
init(px, py, radius);
}
public RoundSpinView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public RoundSpinView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundSpinView(Context context) {
super(context);
}
public void init(int px, int py, int radius) {
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(0);
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.STROKE);
lockscre_pressed_bit = BitmapFactory.decodeResource(getResources(), R.drawable.lockscre_pressed);
lockscreen_normal_bit = BitmapFactory.decodeResource(getResources(), R.drawable.lockscreen_normal);
select_bg_bit = BitmapFactory.decodeResource(getResources(), R.drawable.template_checkbox_normal);
for (int index = 0; index < STONE_COUNT; index++) {
normal_img_bitmap[index] = BitmapFactory.decodeResource(getResources(), normal_img[index]);
select_img_bitmap[index] = BitmapFactory.decodeResource(getResources(), select_img[index]);
}
setBackgroundResource(R.drawable.bg1);
mPointX = px / 2;
mPointY = py / 3 * 2;
mRadius = radius;
setupStones();
computeCoordinates();
}
/**
* 初始化每个点
*/
private void setupStones() {
mStones = new BigStone[STONE_COUNT];
BigStone stone;
int angle = 0;
mDegreeDelta = 360 / STONE_COUNT;
centerStones = new BigStone();
centerStones.angle = angle;
centerStones.x = mPointX;
centerStones.y = mPointY;
for (int index = 0; index < STONE_COUNT; index++) {
stone = new BigStone();
stone.angle = angle;
angle += mDegreeDelta;
mStones[index] = stone;
}
}
/**
* 计算每个点的坐标
*/
private void computeCoordinates() {
BigStone stone;
for (int index = 0; index < STONE_COUNT; index++) {
stone = mStones[index];
stone.x = mPointX + (float) ((mRadius + select_bg_bit.getWidth()/2) * Math.cos(stone.angle * Math.PI / 180));
stone.y = mPointY + (float) ((mRadius + select_bg_bit.getHeight()/2) * Math.sin(stone.angle * Math.PI / 180));
stone.bitmap = normal_img_bitmap[index];
stone.angle = computeCurrentAngle(stone.x, stone.y);
}
}
/**
* 计算坐标点与圆心直径的角度
*
* @param x
* @param y
* @return
*/
private int computeCurrentAngle(float x, float y) {
float distance = (float) Math.sqrt(((x - mPointX) * (x - mPointX) + (y - mPointY) * (y - mPointY)));
int degree = (int) (Math.acos((x - mPointX) / distance) * 180 / Math.PI);
if (y < mPointY) {
degree = -degree;
}
return degree;
}
private boolean isPressLock = false;// 标记是否按住中心锁图片
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
float x, y;
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
isPressLock = isPressLockPic(x, y);
setIsVisible(isPressLock);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
x = event.getX();
y = event.getY();
// 算出当前坐标和圆心的距离
centerStones.angle = computeCurrentAngle(x, y);
if (isPressLock) {
centerStones.bitmap = lockscre_pressed_bit;
computeCoordinates();
if (getDistance(x, y) <= mRadius) {
centerStones.x = x;
centerStones.y = y;
} else {// 大于直径时根据角度算出坐标
centerStones.x = mPointX + (float) ((mRadius) * Math.cos(centerStones.angle * Math.PI / 180));
centerStones.y = mPointY + (float) ((mRadius) * Math.sin(centerStones.angle * Math.PI / 180));
if (centerStones.angle <= (mStones[0].angle + 15) && centerStones.angle >= (mStones[0].angle - 15)) {
mStones[0].bitmap = select_img_bitmap[0];
centerStones.bitmap = select_bg_bit;
centerStones.x = mStones[0].x;
centerStones.y = mStones[0].y;
}
if (centerStones.angle <= (mStones[1].angle + 15) && centerStones.angle >= (mStones[1].angle - 15)) {
mStones[1].bitmap = select_img_bitmap[1];
centerStones.bitmap = select_bg_bit;
centerStones.x = mStones[1].x;
centerStones.y = mStones[1].y;
}
if (centerStones.angle <= (mStones[2].angle + 15) && centerStones.angle >= (mStones[2].angle - 15)) {
mStones[2].bitmap = select_img_bitmap[2];
centerStones.bitmap = select_bg_bit;
centerStones.x = mStones[2].x;
centerStones.y = mStones[2].y;
}
if (centerStones.angle <= (mStones[3].angle + 15) && centerStones.angle >= (mStones[3].angle - 15)) {
mStones[3].bitmap = select_img_bitmap[3];
centerStones.bitmap = select_bg_bit;
centerStones.x = mStones[3].x;
centerStones.y = mStones[3].y;
}
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
//处理Action_Up事件: 判断是否解锁成功,成功则结束我们的Activity ;否则 ,缓慢回退该图片。
handleActionUpEvent(event);
break;
}
return true;
}
private void handleActionUpEvent(MotionEvent event){
boolean islocksuc = false;// 是否解锁成功
float x = event.getX();
float y = event.getY();
centerStones.angle = computeCurrentAngle(x, y);
if (getDistance(x, y) >= mRadius) {
if (centerStones.angle <= (mStones[0].angle + 15) && centerStones.angle >= (mStones[0].angle - 15) && mStones[0].isVisible) {
islocksuc = true;
Log.i(TAG,"解锁-短信 跳转到短信界面");
act.finish();
}
if (centerStones.angle <= (mStones[1].angle + 15) && centerStones.angle >= (mStones[1].angle - 15) && mStones[1].isVisible) {
islocksuc = true;
Log.i(TAG,"解锁-解锁");
act.finish();
}
if (centerStones.angle <= (mStones[2].angle + 15) && centerStones.angle >= (mStones[2].angle - 15) && mStones[2].isVisible) {
islocksuc = true;
Log.i(TAG,"解锁-电话 跳转到电话界面");
act.finish();
}
if (centerStones.angle <= (mStones[3].angle + 15) && centerStones.angle >= (mStones[3].angle - 15) && mStones[3].isVisible) {
islocksuc = true;
Log.i(TAG,"解锁-相机 跳转到相机界面");
act.finish();
}
}
if(!islocksuc) { // 未解锁成功
backToCenter();
}
}
//回退动画时间间隔值
private static int BACK_DURATION = 20 ; // 20ms
//水平方向前进速率
private static float VE_HORIZONTAL = 0.8f ; //0.1dip/ms
private Handler mHandler =new Handler ();
private void backToCenter() {
mHandler.postDelayed(BackDragImgTask, BACK_DURATION);
}
//通过延时控制当前绘制bitmap的位置坐标
private Runnable BackDragImgTask = new Runnable(){
public void run(){
//一下次Bitmap应该到达的坐标值
if(centerStones.x>=mPointX){
centerStones.x = centerStones.x - BACK_DURATION * VE_HORIZONTAL;
if(centerStones.xmPointX){
centerStones.x = mPointX;
}
}
centerStones.y = mPointY + (float) ((centerStones.x-mPointX) * Math.tan(centerStones.angle * Math.PI / 180));
invalidate();//重绘
boolean shouldEnd = getDistance(centerStones.x, centerStones.y) <= 8 ;
if(!shouldEnd)
mHandler.postDelayed(BackDragImgTask, BACK_DURATION);
else { //复原初始场景
centerStones.x = mPointX;
centerStones.y = mPointY;
isPressLock = false;
setIsVisible(isPressLock);
invalidate();
}
}
};
/**
* 获取坐标点与圆心直径的距离
* @param x
* @param y
* @return
*/
private float getDistance(float x, float y) {
float distance = (float) Math.sqrt(((x - mPointX) * (x - mPointX) + (y - mPointY) * (y - mPointY)));
return distance;
}
/**
* 判断手指按下的时候是否按住中心锁图片
*
* @param x
* @param y
* @return
*/
private boolean isPressLockPic(float x, float y) {
float l = centerStones.x - centerStones.bitmap.getWidth() / 2;
float r = centerStones.x + centerStones.bitmap.getWidth() / 2;
float t = centerStones.y - centerStones.bitmap.getHeight() / 2;
float b = centerStones.y + centerStones.bitmap.getHeight() / 2;
if (x >= l && x <= r && y >= t && y <= b) {
return true;
}
return false;
}
@Override
public void onDraw(Canvas canvas) {
if (isPressLock) {// 手指按下状态
canvas.drawCircle(mPointX, mPointY, mRadius, mPaint);// 画圆
drawInCenter(canvas, centerStones.bitmap, centerStones.x, centerStones.y);// 画中心锁图片
for (int index = 0; index < STONE_COUNT; index++) {
if (!mStones[index].isVisible)
continue;
drawInCenter(canvas, mStones[index].bitmap, mStones[index].x, mStones[index].y);
}
} else {
centerStones.bitmap = lockscreen_normal_bit;
drawInCenter(canvas, centerStones.bitmap, centerStones.x, centerStones.y);// 画中心锁图片
}
}
/**
* 把中心点放到中心处
*
* @param canvas
* @param bitmap
* @param left
* @param top
*/
void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top) {
canvas.drawBitmap(bitmap, left - bitmap.getWidth() / 2, top - bitmap.getHeight() / 2, null);
}
private void setIsVisible(boolean isVisible){
for (int index = 0; index < STONE_COUNT; index++) {
mStones[index].isVisible = isVisible;
}
}
class BigStone {
// 图片
public Bitmap bitmap;
// 角度
public int angle;
// x坐标
public float x;
// y坐标
public float y;
// 是否可见
public boolean isVisible = false;
}
}