APP定时上锁

模块需求当超过1分钟没有交互的时候,再回到APP需要先跳到九宫格解锁界面进行解锁操作,根据需求可以分析出以下三种情况:

  1. APP从后台回来,超时需要进入解锁;
  2. 手机锁屏、解屏情况;
  3. 手机未锁屏、长时间处于一个界面没有交互的情况;

首先定义一个倒计时器,用来执行倒计时操作:

/**
 * <pre>
 * 倒计时单例工具类
 * </pre>
 * 
 * @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();
	}
}

定义一个屏幕状态监听类,此处屏幕状态监听的主要作用是用于改变我程序中一些变量的值,因为当处于我APP的时候直接关闭屏幕,检测到程序还是在前台运行的。

/**
 * 
 * <pre>
 * 屏幕状态监听
 * </pre>
 * 
 * @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);
	}

	/**
	 * 
	 * <pre>
	 * screen状态广播接收者
	 * </pre>
	 * 
	 * @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;
			}
		}
	}

	/**
	 * 
	 * <pre>
	 * 返回给调用者屏幕状态信息
	 * </pre>
	 * 
	 * @Date 2016-4-20 上午9:34:07
	 */
	public interface ScreenStateListener {
		/**
		 * 开屏
		 */
		public void onScreenOn();

		/**
		 * 锁屏
		 */
		public void onScreenOff();

		/**
		 * 解屏
		 */
		public void onUserPresent();
	}
}

实现一个类继承ActivityLifecycleCallbacks用以捕获activity状态变化:

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<RunningTaskInfo> 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<RunningAppProcessInfo> 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");
	}
}

将BTCCMWActivityLifecycle、ScreenListener.ScreenStateListener在Application中onCreate()注册:

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


在Fragment中比较麻烦, 采用网友提供的方法,具体做法如下

在BaseActivity中,创建一个回调接口,并向外提供注册、销毁接口,然后在dispatchTouchEvent函数中遍历所有注册了接口的对象,分发onTouchEvent事件。

/**
 * 回调接口
 * @author zhaoxin5
 *
 */
public interface MyTouchListener
{
        public void onTouchEvent(MotionEvent event);
}

/*
 * 保存MyTouchListener接口的列表
 */
private ArrayList<MyTouchListener> myTouchListeners = new ArrayList<MainActivity.MyTouchListener>();

/**
 * 提供给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);

到这里能覆盖APP定时上锁的大部分场景了。


参考资料:

http://jiawa.net/forum.php?mod=viewthread&tid=405

http://www.daxueit.com/article/10622.html

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值