要开发一个解锁应用有两个途径,一个是直接修改framework,按系统解锁一样直接在framework层实现,另外的方法就是直接开发一个第三方锁屏的应用,在power off时启动这个应用, poweron时首先出现的是这个应用,只有解锁关闭这个应用时才会进入系统界面。

       开发这样一个的锁屏应用, 可以分为如下几个方面,

1)上锁

2)锁屏界面

3)解锁

1,上锁

       上锁要完成的事情是在power off时启动锁屏界面的activity,所以开启一个service只要监听android.intent.action.SCREEN_OFF这个消息即可,这个service一直运行,不会随着锁屏activity的结束而解锁。当启动了自定义的activity时,实际上系统的解锁还是存在的,所以还要调用系统的disableKeyguard把系统的解锁停掉。

private BroadcastReceiver mScreenMonitor = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
    //Utility.log("onReceive   " );                        
    String action = intent.getAction();
    ...                

    if (android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(intent.getAction()))
    {
     //在设置里更改系统解锁是要重新disable
        AntiKeyguard.getInstance(context).reenable(false); 
        AntiKeyguard.getInstance(context).disable(false);                                
        return;
    }
    else if (action.equals(Intent.ACTION_SCREEN_OFF)){
          startLockActivityWhenScreenOff(context);
    }
    }
};



private void startLockActivityWhenScreenOff(Context context)
{
    TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    int call_state = tm.getCallState();
    if (TelephonyManager.CALL_STATE_IDLE != call_state) {//通话状态时
        return;
}

Intent i = new Intent(context, LockerActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);//长按home键时不显示图标
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);

try {
    pi.send();
} catch (PendingIntent.CanceledException ex) {

}

//允许第三方解锁继续接受
//abortBroadcast();                         
//play sound when lock
Water.soundPlayLock();

}

要注意的地方是android.intent.action.SCREEN_OFF不能在AndroidManifest.xml中注册,要动态注册。

public void onCreate() {
    super.onCreate();
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_SCREEN_OFF);//注册SCREEN_OFF事件
    filter.addAction("android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED");

    //优先级设到最高
    filter.setPriority(2147483647);
    registerReceiver(mScreenMonitor, filter);//注册广播
    AntiKeyguard.getInstance(this).disable(false);//disable系统锁屏
}

2, 锁屏界面

锁屏界面可以分为两部分内容:

1)基本信息的显示,如时间,日期,电池状态,未接电话,未接来电等等信息,这部分基本是所有解锁通用的。为了显示这些信息,我们需要注册一些receiver来处理

//时间,电量

private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
    // Util.log("onReceive_activity");
    String action = intent.getAction();
    if (Intent.ACTION_TIME_TICK.equals(action)) {
         long millis = System.currentTimeMillis();
         showTime(millis);
         showDate(millis);
    } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
        if (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)) {
            int state = intent.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE,0);
            int plugFlag = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
            showCharge(state, level, scale, plugFlag);
        } else {
            hideCharge();
        }
    }

}
};

//短信

private class MsgObserver extends ContentObserver {

public MsgObserver(Handler handler) {
    super(handler);
    // Util.log("MsgObserver");
}

@Override
public void onChange(boolean selfChange) {
    // Log.d("Test", "MsgObserver onChange");
    showMissedMsg();
}

}

//未接来电

private class CallObserver extends ContentObserver {

public CallObserver(Handler handler) {
    super(handler);
    // Util.log("CallObserver");
}

@Override
public void onChange(boolean selfChange) {
    // Log.d("Test", "CallObserver onChange");
    showMissedCall();
}

}

2)与解锁操作相关的ui显示,如一些图标,一些动画特效等等,这个每个解锁都会不一样

3,解锁后的处理

当解锁操作符合指定的条件时,如滑动了一定的长度,拖动到指定的icon上,这时就表示解锁完成,要离开解锁界面进入指定的应用或laucher,这部分基本所有的解锁也是一样的

