Android自定义锁屏的实现

        最近研究了一下锁屏,要实现锁屏大体的实现思路是自定义一个后台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);
			}
		}
	};
}

LockLayer.java这个类用来屏蔽状态啦下拉和home键的

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;
	}
}

RoundSpinView.java 自定义锁屏界面

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;
	}
}




  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 48
    评论
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值