最近研究了一下锁屏,要实现锁屏大体的实现思路是自定义一个后台service监听手机屏幕开关事件,监听到屏幕关闭的时候替换系统锁屏并调用自定义的锁屏界面,自定义锁屏界面需要屏蔽返回键和home键,以及屏蔽状态栏下拉。
系统屏幕开关的时候会发出相应的广播,我们可以接收对应的广播来调用自己的锁屏界面。屏幕开关的时候会发出以下两个广播事件。
android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
替换系统锁屏要调用KeyguardManager类相应方法去解除屏幕锁定,这里需要在配置文件中添加
<uses-permissionandroid:name="android.permission.DISABLE_KEYGUARD" />权限配置
屏蔽系统锁屏代码
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.x<mPointX){ centerStones.x = mPointX; } } else { centerStones.x = centerStones.x + BACK_DURATION * VE_HORIZONTAL; if(centerStones.x>mPointX){ 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; } }