public void onTrigger(View v, int target) {
    Intent intent = null;
    switch (target) {
        case 0:
            break;
        case 1:
            intent = new Intent(Intent.ACTION_DIAL);
            break;
        case 2:
            intent = new Intent(Intent.ACTION_MAIN);
            intent.setType("vnd.android-dir/mms-sms");
            break;
        case 3:
            intent = new Intent();
            intent.setComponent(new ComponentName("com.android.browser", "com.android.browser.BrowserActivity"));
            break;
        case 4:
            intent = new Intent();
            intent.setAction("android.media.action.STILL_IMAGE_CAMERA");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            break;
        case 5:
            intent = new Intent(Intent.ACTION_VIEW);
            intent.setType("vnd.android.cursor.dir/calls");
            break;
        case 6:
            intent = new Intent(Intent.ACTION_MAIN);
            intent.setType("vnd.android-dir/mms-sms");
            break;
        default:
            break;
    }

    if (intent != null)
        startActivity(intent);
    finishMyself();
    overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
 }

4,常见问题

1)解锁完成时黑屏问题

public void onAttachedToWindow() {
    // getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);//导致解锁时屏幕变黑
    getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
}

android:theme="@android:style/Theme.Translucent.NoTitleBar"

2)侧键不能调节音量

在播放音乐时,不要屏蔽音量调节键

AudioManager manager = (AudioManager) 
this.getSystemService(Context.AUDIO_SERVICE);                
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
&& manager.isMusicActive()) {
    return super.onKeyDown(keyCode, event);
}

3)来电或闹钟处理

public class PhoneReceiver extends BroadcastReceiver {

    private LockPatternUtils lockPatternUtils = null;
    public void onReceive(Context context, Intent intent) {
         if(intent.getAction().equals("android.intent.action.PHONE_STATE")) {
             TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
             int call_state = tm.getCallState();
             if (TelephonyManager.CALL_STATE_IDLE != call_state) {
                 if (Utility.COMPAT_SYSTEM_LOCK)
                 {
                     if (lockPatternUtils == null) {
                         lockPatternUtils = new LockPatternUtils(context);
                     }
                     if (!lockPatternUtils.isSecureDual()) {
                         pause(context);                                        
                     }
                 }
                 else
                     pause(context);
                 }
             else {
                 if (Utility.COMPAT_SYSTEM_LOCK)
                 {
                     if (lockPatternUtils == null) {
                         lockPatternUtils = new LockPatternUtils(context);
                     }
                     if (!lockPatternUtils.isSecureDual()) {
                         resume(context);
                     }
                 }
                 else
                     resume(context);
                 }
             }
         else  {
             if(intent.getAction().equals("com.android.deskclock.ALARM_ALERT")) {
                 Utility.log("ALARM_ALERT");
                 pause(context);
             }
             else if(intent.getAction().equals("com.android.deskclock.ALARM_DONE")) {
                 Utility.log("ALARM_killed");
                 resume(context);
             }
             else if(intent.getAction().equals("com.android.deskclock.ALARM_SNOOZE")) {
                 Utility.log("ALARM_cancel_snooze");
                 resume(context);
             }
         }
     }

private void pause(Context context) {
    LockerActivity activity = LockerActivity.getInstance();
    if(activity != null) {
        activity.finishMyself();
        LockerActivity.setStateStopTemp();
    }
}

private void resume(Context context) {
    if(!LockerActivity.getState()) {
        return;
    }
    Intent i = new Intent(context, LockerActivity.class);
    i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);//长按home键时不显示图标
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
    try {
        pi.send();
    } catch (PendingIntent.CanceledException ex) {
}

LockerActivity.resetState();
}

}

4, home键时不显示图标

i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);//长按home键时不显示图标

5,系统解锁屏蔽

.    在锁屏server  oncreate时调用一次

AntiKeyguard.getInstance(this).disable(false);

   在解锁完成后,锁屏activity的

protected void onDestroy() {
    if (!Utility.COMPAT_SYSTEM_LOCK) {
        AntiKeyguard.getInstance(this).reenable(false);
        if (mBVerifiedBinding)
            AntiKeyguard.getInstance(this).disable(false);        
    }
}

   在锁屏server  onDestroy时调用一次

AntiKeyguard.getInstance(this).reenable(false);

6, 系统设置里改动锁屏类型时重新打开系统锁屏

处理filter.addAction("android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED");

if (android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(intent.getAction()))
{
    AntiKeyguard.getInstance(context).reenable(false);
    AntiKeyguard.getInstance(context).disable(false);                                
    return;
}