注:对不住大家,有点粗心了,之前上传的代码确实有问题(原因是AndroidManifest.xml文件里的包名错了,自己在上传代码时手贱改了一下包名,结果AndroidManifest.xml文件中的package属性没有同步更新,所以运行才报错),现已纠正,正确的代码下载链接地址为http://download.csdn.net/detail/stevenhu_223/5789409,欢迎大家指正,共同学习!

前言:在Android系统锁屏模块开发中,有两种形式的开发:一种是基于源码开发;另一种是基于第三方开发。基于源码开发还是比较具有危险性的,相对于第三方开发来说要考虑的问题比较多,而且移植后可能会出现问题,不便于维护。

当然,基于源码开发锁屏要做的工作相对于第三方开发锁屏要做的工作就少了很多,比如在时间和日期的获取和实时更新、充电时显示的电量状态、运营商名字的显示等等。这些在源码中是已经开发好了,直接可以调用实现。

而基于第三方锁屏的开发就要考虑这些问题,而且还要考虑在启动第三方锁屏时如何屏蔽系统原生的锁屏。

最近鄙人在参考其他人已有的成果上,自己尝试着去开发一个基于第三方锁屏Demo。锁屏相关的资源图片都是自己网上找的,算是仿360的星空锁屏吧。也没有创新性,基本上还是典型的中心图标绕圆圈实现解锁或启动其他应用。现在就把效果图和代码贴出来给大家吐槽一下。

一. 星空锁屏功能介绍:

1. 解锁、启动拨号、短信、相机界面和功能介绍:

功能实现介绍:

-->中心图标动画显示,用户点中心图标可任意拖动。

--> 无论用户拖动中心图标时,手指移动到屏幕的任意一处,中心图标都保持在一定的圆圈范围内移动。

-->若用户拖动中心图标到下方的解锁小图标区域,此时显示白色高亮小图标。用户手指放开时,手机将解锁进入主界面。

-->若用户拖动中心图标到上方的相机小图标区域时,此时显示白色高亮小图标。用户手指放开时,手机将启动相机应用。

-->若用户拖动中心图标到左方的拨号小图标区域时,此时显示白色高亮小图标。用户手指放开时,手机将启动拨号界面。

-->若用户拖动中心图标到右方的短信小图标区域时,此时显示白色高亮小图标。用户手指放开时,手机将启动短信应用。

2. 双击可拖动的中心图标显示的音乐播放控制界面和功能介绍:

功能实现介绍:

-->在显示音乐播放控件界面的情况下,用户拖动中心图标时,隐藏音乐控制按钮,显示解锁、启动应用相关图标,进行解锁、启动应用操作。

-->用户可点击上方的音乐控制按钮图标,进行音乐的播放、暂停。(音乐正在播放时显示暂停按钮,暂停时显示播放按钮)

-->用户可点击下方的音乐控制按钮图标,进行音乐的停止。(音乐停止时,上方图标显示音乐播放按钮)

-->用户可点击左方的音乐控制按钮图标,进行上一曲播放(若音乐在暂时状态时点击上一曲,则上方图标显示暂停按钮)

-->用户可点击右方的音乐控制按钮图标,进行下一曲播放(若音乐在暂时状态时点击下一曲,则上方图标显示暂停按钮)

-->当锁屏界面双击切换到控制音乐播放界面时,上方界面日期显示下方会显示正在播放的歌曲相关信息(歌曲、歌手)

-->当正在处于音乐控制界面时,再次双击中心图标,回到原来的锁屏操作界面(依次循环)

二. 星空锁屏代码实现:

  1. main.xml:

该布局文件为显示锁屏全局界面的布局,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"android:background="@drawable/suoping"><LinearLayout android:layout_marginTop="40dip"android:layout_marginBottom="12dip"android:layout_marginRight="42dip"android:layout_gravity="right"android:layout_width="wrap_content"android:layout_height="wrap_content"><!-- 时间显示 --><TextView android:id="@+id/time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="80sp"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_marginBottom="6dip"android:textColor="#ffffff"/><!-- 上午、下午显示 --><TextView android:id="@+id/am_pm"android:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:ellipsize="none"android:textSize="20sp"android:layout_marginLeft="8dip"android:layout_toRightOf="@id/time"android:layout_alignBottom="@id/time"/></LinearLayout><LinearLayoutandroid:layout_gravity="right"android:layout_marginRight="42dip"android:layout_width="wrap_content"android:layout_height="wrap_content" android:orientation="vertical"><!-- 日期显示 --><TextViewandroid:id="@+id/date" android:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:textAppearance="?android:attr/textAppearanceMedium"android:textSize="14dip"/></LinearLayout><!-- 音乐播放界面歌手名显示,歌手名过长会以跑马灯的形式显示 --><TextView android:id="@+id/artist"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ellipsize="marquee"android:singleLine = "true"android:textSize="14dip"android:layout_gravity="center"android:textColor="#ffffff"/><!-- 音乐播放界面歌曲名显示 ,歌曲名过长会以跑马灯的形式显示--><TextView android:id="@+id/music"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ellipsize="marquee"android:singleLine = "true"android:textSize="14dip"android:layout_gravity="center"android:textColor="#ffffff"/><LinearLayoutandroid:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"><!-- 锁屏核心功能操作界面自定义ViewGrou的显示 --><com.phicomm.hu.StarLockViewandroid:id="@+id/FxView"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout></LinearLayout>

       2. StarLockView.java:

该自定义ViewGroup类为锁屏主要功能实现的核心类。该类负责处理中心图标的动画显示、用户拖动监听操作。同时也处理了解锁图标、应用程序启动图标、音乐控制图标等相关小图标的布局、监听。实现锁屏界面和音乐控制界面的显示和切换,实现发送广播至系统音乐应用的后台服务(MediaPlaybackService),已达到控制后台音乐服务。代码如下:

