模块需求当超过1分钟没有交互的时候,再回到APP需要先跳到九宫格解锁界面进行解锁操作,根据需求可以分析出以下三种情况:
- APP从后台回来,超时需要进入解锁;
- 手机锁屏、解屏情况;
- 手机未锁屏、长时间处于一个界面没有交互的情况;
首先定义一个倒计时器,用来执行倒计时操作:
/**
*
* 倒计时单例工具类
*
*
* @author hyj
* @Date 2016-4-21 下午2:49:21
*/
public class BTCCTimer extends CountDownTimer {
/**
* 倒计时总时长(s)
*/
private final static long millisInFuture = 5 * 1000;
private static BTCCTimer instance;
private Activity activity;
/**
* 倒计时是否结束
*/
private static boolean isTimeFinish = false;
private BTCCTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
/**
* 获取一个倒计时实例
*
* @return
*/
public static BTCCTimer getInstance() {
if (null == instance) {
synchronized (BTCCTimer.class) {
if (null == instance) {
instance = new BTCCTimer(millisInFuture, 1 * 1000);
}
}
}
return instance;
}
@Override
public void onTick(long millisUntilFinished) {
BTCLogManager.logE("执行倒计时:" + (millisUntilFinished / 1000) + " "
+ millisUntilFinished);
if (millisUntilFinished <= 2 * 1000) {
isTimeFinish = true;
return;
}
isTimeFinish = false;
}
@Override
public void onFinish() {
if (isTimeFinish) {
BTCLogManager.logE("倒计时解锁,执行锁屏操作");
BaseActivity.CheckPass(activity);
isTimeFinish = false;
} else {
BTCLogManager.logE("倒计时被中断");
}
}
/**
* 显示解锁界面
*/
public void showLock(Activity activity) {
if (isTimeFinish) {
BTCLogManager.logE("跳进解锁界面");
BaseActivity.CheckPass(activity);
isTimeFinish = false;
}
start(activity);
}
/**
* 开始倒计时
*
* @param activity
*/
public void start(Activity activity) {
this.activity = activity;
stop();
if (activity instanceof CreateGesturePasswordActivity) {
BTCLogManager.logE("当前为九宫格解锁界面");
return;
}
instance.start();
}
/**
* 停止倒计时
*/
public void stop() {
instance.cancel();
instance.onFinish();
}
}
/**
*
*
* 屏幕状态监听
*
*
* @Date 2016-4-21 下午2:52:36
*/
public class ScreenListener {
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private ScreenStateListener mScreenStateListener;
public ScreenListener(Context context) {
this.mContext = context;
this.mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
* 开始监听screen状态
*
* @param listener
*/
public void begin(ScreenStateListener listener) {
this.mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
* 获取screen状态
*/
private void getScreenState() {
if (null == mScreenStateListener) {
return;
}
PowerManager manager = (PowerManager) mContext
.getSystemService(Context.POWER_SERVICE);
if (manager.isScreenOn()) {
mScreenStateListener.onScreenOn();
} else {
mScreenStateListener.onScreenOff();
}
}
/**
* 启动screen状态广播接收器
*/
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiver(mScreenReceiver, filter);
}
/**
* 停止screen状态监听
*/
public void unregisterListener() {
mContext.unregisterReceiver(mScreenReceiver);
}
/**
*
*
* screen状态广播接收者
*
*
* @author hyj
* @Date 2016-4-20 上午9:36:00
*/
private class ScreenBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_SCREEN_ON:// 开屏
mScreenStateListener.onScreenOn();
break;
case Intent.ACTION_SCREEN_OFF: // 锁屏
mScreenStateListener.onScreenOff();
break;
case Intent.ACTION_USER_PRESENT:// 解锁
mScreenStateListener.onUserPresent();
break;
}
}
}
/**
*
*
* 返回给调用者屏幕状态信息
*
*
* @Date 2016-4-20 上午9:34:07
*/
public interface ScreenStateListener {
/**
* 开屏
*/
public void onScreenOn();
/**
* 锁屏
*/
public void onScreenOff();
/**
* 解屏
*/
public void onUserPresent();
}
}
public class BTCCMWActivityLifecycle implements ActivityLifecycleCallbacks {
/**
* 是否现在退出APP
*/
public static boolean isExitAPP = false;
private int activityCount = 0;// 当前活动Activity的数量
private Activity preActivity;// 上一个展示界面
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityCreated");
}
@Override
public void onActivityStarted(Activity activity) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityStarted");
activityCount++;
}
@Override
public void onActivityResumed(Activity activity) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityResumed");
preActivity = activity;
// BTCCTimer.getInstance().showLock();
BTCCTimer.getInstance().start(preActivity);
}
@Override
public void onActivityPaused(Activity activity) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityPaused");
}
@Override
public void onActivityStopped(Activity activity) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityStopped:" + preActivity);
activityCount--;
if (activityCount <= 0 && !isExitAPP) {
BTCLogManager.logI("所有Actvity停止...");
BTCCTimer.getInstance().start(preActivity);
if (isBackground(activity)) {
IPhoneDialogUtil.showToast(activity, "随心用正在后台运行");
GlobalInfo.homeFlag = true;
ArgumentBaseActivity.isNoNeedPwd = false;
BTCCMWApplication.isSettingPassword = false;
}
} else {
BTCCTimer.getInstance().start(preActivity);
}
}
/**
* 判断当前应用程序处于前台还是后台
*/
public static boolean isApplicationBroughtToBackground(final Context context) {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
/**
* 判断应用是处于后台
*
* @param context
* @return
*/
public static boolean isBackground(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
String msg = "importance = " + appProcess.importance;
msg += "\nbackground = 400;empty = 500;foreground = 100;";
msg += "gone = 1000; perceptible = 130;service = 300;visible = 200";
BTCLogManager.logI(msg);
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
BTCLogManager.logI("检测到在后台运行");
return true;
} else {
BTCLogManager.logI("还在前台1");
return false;
}
}
}
BTCLogManager.logI("还在前台2");
return false;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivitySaveInstanceState");
}
@Override
public void onActivityDestroyed(Activity activity) {
BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
+ ":onActivityDestroyed");
}
}
registerActivityLifecycleCallbacks(new BTCCMWActivityLifecycle());
// 屏幕状态监听
ScreenListener.ScreenStateListener screenListener = new ScreenListener.ScreenStateListener() {
@Override
public void onScreenOn() {
}
@Override
public void onScreenOff() {
BTCLogManager.logE("屏幕锁定");
GlobalInfo.homeFlag = true;
ArgumentBaseActivity.isNoNeedPwd = false;
BTCCMWApplication.isSettingPassword = false;
}
@Override
public void onUserPresent() {
}
};
ScreenListener mScreenListener = new ScreenListener(this);
mScreenListener.begin(screenListener);
这些都写完之后,后台运行、锁屏这两种状态下的倒计时都搞定了。
现在就只剩下一种情况了。亮屏的时候长时间无交互需要进入锁屏;当手指点击屏幕的时候需要打断计时,抬起的时候需要重新计时。
这种情况分activity、fragment两种情况
在activity的中,我采用的是在基类BaseActivity中重写dispatchTouchEvent();这种可以覆盖掉Activity的情况
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//循环遍历注册过时间的Fragment对象
for (MyOnTouchListener listener : onTouchListeners) {
BTCLogManager.logI("循环Fragment:" + ev.getSource());
listener.onTouch(ev);
}
BTCLogManager.logI("dispatchTouchEvent action:" + ev.getAction());
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
BTCLogManager.logI("dispatchTouchEvent 按…………");
BTCCTimer.getInstance().stop();
break;
case MotionEvent.ACTION_UP:
BTCLogManager.logI("dispatchTouchEvent 松…………");
BTCCTimer.getInstance().start(this);
break;
}
在BaseActivity中,创建一个回调接口,并向外提供注册、销毁接口,然后在dispatchTouchEvent函数中遍历所有注册了接口的对象,分发onTouchEvent事件。
/**
* 回调接口
* @author zhaoxin5
*
*/
public interface MyTouchListener
{
public void onTouchEvent(MotionEvent event);
}
/*
* 保存MyTouchListener接口的列表
*/
private ArrayList myTouchListeners = new ArrayList();
/**
* 提供给Fragment通过getActivity()方法来注册自己的触摸事件的方法
* @param listener
*/
public void registerMyTouchListener(MyTouchListener listener)
{
myTouchListeners.add( listener );
}
/**
* 提供给Fragment通过getActivity()方法来取消注册自己的触摸事件的方法
* @param listener
*/
public void unRegisterMyTouchListener(MyTouchListener listener)
{
myTouchListeners.remove( listener );
}
/**
* 分发触摸事件给所有注册了MyTouchListener的接口
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
for (MyTouchListener listener : myTouchListeners) {
listener.onTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
然后是在Fragment中的初始化、注册接口,首先需要声明一个父类Activity中的回调接口的对象,然后实现该回调接口中的onTouchEvent方法。并加上自己的处理。
同时需要在该Fragment的初始化函数中,调用父类Activity的registerMyTouchListener函数来注册自己声明的父类Activity中的回调接口的对象,以便把自己加入到父类Activity的事件分发的接收对象列表中。
/**
* Fragment中,注册
* 接收MainActivity的Touch回调的对象
* 重写其中的onTouchEvent函数,并进行该Fragment的逻辑处理
*/
private MainActivity.MyTouchListener mTouchListener = new MyTouchListener() {
@Override
public void onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_UP){
//逻辑处理
}
}
};
//在该Fragment的构造函数中注册mTouchListener的回调
((MainActivity)this.getActivity()).registerMyTouchListener(mTouchListener);
参考资料:
http://jiawa.net/forum.php?mod=viewthread&tid=405
http://www.daxueit.com/article/10622.html