package com.phicomm.hu;import com.phicomm.hu.R;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;public class StarLockView extends ViewGroup implements OnClickListener
{private static final boolean DBG = true;private Context mContext;private Handler mainHandler = null;private float mx;private float my;private int count = 0;private long firstClick = 0;private long secondClick = 0;private int mWidth, mHight;private int mScreenHalfWidth;private int mAlphaViewWidth, mAlphaViewHeight;private int mCenterViewWidth, mCenterViewHeight;private int mCenterViewTop, mCenterViewBottom;private int mAlphaViewTop, mAlphaViewBottom;private int mSmsViewHalfWidth, mSmsViewHalfHeight;private int mDialViewHalfWidth, mDialViewHalfHeight;private int mCameraViewHalfWidth, mHalfCameraViewHeight;private int mUnlockViewHalfWidth, mUnlockViewHalfHeight;   private int mLightViewHalfWidth, mLightViewHalfHeight;private int mMusicViewHalfWidth, mMusicViewHalfHeight;private ImageView mSmsView, mDialView, mCameraView, mUnLockView;private ImageView mCenterView, mAlphaView;private ImageView mSmsLightView, mUnLockLightView,mCameraLightView, mDialLightView;private ImageView mPlayView, mNextView, mPrevView, mStopView;private Rect smsRect, dialRect, cameraRect, unlockRect;private Rect mCenterViewRect;private AlphaAnimation alpha;private boolean mTracking = false;private static final String TAG = "FxLockView";public static final String SHOW_MUSIC = "com.phicomm.hu.action.music";private static final String SERVICECMD = "com.android.music.musicservicecommand";private static final String CMDNAME = "command";private static final String CMDSTOP = "stop";private static final String CMDPAUSE = "pause";private static final String CMDPLAY = "play";private static final String CMDPREV = "previous";private static final String CMDNEXT = "next";public StarLockView(Context context, AttributeSet attrs) {super(context, attrs, 0);mContext = context;if(DBG) Log.d(TAG, "FxLockView2");//connectMediaService();if(DBG) Log.d(TAG, "FxLockView-->isMusic--->" + MusicInfo.isMusic());MusicInfo.setMusic(false);initViews(context);setViewId();//setViewOnClick();onAnimationStart();}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubif (changed) {mWidth = r;mHight = b;mHalfWidth >> 1为向右位移1位,相当于mHalfWidth / 2。采用位移的原因是计算效率比较高。mScreenHalfWidth = mWidth >> 1;getViewMeasure();mCenterViewTop = 4 * mHight / 7 - (mCenterViewHeight >> 1);mCenterViewBottom = 4 * mHight / 7 + (mCenterViewHeight >> 1);mAlphaViewTop = 4 * mHight / 7 - (mAlphaViewHeight >> 1);mAlphaViewBottom = 4 * mHight / 7 + (mAlphaViewHeight >> 1);setChildViewLayout();setMusicButtonsLayout();setActivatedViewLayout();getChildViewRect();mCenterViewRect = new Rect(mWidth / 2 - mAlphaViewWidth / 2, mAlphaViewTop,mWidth / 2 + mAlphaViewWidth / 2, mAlphaViewBottom);}if(DBG) Log.d(TAG, "l-->" + l);if(DBG) Log.d(TAG, "t-->" + t);if(DBG) Log.d(TAG, "r-->" + r);if(DBG) Log.d(TAG, "b-->" + b);}//获取各个图标的宽、高private void getViewMeasure(){mAlphaView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mAlphaViewWidth = mAlphaView.getMeasuredWidth();mAlphaViewHeight = mAlphaView.getMeasuredHeight();mCenterView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mCenterViewWidth = mCenterView.getMeasuredWidth();mCenterViewHeight = mCenterView.getMeasuredHeight();mSmsView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mSmsViewHalfWidth = (mSmsView.getMeasuredWidth()) >> 1;mSmsViewHalfHeight = (mSmsView.getMeasuredHeight()) >> 1;mDialView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mDialViewHalfWidth = (mDialView.getMeasuredWidth()) >> 1;mDialViewHalfHeight = (mDialView.getMeasuredHeight()) >> 1;mCameraView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mCameraViewHalfWidth = (mCameraView.getMeasuredWidth()) >> 1;mHalfCameraViewHeight = (mCameraView.getMeasuredHeight()) >> 1;mUnLockView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mUnlockViewHalfWidth = (mUnLockView.getMeasuredWidth()) >> 1;mUnlockViewHalfHeight = (mUnLockView.getMeasuredHeight()) >> 1;mSmsLightView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mLightViewHalfWidth = (mSmsLightView.getMeasuredWidth()) >> 1;mLightViewHalfHeight = (mSmsLightView.getMeasuredHeight()) >> 1;mPlayView.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mMusicViewHalfWidth = (mPlayView.getMeasuredWidth()) >> 1;mMusicViewHalfHeight = (mPlayView.getMeasuredHeight()) >> 1;}//设置高亮图标的布局private void setActivatedViewLayout(){mUnLockLightView.layout(mScreenHalfWidth - mLightViewHalfWidth - 5, (mCenterViewTop + 2 * mCenterViewHeight) - mLightViewHalfHeight, mScreenHalfWidth + mLightViewHalfWidth - 5,(mCenterViewBottom + mCenterViewHeight) + mLightViewHalfHeight);mSmsLightView.layout((mScreenHalfWidth + 3 * mCenterViewWidth / 2) - 2 * mLightViewHalfWidth,(mCenterViewTop + mCenterViewHeight / 2) - mLightViewHalfHeight, (mScreenHalfWidth + 3 * mCenterViewWidth / 2) + 2 * mLightViewHalfWidth,(mAlphaViewBottom - mCenterViewHeight / 2) + mLightViewHalfHeight);mDialLightView.layout((mScreenHalfWidth - 3 * mCenterViewWidth / 2) - mLightViewHalfWidth, (mCenterViewTop + mCenterViewHeight / 2) - mLightViewHalfHeight, (mScreenHalfWidth - 3 * mCenterViewWidth / 2) + mLightViewHalfWidth, (mAlphaViewBottom - mCenterViewHeight / 2) + mLightViewHalfHeight);mCameraLightView.layout(mScreenHalfWidth - mLightViewHalfWidth, (mCenterViewTop - mCenterViewHeight) - mLightViewHalfHeight,mScreenHalfWidth + mLightViewHalfWidth,(mCenterViewBottom - 2 * mCenterViewHeight) + mLightViewHalfHeight);}//设置各图标在FxLockView中的布局private void setChildViewLayout(){mAlphaView.layout(mScreenHalfWidth - mAlphaViewWidth / 2, mAlphaViewTop,mScreenHalfWidth + mAlphaViewWidth / 2, mAlphaViewBottom);mCenterView.layout(mScreenHalfWidth - mCenterViewWidth / 2, mCenterViewTop,mScreenHalfWidth + mCenterViewWidth / 2, mCenterViewBottom);mSmsView.layout((mScreenHalfWidth + 3 * mCenterViewWidth / 2) - 2 * mSmsViewHalfWidth,(mCenterViewTop + mCenterViewHeight / 2) - mSmsViewHalfHeight, (mScreenHalfWidth + 3 * mCenterViewWidth / 2) + 2 * mSmsViewHalfWidth,(mAlphaViewBottom - mCenterViewHeight / 2) + mSmsViewHalfHeight);mDialView.layout((mScreenHalfWidth - 3 * mCenterViewWidth / 2) - mDialViewHalfWidth, (mCenterViewTop + mCenterViewHeight / 2) - mDialViewHalfHeight, (mScreenHalfWidth - 3 * mCenterViewWidth / 2) + mDialViewHalfWidth, (mAlphaViewBottom - mCenterViewHeight / 2) + mDialViewHalfHeight);mCameraView.layout(mScreenHalfWidth - mCameraViewHalfWidth, (mCenterViewTop - mCenterViewHeight) - mHalfCameraViewHeight,mScreenHalfWidth + mCameraViewHalfWidth,(mCenterViewBottom - 2 * mCenterViewHeight) + mHalfCameraViewHeight);mUnLockView.layout(mScreenHalfWidth - mUnlockViewHalfWidth, (mCenterViewTop + 2 * mCenterViewHeight) - mUnlockViewHalfHeight,mScreenHalfWidth + mUnlockViewHalfWidth,(mCenterViewBottom + mCenterViewHeight) + mUnlockViewHalfHeight);}//设置音乐控制按钮布局private void setMusicButtonsLayout(){mNextView.layout((mScreenHalfWidth + 3 * mCenterViewWidth / 2) - 2 * mMusicViewHalfWidth,(mCenterViewTop + mCenterViewHeight / 2) - mMusicViewHalfHeight, (mScreenHalfWidth + 3 * mCenterViewWidth / 2) + 2 * mMusicViewHalfWidth,(mAlphaViewBottom - mCenterViewHeight / 2) + mMusicViewHalfHeight);mPrevView.layout((mScreenHalfWidth - 3 * mCenterViewWidth / 2) - mMusicViewHalfWidth, (mCenterViewTop + mCenterViewHeight / 2) - mMusicViewHalfHeight, (mScreenHalfWidth - 3 * mCenterViewWidth / 2) + mMusicViewHalfWidth, (mAlphaViewBottom - mCenterViewHeight / 2) + mMusicViewHalfHeight);mStopView.layout(mScreenHalfWidth - mMusicViewHalfWidth, (mCenterViewTop + 2 * mCenterViewHeight) - mMusicViewHalfHeight,mScreenHalfWidth + mMusicViewHalfWidth,(mCenterViewBottom + mCenterViewHeight) + mMusicViewHalfHeight);mPlayView.layout(mScreenHalfWidth - mMusicViewHalfWidth, (mCenterViewTop - mCenterViewHeight) - mMusicViewHalfHeight,mScreenHalfWidth + mMusicViewHalfWidth,(mCenterViewBottom - 2 * mCenterViewHeight) + mMusicViewHalfHeight);}//创建各图标位置对应的Rectprivate void getChildViewRect(){smsRect = new Rect((mScreenHalfWidth + 3 * mCenterViewWidth / 2) - 2 * mSmsViewHalfWidth,(mCenterViewTop + mCenterViewHeight / 2) - mSmsViewHalfHeight, (mScreenHalfWidth + 3 * mCenterViewWidth / 2) + 2 * mSmsViewHalfWidth,(mAlphaViewBottom - mCenterViewHeight / 2) + mSmsViewHalfHeight);dialRect = new Rect((mScreenHalfWidth - 3 * mCenterViewWidth / 2) - mDialViewHalfWidth, (mCenterViewTop + mCenterViewHeight / 2) - mDialViewHalfHeight, (mScreenHalfWidth - 3 * mCenterViewWidth / 2) + mDialViewHalfWidth, (mAlphaViewBottom - mCenterViewHeight / 2) + mDialViewHalfHeight);cameraRect = new Rect(mScreenHalfWidth - mCameraViewHalfWidth, (mCenterViewTop - mCenterViewHeight) - mHalfCameraViewHeight,mScreenHalfWidth + mCameraViewHalfWidth,(mCenterViewBottom - 2 * mCenterViewHeight) + mHalfCameraViewHeight);unlockRect = new Rect(mScreenHalfWidth - mUnlockViewHalfWidth, (mCenterViewTop + 2 * mCenterViewHeight) - mUnlockViewHalfHeight,mScreenHalfWidth + mUnlockViewHalfWidth,(mCenterViewBottom + mCenterViewHeight) + mUnlockViewHalfHeight);}//获取图标,将获取的图标添加入FxLockView,设置图标的可见性private void initViews(Context context) {mAlphaView = new ImageView(context);mAlphaView.setImageResource(R.drawable.centure2);setViewsLayout(mAlphaView);mAlphaView.setVisibility(View.INVISIBLE);mCenterView = new ImageView(context);mCenterView.setImageResource(R.drawable.centure1);setViewsLayout(mCenterView);mCenterView.setVisibility(View.VISIBLE);mSmsView = new ImageView(context);mSmsView.setImageResource(R.drawable.sms);setViewsLayout(mSmsView);mSmsView.setVisibility(View.VISIBLE);mDialView = new ImageView(context);mDialView.setImageResource(R.drawable.dial);setViewsLayout(mDialView);mDialView.setVisibility(View.VISIBLE);mCameraView = new ImageView(context);mCameraView.setImageResource(R.drawable.camera);setViewsLayout(mCameraView);mCameraView.setVisibility(View.VISIBLE);mUnLockView = new ImageView(context);mUnLockView.setImageResource(R.drawable.home);setViewsLayout(mUnLockView);mUnLockView.setVisibility(View.VISIBLE);mNextView = new ImageView(context);mNextView.setImageResource(R.drawable.next);setViewsLayout(mNextView);setMusicButtonBackground(mNextView);mPrevView = new ImageView(context);mPrevView.setImageResource(R.drawable.prev);setViewsLayout(mPrevView);setMusicButtonBackground(mPrevView);mPlayView = new ImageView(context);setPlayViewDrawable();setViewsLayout(mPlayView);setMusicButtonBackground(mPlayView);mStopView = new ImageView(context);mStopView.setImageResource(R.drawable.stop);setViewsLayout(mStopView);setMusicButtonBackground(mStopView);//mStopView.setVisibility(View.INVISIBLE);mSmsLightView= new ImageView(context);setLightDrawable(mSmsLightView);setViewsLayout(mSmsLightView);mSmsLightView.setVisibility(INVISIBLE);mUnLockLightView = new ImageView(context);setLightDrawable(mUnLockLightView);setViewsLayout(mUnLockLightView);mUnLockLightView.setVisibility(INVISIBLE);mCameraLightView = new ImageView(context);setLightDrawable(mCameraLightView);setViewsLayout(mCameraLightView);mCameraLightView.setVisibility(INVISIBLE);mDialLightView = new ImageView(context);setLightDrawable(mDialLightView);setViewsLayout(mDialLightView);mDialLightView.setVisibility(INVISIBLE);}private void setLightDrawable(ImageView img){img.setImageResource(R.drawable.light);}//设置获取图标的参数,并添加到FxLockViewprivate void setViewsLayout(ImageView image) {image.setScaleType(ScaleType.CENTER);image.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));addView(image);}//设置音乐播放控制按钮的点击触摸反馈背景private void setMusicButtonBackground(ImageView musicIcon){musicIcon.setBackgroundResource(R.drawable.music_button_bg);musicIcon.setVisibility(View.INVISIBLE);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubfinal int action = ev.getAction();final float x = ev.getX();final float y = ev.getY();switch (action) {case MotionEvent.ACTION_DOWN://手指点在中心图标范围区域内if (mCenterViewRect.contains((int) x, (int) y)) {mTracking = true;//stopViewAnimation();onAnimationEnd();mAlphaView.setVisibility(View.INVISIBLE);return true;} else if(MusicInfo.isMusic()){//为音乐控制按钮绑定点击监听setMusicViewsOnClick();}       break;default:break;}if(DBG) Log.d(TAG, "onInterceptTouchEvent()");//此处返回false,onClick事件才能监听的到return false;}@Overridepublic boolean onTouchEvent(MotionEvent event) {/*mTracking为true时,说明中心图标被点击移动* 即只有在中心图标被点击移动的情况下,onTouchEvent* 事件才会触发。*/if (mTracking){final int action = event.getAction();final float nx = event.getX();final float ny = event.getY();switch (action) {case MotionEvent.ACTION_DOWN:showMusicButtons();break;case MotionEvent.ACTION_MOVE:setTargetViewVisible(nx, ny);//中心图标移动handleMoveView(nx, ny);break;case MotionEvent.ACTION_UP:mTracking = false;doTriggerEvent(mx, my);resetMoveView();break;case MotionEvent.ACTION_CANCEL:mTracking = false;doTriggerEvent(mx, my);resetMoveView();break;}}if(DBG) Log.d(TAG, "onTouchEvent()");return mTracking || super.onTouchEvent(event);}//双击中心图标显示音乐控制按钮private void showMusicButtons(){Intent intent = new Intent(SHOW_MUSIC);count ++;if(count == 1){firstClick = System.currentTimeMillis();}else if (count == 2){secondClick = System.currentTimeMillis();if (secondClick - firstClick < 500){//双击监听事件//Toast.makeText(mContext, "click twice",  Toast.LENGTH_LONG).show();//setTargetViewInvisible();if(DBG) Log.d(TAG, "count--->" + count);if(DBG) Log.d(TAG, "isMusic--->" + MusicInfo.isMusic());        if (MusicInfo.isMusic()){setMusicButtonVisibility(false);setTargetViewVisible();}else{setMusicButtonVisibility(true);}      intent.putExtra("music_show", MusicInfo.isMusic());mContext.sendBroadcast(intent);}               count = 0;firstClick = 0;secondClick = 0;}}//平方和计算private float dist2(float dx, float dy){return dx * dx + dy * dy;}private void handleMoveView(float x, float y){int mHalfCenterViewWidth = mCenterViewWidth >> 1;//Radius为中心图标移动的限定的圆范围区域半径int Radius = mCenterViewWidth + mHalfCenterViewWidth;/*若用户手指移动的点与中心点的距离长度大于Radius,则中心图标坐标位置限定在移动区域范围圆弧上。* 一般是用户拖动中心图标,手指移动到限定圆范围区域外。*/if (Math.sqrt(dist2(x - mScreenHalfWidth, y - (mCenterView.getTop() + mCenterViewWidth / 2))) > Radius)       {//原理为x1 / x = r1 / rx = (float) ((Radius / (Math.sqrt(dist2(x - mScreenHalfWidth, y - (mCenterView.getTop() + mHalfCenterViewWidth))))) * (x - mScreenHalfWidth) + mScreenHalfWidth);y = (float) ((Radius / (Math.sqrt(dist2(x - mScreenHalfWidth, y - (mCenterView.getTop() + mHalfCenterViewWidth))))) * (y - (mCenterView.getTop() + mHalfCenterViewWidth)) + mCenterView.getTop() + mHalfCenterViewWidth);}mx = x;my = y;/*图形的坐标是以左上角为基准的,* 所以,为了使手指所在的坐标和图标的中心位置一致,* 中心坐标要减去宽度和高度的一半。*/mCenterView.setX((int)x - mCenterView.getWidth()/2);mCenterView.setY((int)y - mCenterView.getHeight()/2);ShowLightView(x, y);invalidate();}//监听解锁、启动拨号、相机、短信应用private void doTriggerEvent(float a, float b){if (smsRect.contains((int)a, (int) b)){//stopViewAnimation();onAnimationEnd();setTargetViewInvisible(mSmsView);virbate();//发送消息到MainActivity类中的mHandler出来mainHandler.obtainMessage(MainActivity.MSG_LAUNCH_SMS).sendToTarget();}else if (dialRect.contains((int)a , (int)b)){onAnimationEnd();setTargetViewInvisible(mDialView);virbate();mainHandler.obtainMessage(MainActivity.MSG_LAUNCH_DIAL).sendToTarget();}else if (cameraRect.contains((int)a, (int)b)){onAnimationEnd();setTargetViewInvisible(mCameraView);virbate();mainHandler.obtainMessage(MainActivity.MSG_LAUNCH_CAMERA).sendToTarget();}else if (unlockRect.contains((int)a, (int)b)){onAnimationEnd();setTargetViewInvisible(mUnLockView);virbate();mainHandler.obtainMessage(MainActivity.MSG_LAUNCH_HOME).sendToTarget();}}//中心图标拖动到指定区域时显示高亮图标private void ShowLightView(float a, float b){if (unlockRect.contains((int)a, (int)b)){setLightVisible(mUnLockLightView);}else if (smsRect.contains((int)a, (int) b)){setLightVisible(mSmsLightView);}else if (dialRect.contains((int)a , (int)b)){setLightVisible(mDialLightView);}else if (cameraRect.contains((int)a, (int)b)){setLightVisible(mCameraLightView);}else{setLightInvisible();}}private void setLightVisible(ImageView view){view.setVisibility(View.VISIBLE);mCenterView.setVisibility(View.INVISIBLE);}//隐藏高亮图标private void setLightInvisible(){final View mActivatedViews[] = {mUnLockLightView, mSmsLightView, mDialLightView, mCameraLightView};for (View view : mActivatedViews){view.setVisibility(View.INVISIBLE);}mCenterView.setVisibility(View.VISIBLE);}private void setTargetViewInvisible(ImageView img){img.setVisibility(View.INVISIBLE);   }private void setTargetViewVisible(float x, float y){if(Math.sqrt(dist2(x - mScreenHalfWidth, y - (mCenterView.getTop() + mCenterViewWidth / 2))) > mAlphaViewHeight / 4){if (MusicInfo.isMusic()){setMusicButtonVisibility(false);}else{return;}}}private void setTargetViewVisible(){if(DBG) Log.d(TAG, "setTargetViewVisible()");  final View mTargetViews[] = {mSmsView, mDialView, mUnLockView, mCameraView};for (View view : mTargetViews){view.setVisibility(View.VISIBLE);}MusicInfo.setMusic(false);}//show为true时显示音乐播放按钮,false时隐藏private void setMusicButtonVisibility(boolean show){int visibility = show ? View.VISIBLE : View.INVISIBLE;if(DBG) Log.d(TAG, "setMusicIconVisible()");final View mMusicViews[] = {mPlayView, mNextView, mPrevView, mStopView};for(View view : mMusicViews){view.setVisibility(visibility);}//showMusicAnimation(visibility);if (show){//showMusicAnimation();MusicInfo.setMusic(show);}}//重置中心图标,回到原位置private void resetMoveView(){mCenterView.setX(mWidth / 2 - mCenterViewWidth /2);mCenterView.setY((mCenterView.getTop() + mCenterViewHeight / 2) - mCenterViewHeight / 2);onAnimationStart();if (MusicInfo.isMusic()){setMusicButtonVisibility(true);}invalidate();}public void setMainHandler(Handler handler){mainHandler = handler;}//解锁时震动private void virbate(){Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);vibrator.vibrate(200);}//音乐控制按钮绑定点击监听private void setMusicViewsOnClick(){final View mMusicViews[] = {mPlayView, mNextView, mPrevView, mStopView};for (View view : mMusicViews){view.setOnClickListener(this);}}private void setViewId(){if(DBG) Log.d(TAG, "setViewId()");mPlayView.setId(0);mNextView.setId(1);mPrevView.setId(2);mStopView.setId(3);}//音乐播放控制按钮点击事件监听@Overridepublic void onClick(View v) {// TODO Auto-generated method stubIntent intent = new Intent();intent.setAction(SERVICECMD);if(DBG) Log.d(TAG, "onClick");/*发送广播到后台服务,实现控制音乐播放。因为音乐后台服务随时会超时自动停止销毁,* 所以每次点击音乐播放按钮时要先启动后台音乐服务,在保证该服务时启动的情况下才* 能接收到发送的广播。*/switch (v.getId()) {case 0:MainActivity.mStatusViewManager.connectMediaService();if (MusicInfo.isPlaying()){//暂停音乐intent.putExtra(CMDNAME, CMDPAUSE);mPlayView.setImageResource(R.drawable.play);}else{//播放音乐intent.putExtra(CMDNAME, CMDPLAY);mPlayView.setImageResource(R.drawable.pause);}break;case 1:MainActivity.mStatusViewManager.connectMediaService();//下一曲intent.putExtra(CMDNAME, CMDNEXT);mPlayView.setImageResource(R.drawable.pause);break;case 2:MainActivity.mStatusViewManager.connectMediaService();//上一曲intent.putExtra(CMDNAME, CMDPREV);mPlayView.setImageResource(R.drawable.pause);break;case 3://停止MainActivity.mStatusViewManager.connectMediaService();intent.putExtra(CMDNAME, CMDSTOP);mPlayView.setImageResource(R.drawable.play);break;        }mContext.sendBroadcast(intent);}private void setPlayViewDrawable(){if(DBG) Log.d(TAG, "setPlayViewDrawable()-->" + MusicInfo.isPlaying());mPlayView.setImageResource(MusicInfo.isPlaying() ? R.drawable.pause : R.drawable.play);}//停止中心图标动画@Overrideprotected void onAnimationEnd() {// TODO Auto-generated method stubsuper.onAnimationEnd();if (alpha != null){alpha = null;}mAlphaView.setAnimation(null);}//显示中心图标动画@Overrideprotected void onAnimationStart() {// TODO Auto-generated method stubsuper.onAnimationStart();mAlphaView.setVisibility(View.VISIBLE);if (alpha == null) {alpha = new AlphaAnimation(0.0f, 1.0f);alpha.setDuration(1000);}alpha.setRepeatCount(Animation.INFINITE);mAlphaView.startAnimation(alpha);}}      

 3. MediaControl.java:

自定义接口,StarLockService和StatusViewManager均实现它,代码如下:

package com.phicomm.hu;public interface MediaControl
{void connectMediaService();void registerComponent();void unregisterComponent();void initViews();
}

 4.MainActivity.java:

继承Activity类,承载锁屏整个界面,覆盖手机home界面,作为第三方锁屏的可视化操作界面;主要负责加载界面布局、处理来自StarLockView发送的解锁、启动相关应用的信息、屏蔽相关的物理按钮;代码如下:

package com.phicomm.hu;
import com.phicomm.hu.R;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;public class MainActivity extends Activity
{private static final boolean DBG = true;private static final String TAG = "MainActivity";public static final int MSG_LAUNCH_HOME = 0;public static final int MSG_LAUNCH_DIAL = 1;public static final int MSG_LAUNCH_SMS = 2;public static final int MSG_LAUNCH_CAMERA = 3;private StarLockView mLockView;public static StatusViewManager mStatusViewManager;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if(DBG) Log.d(TAG, "onCreate()");this.requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(R.layout.main);initViews();mStatusViewManager = new StatusViewManager(this, this.getApplicationContext());//启动音乐服务mStatusViewManager.connectMediaService();startService(new Intent(MainActivity.this, StarLockService.class));mLockView.setMainHandler(mHandler);}//接收来自StarLockView发送的消息,处理解锁、启动相关应用的功能private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubswitch (msg.what) {case MSG_LAUNCH_HOME:finish();break;case MSG_LAUNCH_SMS:launchSms();finish();break;case MSG_LAUNCH_DIAL:launchDial();finish();break;case MSG_LAUNCH_CAMERA:launchCamera();finish();break;}}};//启动短信应用private void launchSms() {//mFocusView.setVisibility(View.GONE);Intent intent = new Intent();ComponentName comp = new ComponentName("com.android.mms","com.android.mms.ui.ConversationList");intent.setComponent(comp);intent.setAction("android.intent.action.VIEW");intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);startActivity(intent);}//启动拨号应用private void launchDial() {Intent intent = new Intent(Intent.ACTION_DIAL);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);startActivity(intent);}//启动相机应用private void launchCamera() {Intent intent = new Intent();ComponentName comp = new ComponentName("com.android.camera","com.android.camera.Camera");intent.setComponent(comp);intent.setAction("android.intent.action.VIEW");intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);startActivity(intent);}//使home物理键失效@Overridepublic void onAttachedToWindow() {// TODO Auto-generated method stubthis.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);super.onAttachedToWindow();}//使back键,音量加减键失效@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// TODO Auto-generated method stubreturn disableKeycode(keyCode, event);}private boolean disableKeycode(int keyCode, KeyEvent event){int key = event.getKeyCode();switch (key){case KeyEvent.KEYCODE_BACK:      case KeyEvent.KEYCODE_VOLUME_DOWN:case KeyEvent.KEYCODE_VOLUME_UP:return true;          }return super.onKeyDown(keyCode, event);}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if(DBG) Log.d(TAG, "onDestroy()");}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();if(DBG) Log.d(TAG, "onResume()");}@Overridepublic void onDetachedFromWindow() {// TODO Auto-generated method stubsuper.onDetachedFromWindow();if(DBG) Log.d(TAG, "onDetachedFromWindow()");//解除监听mStatusViewManager.unregisterComponent();}public void initViews() {// TODO Auto-generated method stubmLockView = (StarLockView) findViewById(R.id.FxView);}}

注:若4.0以上的系统,launchCamera()方法中的代码改为

private void launchCamera() {
Intent intent = new Intent();
intent.setAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent);
}

5. StarLockService.java:

锁屏后台服务类,主要负责动态监听接收按Power键的广播和音乐后台服务的广播;代码实现如下:

package com.phicomm.hu;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;
import android.util.Log;public class StarLockService extends Service implements MediaControl
{private static final boolean DBG = true;private static final String TAG = "FxLockService";private Intent mFxLockIntent = null;private KeyguardManager mKeyguardManager = null ;private KeyguardManager.KeyguardLock mKeyguardLock = null ;private MusicBroadcastReceiver mMBR;@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();refreshInfo();if (DBG)Log.d(TAG, "-->onCreate()");mFxLockIntent = new Intent(StarLockService.this, MainActivity.class);mFxLockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);registerComponent();}@Overridepublic void onStart(Intent intent, int startId){// TODO Auto-generated method stubsuper.onStart(intent, startId);if(DBG) Log.d(TAG, "-->onStart()");}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if(DBG) Log.d(TAG, "-->onDestroy()");unregisterComponent();//被销毁时启动自身,保持自身在后台存活startService(new Intent(StarLockService.this, StarLockService.class));}@Overridepublic IBinder onBind(Intent arg0){// TODO Auto-generated method stubif(DBG) Log.d(TAG, "-->onBind()");return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubif(DBG) Log.d(TAG, "-->onStartCommand()");return Service.START_STICKY;}//监听来自用户按Power键点亮点暗屏幕的广播private BroadcastReceiver mScreenOnOrOffReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent){if(DBG) Log.d(TAG, "mScreenOffReceiver-->" + intent.getAction());if (intent.getAction().equals("android.intent.action.SCREEN_ON")|| intent.getAction().equals("android.intent.action.SCREEN_OFF")){refreshInfo();mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);mKeyguardLock = mKeyguardManager.newKeyguardLock("FxLock");//屏蔽手机内置的锁屏mKeyguardLock.disableKeyguard();//启动该第三方锁屏startActivity(mFxLockIntent);} if(intent.getAction().equals("com.phicomm.hu.action.music")){refreshInfo();}}};//监听接收后台音乐服务MediaPlaybackService发送的广播,获取广播中携带的播放音乐信息(歌曲、歌手、专辑等)private class MusicBroadcastReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubif(DBG) Log.d(TAG, "MusicBroadcastReceiver-->" + intent.getAction());MusicInfo.setArtistName(intent.getStringExtra("artist"));//artistName = intent.getStringExtra("artist");MusicInfo.setMusicName(intent.getStringExtra("track"));//musicName = intent.getStringExtra("track");MusicInfo.setPlaying(intent.getBooleanExtra("playing", false));//playing = intent.getBooleanExtra("playing", playing);//String album = intent.getStringExtra("album");setMusicViewText();if(DBG) Log.d(TAG, "artistName-->" + MusicInfo.getArtistName());if(DBG) Log.d(TAG, "musicName-->" + MusicInfo.getMusicName());if(DBG) Log.d(TAG, "playing-->" + MusicInfo.isPlaying());//Log.d(TAG, "album-->" + album);//因为音乐后台服务发送的是粘性广播,所以接收后要删除,不然会保持removeStickyBroadcast(intent);}}//刷新音乐播放信息private void refreshInfo(){if (MusicInfo.isMusic()){setMusicViewText();}else{setLockViewText();}}//设置显示音乐播放信息private void setMusicViewText(){if(MusicInfo.getArtistName() != null || MusicInfo.getMusicName()!= null){/*StringBuilder s = new StringBuilder();s.append(MusicInfo.getArtistName()).append("-").append(MusicInfo.getMusicName());MainActivity.mStatusViewManager.mArtistView.setText(s.toString());*/MainActivity.mStatusViewManager.mArtistView.setText(MusicInfo.getArtistName());MainActivity.mStatusViewManager.mMusicView.setText(MusicInfo.getMusicName());}else{MainActivity.mStatusViewManager.mArtistView.setText("no music to be chosen");}}//锁屏界面时隐藏音乐播放信息private void setLockViewText(){MainActivity.mStatusViewManager.mArtistView.setText(null);}@Overridepublic void connectMediaService(){// TODO Auto-generated method stub//MainActivity.mStatusViewManager.connectMediaService();}//注册广播监听@Overridepublic void registerComponent(){// TODO Auto-generated method stubif(DBG) Log.d(TAG, "registerComponent()");IntentFilter mScreenOnOrOffFilter = new IntentFilter();mScreenOnOrOffFilter.addAction("android.intent.action.SCREEN_ON");mScreenOnOrOffFilter.addAction("android.intent.action.SCREEN_OFF");mScreenOnOrOffFilter.addAction(StarLockView.SHOW_MUSIC);StarLockService.this.registerReceiver(mScreenOnOrOffReceiver, mScreenOnOrOffFilter);if (mMBR == null){   mMBR = new MusicBroadcastReceiver();IntentFilter mFilter = new IntentFilter();mFilter.addAction("com.android.music.playstatechanged");   mFilter.addAction("com.android.music.metachanged");mFilter.addAction("com.android.music.queuechanged");mFilter.addAction("com.android.music.playbackcomplete");   StarLockService.this.registerReceiver(mMBR, mFilter);}}//解除广播监听@Overridepublic void unregisterComponent() {// TODO Auto-generated method stubif(DBG) Log.d(TAG, "unregisterComponent()");if (mScreenOnOrOffReceiver != null){StarLockService.this.unregisterReceiver(mScreenOnOrOffReceiver);}if (mMBR != null){StarLockService.this.unregisterReceiver(mMBR);}}@Overridepublic void initViews() {// TODO Auto-generated method stub}}

6. StatusViewManage.java:

该类主要用来管理在锁屏界面上显示时间(包括12小时制下显示上午和下午)和日期。代码如下:

package com.phicomm.hu;import java.lang.ref.WeakReference;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.Date;import com.phicomm.hu.R;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Typeface;
import android.os.Handler;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.widget.TextView;//该类主要用来管理在锁屏界面上显示时间(包括12小时制下显示上午和下午)和日期。
public class StatusViewManager implements MediaControl
{private static final String SYSTEM = "/system/fonts/";private static final String SYSTEM_FONT_TIME_BACKGROUND = SYSTEM + "AndroidClock.ttf";private static final String SYSTEM_FONT_TIME_FOREGROUND = SYSTEM + "AndroidClock_Highlight.ttf";private final static String M12 = "h:mm";private final static String M24 = "kk:mm";private TextView mDateView;private TextView mTimeView;public TextView mArtistView;public TextView mMusicView;private String mDateFormat;private String mFormat;private static Activity mActivity;private AmPm mAmPm;private Calendar mCalendar;public ContentObserver mFormatChangeObserver;public BroadcastReceiver mIntentReceiver;private final Handler mHandler = new Handler();private static final Typeface sBackgroundFont;private static final Typeface sForegroundFont;private static Context mContext;static {//创建获取字体风格sBackgroundFont = Typeface.createFromFile(SYSTEM_FONT_TIME_BACKGROUND);sForegroundFont = Typeface.createFromFile(SYSTEM_FONT_TIME_FOREGROUND);}public StatusViewManager(Activity activity, Context context){mContext = context;mActivity = activity;initViews();refreshDate();}private View findViewById(int id) {return mActivity.findViewById(id);}private void refreshDate(){if (mDateView != null){//锁屏界面显示日期mDateView.setText(DateFormat.format(mDateFormat, new Date()));}}private String getString(int id){return mActivity.getString(id);}class AmPm {private TextView mAmPmTextView;private String mAmString, mPmString;AmPm(Typeface tf) {mAmPmTextView = (TextView)findViewById(R.id.am_pm);if (mAmPmTextView != null && tf != null) {//设置显示的上午、下午字体风格mAmPmTextView.setTypeface(tf);}//获取显示上午、下午的字符串数组String[] ampm = new DateFormatSymbols().getAmPmStrings();mAmString = ampm[0];mPmString = ampm[1];}void setShowAmPm(boolean show) {if (mAmPmTextView != null) {mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);}}void setIsMorning(boolean isMorning) {if (mAmPmTextView != null) {mAmPmTextView.setText(isMorning ? mAmString : mPmString);}}}private static class TimeChangedReceiver extends BroadcastReceiver {private WeakReference<StatusViewManager> mStatusViewManager;//private Context mContext;public TimeChangedReceiver(StatusViewManager status) {mStatusViewManager = new WeakReference<StatusViewManager>(status);}@Overridepublic void onReceive(Context context, Intent intent) {// Post a runnable to avoid blocking the broadcast.final boolean timezoneChanged =intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);final StatusViewManager status = mStatusViewManager.get();if (status != null) {status.mHandler.post(new Runnable() {public void run() {if (timezoneChanged) {status.mCalendar = Calendar.getInstance();}status.updateTime();}});} else {try {mContext.unregisterReceiver(this);} catch (RuntimeException e) {// Shouldn't happen}}}};/*监听URI为Settings.System.CONTENT_URI的数据变化,即12小时制还是24小时制* 的变化(一般来自用户在设置里对时间显示的设置)*/private static class FormatChangeObserver extends ContentObserver {private WeakReference<StatusViewManager> mStatusViewManager;//private Context mContext;public FormatChangeObserver(StatusViewManager status) {super(new Handler());//创建保存在弱应用中的StatusViewManager对象mStatusViewManager = new WeakReference<StatusViewManager>(status);}@Overridepublic void onChange(boolean selfChange) {StatusViewManager mStatusManager = mStatusViewManager.get();if (mStatusManager != null) {mStatusManager.setDateFormat();mStatusManager.updateTime();} else {try {mContext.getContentResolver().unregisterContentObserver(this);} catch (RuntimeException e) {// Shouldn't happen}}}}//更新时间private void updateTime() {mCalendar.setTimeInMillis(System.currentTimeMillis());CharSequence newTime = DateFormat.format(mFormat, mCalendar);mTimeView.setText(newTime);mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);}//设置时间显示格式,如果时间显示为12小时制,则显示上午、下午private void setDateFormat() {mFormat = android.text.format.DateFormat.is24HourFormat(mContext)? M24 : M12;mAmPm.setShowAmPm(mFormat.equals(M12));}/*该锁屏通过控制系统音乐模块后台服务MediaPlaybackService来实现音乐播放的控制,* 但是由于系统音乐模块后台服务默认是禁止跨进程启动它的,所以本锁屏是无法跨进去启动该服务的,* 不过,如果自己的手机有root权限,可以去音乐模块的AndroidManifest.xml文件里修改服务的exported属性,* 然后编译音乐模块再push入手机,这样就可以做到控制系统音乐应用模块的后天服务音乐播放控制了。* 注:这个锁屏是基于这样控制音乐播放的,这里的代码注释掉是考虑到别的手机没有root权限;所以锁屏的音乐控制无效*/@Overridepublic void connectMediaService() {/*Intent intent = new Intent();intent.setClassName("com.android.music", "com.android.music.MediaPlaybackService");//绑定连接远程服务mContext.startService(intent);*/}@Overridepublic void registerComponent() {// TODO Auto-generated method stubLog.d("MainActivity", "registerComponent()");if (mIntentReceiver == null) {mIntentReceiver = new TimeChangedReceiver(this);IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_TIME_TICK);filter.addAction(Intent.ACTION_TIME_CHANGED);filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);mContext.registerReceiver(mIntentReceiver, filter);}if (mFormatChangeObserver == null) {mFormatChangeObserver = new FormatChangeObserver(this);mContext.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);}updateTime();}@Overridepublic void unregisterComponent(){// TODO Auto-generated method stubLog.d("MainActivity", "unregisterComponent()");if (mIntentReceiver != null) {mContext.unregisterReceiver(mIntentReceiver);}if (mFormatChangeObserver != null) {mContext.getContentResolver().unregisterContentObserver(mFormatChangeObserver);}mFormatChangeObserver = null;mIntentReceiver = null;}@Overridepublic void initViews() {// TODO Auto-generated method stubmDateView = (TextView)findViewById(R.id.date);//定义日期的显示格式,日期显示格式在donotTranslatr.xml文件中定义mDateFormat = getString(R.string.month_day_year);mTimeView = (TextView) findViewById(R.id.time);mTimeView.setTypeface(sBackgroundFont);mArtistView = (TextView)findViewById(R.id.artist);mMusicView = (TextView)findViewById(R.id.music);//启动跑马灯功能mArtistView.setSelected(true);mMusicView.setSelected(true);/*创建AmPm对象,参数为设置的字体风格(如可设为Typeface.DEFAULT_BOLD粗体),* 此处参数为空,默认情况。*/mAmPm = new AmPm(null);//获取mCalendar对象mCalendar = Calendar.getInstance();setDateFormat();//注册监听registerComponent();}}

7. MusicInfo.java:

该类用于更新和保存来自音乐应用的音乐播放状态、歌曲名、歌手等相关的音乐信息。同时向外部提供保存的相关音乐信息;(类似JavaBean) 。代码如下:

package com.phicomm.hu;public class MusicInfo
{private static boolean isMusic;private static boolean playing;private static String artistName;private static String musicName;public static boolean isMusic() {return isMusic;}public static void setMusic(boolean isMusic){MusicInfo.isMusic = isMusic;}public static boolean isPlaying() {return playing;}public static void setPlaying(boolean playing) {MusicInfo.playing = playing;}public static String getArtistName(){return artistName;}public static void setArtistName(String artistName) {MusicInfo.artistName = artistName;}public static String getMusicName() {return musicName;}public static void setMusicName(String musicName) {MusicInfo.musicName = musicName;}}

关于Android第三方锁屏开发的介绍就到此结束了,呵呵,代码着实有点多,大家想吐槽的尽管槽吧。

最后,请注意以下几点事项:

1.  该锁屏通过控制系统音乐模块后台服务MediaPlaybackService来实现音乐播放的控制,但是由于系统音乐模块后台服务默认是禁止跨进程启动它的,所以本锁屏是无法跨进去启动该服务的;

2. 正是因为很多手机音乐模块的后台服务默认是禁止跨进程调用的,所以代码中我注释了很多涉及到调用音乐会引起程序异常的代码(新的代码下载地址链接中的代码已纠正);不然运行程序会有问题;

3. 不过,如果自己的手机有root权限,可以去音乐模块的AndroidManifest.xml文件里修改服务类的exported属性,然后编译音乐模块再push入手机,这样就可以做到控制系统音乐应用模块的后天服务音乐播放控制了。
    4. 当然也可以自己编写一个类似音乐模块中的后台服务类控制来控制手机中的音频播放

基于第三方开发Android锁屏相关推荐

  1. android 游戏 锁屏界面开发,android 锁屏程序开发

    参考http://blog.csdn.net/wdaming1986/article/details/8837023 锁屏程序的步骤如下: 1.替换系统锁屏 2.屏蔽Home键,back键.menu键 ...

  2. android 锁屏画面开发,android 锁屏应用开发

    要先注册为admin的.相关代码: mAdminName = new ComponentName(this, MyAdmin.class); // public static class MyAdmi ...

  3. android锁屏快捷键设置,Android4.0+锁屏程序开发——设置锁屏页面篇

    [如何开发一个锁屏应用] 想要开发一个锁屏应用,似乎很难,其实并没有想象中那么难. 从本质上来说,锁屏界面也只是一个Activity而已,只是这个界面比较特殊,在我们点亮屏幕的时候,这个界面就会出现. ...

  4. 安卓开发--关于锁屏状态下如何实现消息推送

    安卓开发–关于锁屏状态下如何实现消息推送 1. 新建一个AlarmHandlerActivity并设置在锁屏状态下弹窗! onCreate方法中添加标志: /* * 分别是锁屏状态下显示,解锁,保持屏 ...

  5. android 锁屏通知

    最近有个需求,说要弄个锁屏通知,通知倒是做过很多了,锁屏通知还真没弄过,经过一番研究,这里做个记录,方便搬砖. 话不多少,直接上效果图: 直接上代码: 安卓系统7以及以下: Notification. ...

  6. android锁屏机制探讨

    最近在搜狗输入法实习,研究了一下android系统的锁屏问题,记录一下,相互学习! android锁屏分系统自带的锁屏和第三方的锁屏. 1.系统自带的锁屏的修改需要改android源码,不同的手机厂商 ...

  7. Android锁屏的实现原理及技术要点

    这两天在搞一个锁屏的小玩意儿,由于时间比较紧,先着重于功能实现,未能从源代码上分析,以下是一些个人的认识与总结,不足或错误之处,还请各位看官批评指正. 1.锁屏页的本质: 锁屏界面其实也是一个Acti ...

  8. 游戏陪玩平台源码开发,锁屏状态下消息提醒的实现

    当游戏陪玩平台源码在后台运行时,如果用户关闭了手机屏幕(手机进入灭屏休眠状态),这个时候有消息进来怎么办?这就需要在游戏陪玩平台源码开发时实现手机锁屏状态下消息提醒功能. 解决思路: 1.游戏陪玩平台 ...

  9. android锁屏显示应用程序,今日应用:微软又给 Android 做了一款锁屏应用

    微软又做了一款 Android 锁屏应用,质量还不错.如果你已经设置了锁屏,Picturesque可能让你再解锁一次你真的需要在锁屏就处理这么多任务吗? 微软又来给 Android 提供应用了,他们昨 ...

最新文章

  1. python 获取窗口句柄_Python文件读写最详细的讲解
  2. C#判断Textbox是否为数字
  3. java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?
  4. iis6 配置python CGI
  5. 如何把女儿培养进麻省理工学院?博士爸爸的40封家书,堪称家庭教育的典范!...
  6. C++/CLI思辨录之再谈继承
  7. FPGA_EP2C8T144_SCH(PDF)
  8. Java 开源 CMS :magnolia
  9. 走出软件质量困境的指导性思想
  10. MySql数据库快速入门与常用sql语句
  11. 【Python】打印200以内所有素数
  12. wex5 tomcat配置php,WeX5 Tomcate 发布
  13. 应对Flash中国版流氓后台偷窥的解决方法
  14. DDD(领域驱动设计)系列主题:DDD战略设计和战术设计分析流程及关键输出物
  15. 11. 符号和符号解析
  16. 敏捷实施步骤与价值观
  17. 数据中心双活该如何构建
  18. 螺旋无限延伸_八卦中的双螺旋结构,无限大∞符号隐含的秘密
  19. 非计算机专业学生计算机基础知识和应用能力,全国高校非计算机专业学生计算机基础知识和应用能力等级考试大纲...
  20. Keras(1):Keras安装与简介

热门文章

  1. 面向iPhone X的iOS应用测试要领
  2. uni-app:商品详情
  3. Redux 包教包会(二):趁热打铁,重拾初心
  4. Linux中的线程同步机制-futex
  5. vue 路由跳转 页面数据不更新问题
  6. 【动态规划】(一)编辑距离
  7. 关于希尔排序的一大坑,与冒泡排序有关千万注意
  8. 二维码框架Zxing的使用及自定义
  9. MBA管理精粹70则
  10. Intellij IDEA字体大小快捷键设置