模块功能描述(总述)
讲的是延时关机整体功能描述以及UI效果,这篇文章将着重讲解逻辑实现。
按照功能模块分为3部分:关机App、关机Service、Launcher
模块图如下:
关机App模块
主要功能:1.展示UI设置延时时长 2.取消延时关机 3.取消延时对话框倒计时功能
1.展示UI设置延时时长
此处即为延时关机功能入口
:
1.布局及逻辑处理Activity如下,代码中含有注释:
/**
* 延时关机
*/
public class DelayShutdownActivity extends BaseActivity {
private final String TAG = "DelayShutdownActivity";
public final static String ACTION_SCREENOFF = "android.intent.action.SCREEN_OFF";
private MHorizontalScrollView mScrollLayout;
private MAbsoluteLayout mPanelLayout;
private MAbsoluteLayout mMainLayout;
private SelectTimeView mSelectTimeView;
private CancleDelayDialog mCancleDialog;
private View mCurrentView;
private PowerManager mPowerManager;
private ScreenOffBroadcastReceiver mReceiver;
private boolean isCancleMode;
private Animation mAlphaInAnim;
private Animation mAlphaOutAnim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogHelper.releaseLog(TAG, "--onCreate");
setContentView(R.layout.activity_delay_shutdown);
initView();
}
//初始化View
private void initView(){
initMode();// 进入UI时,需要判断是否已经设置了延时关机,根据状态显示不同的UI(设置延时或取消延时)
initScreenOffBroadcast(); // 注册待机广播,在设置延时关机页面待机,再回来延时关机页面应该销毁
mAlphaInAnim = AnimationUtils.loadAnimation(this, R.anim.alpha_in_anim);// 渐入动画(alpha:0-1)
mAlphaOutAnim = AnimationUtils.loadAnimation(this, R.anim.alpha_out_anim); // 渐出动画 (alpha:1-0)
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mScrollLayout = getViewById(R.id.shutdown_horizontalscrollLayout); // 延时关机、关机、重启父级控件
mMainLayout = getViewById(R.id.main_layout);
mPanelLayout = getViewById(R.id.shutdown_layout);
mCurrentView = mScrollLayout;
if(null != mScrollLayout){
mScrollLayout.setOkCallBack(mOkCB); // 设置OK键回调
mScrollLayout.setBackCallBack(mBackCB); // 设置Back键回调
}
addShutdownView(); // 添加3个子元素( 延时关机、关机、重启)
}
private void addShutdownView(){
if(isCancleMode){ // 判断是否为取消延时模式,设置不一样的UI文案提示
addItemView(R.drawable.power_delay, R.string.cancel_delay_shutdown);
}
else{
addItemView(R.drawable.power_delay, R.string.delay_shutdown);
}
addItemView(R.drawable.power_off, R.string.five_shutdown);
addItemView(R.drawable.restart, R.string.five_reboot);
if(null != mScrollLayout){
mScrollLayout.setInitFocusView(1); // 初始化聚焦在“关机”上
}
if(null != mMainLayout){
mMainLayout.startAnimation(mAlphaInAnim); // 整个Layout执行透明度动画
}
}
// 添加元素到父控件
private void addItemView(int IconId, int textId){
if(null != mScrollLayout){
LogHelper.releaseLog(TAG, "--addItemView");
mScrollLayout.addView(IconId, textId);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (KeyEvent.ACTION_DOWN != event.getAction()) {
return true;
}
if (KeyEvent.ACTION_DOWN == event.getAction()) {
if (null != mCurrentView) {
mCurrentView.dispatchKeyEvent(event);
}
}
return false;
}
// 延时关机、关机、重启页OK键回调
private EnterOkCallBack mOkCB = new EnterOkCallBack() {
@Override
public void callBack(int index) {
LogHelper.releaseLog(TAG, "--mOkCB--index:"+index);
doOk(index);
}
};
// 延时关机、关机、重启页Back键回调
private EnterBackCallBack mBackCB = new EnterBackCallBack() {
@Override
public void callBack() {
LogHelper.releaseLog(TAG, "--mBackCB--finish Activity");
// finish
if(null != mMainLayout){
mAlphaOutAnim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationEnd(Animation arg0) {
LogHelper.releaseLog(TAG, "---animation end finish-");
StaticFunction.getPageHelper().finishPage(KEY_PAGEID.PAGE_DELAY_SHOTDOWN); // 动画执行完成退出延时关机APP
}
});
mMainLayout.startAnimation(mAlphaOutAnim);
}
else{
LogHelper.releaseLog(TAG, "---direct finish-");
StaticFunction.getPageHelper().finishPage(KEY_PAGEID.PAGE_DELAY_SHOTDOWN); // 退出延时关机App
}
}
};
// 延时关机、关机、重启页ok键处理
private void doOk(int index){
if(index < 0 || index > 2){
return;
}
switch (index) {
case 0:
if(isCancleMode){ // 取消延时模式,点击OK键显示取消延时关机Dialog
if(null != mPanelLayout){
DelayShutdownHelper.hideLauncherCountView(); // 若launcher正在倒计时,则隐藏倒计时UI
mCancleDialog = new CancleDelayDialog(this);
mCancleDialog.setCallback(mDialogCB); // 设置Dialog事件回调
LayoutParams params = new MAbsoluteLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT,0,0);
mCurrentView = mCancleDialog;
LogHelper.releaseLog(TAG, "--add cancel dialog");
mPanelLayout.addView(mCancleDialog, params);
}
}
else{ // 设置延时模式
if(null != mPanelLayout){
if(null != mScrollLayout){
mScrollLayout.setVisibility(View.GONE); // 隐藏选项入口View
LogHelper.releaseLog(TAG, "--gone scroll view");
}
mSelectTimeView = new SelectTimeView(this); // 延时关机时间选择View
mSelectTimeView.setCallback(mSelectTimeCallback); // 设置Back键回调
LayoutParams params = new MAbsoluteLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT,0,0);
mCurrentView = mSelectTimeView;
mPanelLayout.setVisibility(View.VISIBLE);
mPanelLayout.addView(mSelectTimeView,params);
mSelectTimeView.startAnimation(mAlphaInAnim);
LogHelper.releaseLog(TAG, "--addSelectView--");
}
}
break;
case 1:
if(null != mPowerManager){ // 关机
mPowerManager.reboot("standby");
LogHelper.releaseLog(TAG, "--reboot stanby");
}
break;
case 2:
if(null != mPowerManager){ // 重启
mPowerManager.reboot("");
LogHelper.releaseLog(TAG, "--reboot");
}
break;
default:
break;
}
}
// 延时时间选择View,Back键回调
private SelectTimeCallback mSelectTimeCallback = new SelectTimeCallback() {
@Override
public void callback() {
if(null != mSelectTimeView){
mAlphaOutAnim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationEnd(Animation arg0) {
mSelectTimeView.setVisibility(View.GONE); // 隐藏时间选择View
if(null != mScrollLayout){
mScrollLayout.setVisibility(View.VISIBLE); // 延时关机、关机、重启选项入口显示
mCurrentView = mScrollLayout;
}
}
});
mSelectTimeView.startAnimation(mAlphaOutAnim); // 执行渐出动画
}
}
};
// Dialog事件回调
private keyCallBack mDialogCB = new keyCallBack() {
@Override
public void operation() { // 点击允许键
HeliosToast.getInstance().showToast(GeneralHelper.getString(R.string.cancel_delay_shutdown_toast), 3000); // toast提示
// send broadcast
DelayShutdownHelper.cancelDelayTime(); // 执行取消延时关机逻辑
// change mode
cancelDelayMode(); // 修改UI界面(从取消延时关机变为延时关机)
if(null != mCancleDialog){
mCancleDialog.setVisibility(View.GONE); // 隐藏Dialog
}
mCurrentView = mScrollLayout; // 当前View为延时关机、关机、重启入口选择View
LogHelper.releaseLog(TAG, "--cancel delay shutdown");
}
@Override
public void dismissDialog() { // 点击Back键
LogHelper.releaseLog(TAG, "--dismissDialog--");
DelayShutdownHelper.showLauncherCountView(); // 若launcher正在倒计时,则显示倒计时UI
if(null != mCancleDialog){
mCancleDialog.setVisibility(View.GONE);
}
mCurrentView = mScrollLayout;
}
@Override
public void cancle() { // 点击取消键
LogHelper.releaseLog(TAG, "--cancle--");
DelayShutdownHelper.showLauncherCountView();
if(null != mCancleDialog){
mCancleDialog.setVisibility(View.GONE);
}
mCurrentView = mScrollLayout;
}
};
//注册待机广播
private void initScreenOffBroadcast(){
IntentFilter screenOffFilter = new IntentFilter();
screenOffFilter.addAction(ACTION_SCREENOFF);
mReceiver = new ScreenOffBroadcastReceiver();
registerReceiver(mReceiver, screenOffFilter);
}
/**
* 取消延时关机
*/
private void cancelDelayMode(){
isCancleMode = false;
if(null != mScrollLayout){
mScrollLayout.changeItemView(0, R.drawable.power_delay, R.string.delay_shutdown);
}
}
/**
*初始化延时关机模式
*/
private void initMode(){
isCancleMode = DelayShutdownHelper.isCancelMode();
LogHelper.releaseLog(TAG, "--initMode--isCancelMode--"+isCancleMode);
}
@Override
protected void onDestroy() {
try {
unregisterReceiver(mReceiver);
} catch (Exception e) {
e.printStackTrace();
LogHelper.releaseLog(TAG, "unregisterReceiver has an Exception");
}
super.onDestroy();
}
}
2.关机App与关机Service之间通信方式的封装
Activity中用到许多需要与Service打交道的地方如:启动Service开始计时、隐藏与显示Launcher倒计时UI、取消计时等。
public class DelayShutdownHelper {
private final static String TAG = "DelayShutdownHelper";
private final static String DELAY_SHUTDOWN = "delay_shutdown";
private final static String ACTION_DELAY_SHUTDOWN = "com.helios.action.ACTION_DELAY_SHUTDOWN";
private static String START_TIMER = "start_timer";
private static String CANCEL_TIMER = "cancel_timer";
private static Context mContext;
public static void init(Context context){// 初始化,在应用初始化时调用
mContext = context;
LogHelper.releaseLog(TAG, "--init");
}
/**
* 设置延时时间:单位second
* @param delaySeconds 秒数
*/
public static void setDelayTime(String delaySeconds){
Common.getGlobalData().setGlobalData(DELAY_SHUTDOWN, delaySeconds);
//发送广播,通知CommonService开始Timer
sendBroadcast(START_TIMER);
LogHelper.releaseLog(TAG, "--setDelayTime-"+delaySeconds);
}
public static void cancelDelayTime(){ // 取消延时
Common.getGlobalData().setGlobalData(DELAY_SHUTDOWN, "");
//发送广播,通知CommonService关闭Timer,并通知launcher停止倒计时
sendBroadcast(CANCEL_TIMER);
LogHelper.releaseLog(TAG, "--cancelDelayTime");
}
/**
* 取消延时关机对话框退出后,launcher应显示倒计时
*/
public static void showLauncherCountView(){
if(isLessThanSixtySeconds()){
sendBroadcast(Define.LAUNCHER_SHOW_COUNTDOWN);
LogHelper.releaseLog(TAG, "--showLauncherCountView");
}
}
/**
* 取消延时关机对话框显示,launcher隐藏倒计时
*/
public static void hideLauncherCountView(){
if(isLessThanSixtySeconds()){
sendBroadcast(Define.LAUNCHER_HIDE_COUNTDOWN);
LogHelper.releaseLog(TAG, "--hideLauncherCountView");
}
}
/**
* 是否已设置延时关机,若设置则为取消延时关机模式
* @return true: 取消延时模式,false :设置延时模式
*/
public static boolean isCancelMode(){
String delayTime = Common.getGlobalData().getGlobalData(DELAY_SHUTDOWN);
boolean isCancleMode = false;
if(!TextUtils.isEmpty(delayTime)){
isCancleMode = true;
}
return isCancleMode;
}
/**
* 倒计时是否小于60秒
* @return true: 小于60
*/
public static boolean isLessThanSixtySeconds(){
try {
String delayTime = getDelayTime();
if(TextUtils.isEmpty(delayTime)){
return false;
}
int delaySeconds = Integer.parseInt(delayTime);
return (delaySeconds <= 60);
} catch (NumberFormatException e) {
e.printStackTrace();
LogHelper.releaseLog(TAG, "--parseInt has an Exception");
}
return false;
}
/**
* 获取延时秒数,先判断为取消模式,才调用此方法
* @return 延时秒数
*/
public static String getDelayTime(){
String delayTime = Common.getGlobalData().getGlobalData(DELAY_SHUTDOWN);
LogHelper.releaseLog(TAG, "--getDelayTime-"+delayTime);
return delayTime;
}
/**
* 将分秒转为xx:xx格式
* @param number
* @return
*/
public static String unitFormat(int number){
String retStr = "";
if (number >= 0 && number < 10){
retStr = "0" + Integer.toString(number);
}
else{
retStr = "" + number;
}
return retStr;
}
private static void sendBroadcast(String data){
Intent intent = new Intent();
intent.setAction(ACTION_DELAY_SHUTDOWN);
intent.putExtra("data", data);
mContext.sendBroadcast(intent);
}
}
当然还有一些UI上的细节省略掉了,这里主要注重整体逻辑。
关机Service模块
1.注册开机启动广播
<application
android:allowBackup="true"
android:persistent="true" >
<service android:name="com.helios.service.bluetooth.YourService" ></service>
<receiver android:name="com.helios.service.bluetooth.YourReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
</application>
2.在YourReceiver接收开机广播中启动Service
@Override
public void onReceive(Context context, Intent action) {
Intent intent = new Intent(context,BootService.class);
context.startService(intent);
}
3.在onStart方法中注册延时关机、真待机广播监听
private void registerDelayShutdownBroadCast(){
IntentFilter filter = new IntentFilter();
filter.addAction(DelayShutdownHelper.ACTION_SCREEN_OFF_ACTUALLY); // 真待机
// filter.addAction(DelayShutdownHelper.ACTION_SHUTDOWN); // 关机
filter.addAction(DelayShutdownHelper.ACTION_DELAY_SHUTDOWN); // 延时关机
registerReceiver(new DelayBroadcastReceiver(), filter);
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--registerDelayShutdownBroadCast");
}
4.广播监听实现
public class DelayBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(null != intent){
String action = intent.getAction();
if(DelayShutdownHelper.ACTION_SCREEN_OFF_ACTUALLY.equals(action)){ // 真待机
DelayShutdownHelper.stopTimer();
DelayShutdownHelper.cancelDelayTime();
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--onReceive--ACTION_SCREEN_OFF_ACTUALLY");
}
else if(DelayShutdownHelper.ACTION_DELAY_SHUTDOWN.equals(action)){ // 延时关机
if(intent.hasExtra("data")){
String data = intent.getStringExtra("data");
if(DelayShutdownHelper.START_TIMER.equals(data)){ // 启动倒计时
DelayShutdownHelper.startTimer(); // 启动倒计时功能
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--onReceive--start timer");
}
else if(DelayShutdownHelper.CANCEL_TIMER.equals(data)){ // 取消倒计时
DelayShutdownHelper.stopTimer(); // 取消倒计时功能
DelayShutdownHelper.sendBroadcast(Define.LAUNCHER_CANCEL_COUNTDOWN,0); // 通知Launcher取消倒计时UI
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--onReceive--cancel timer");
}
else if(Define.LAUNCHER_SHOW_COUNTDOWN.equals(data)){ // 显示Launcher倒计时UI
DelayShutdownHelper.sendBroadcast(Define.LAUNCHER_SHOW_COUNTDOWN, DelayShutdownHelper.getCurrentSeconds()); // 传时间到Launcher,Launcher以此为基准开始倒计时
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--onReceive--show countdown--seconds:"+DelayShutdownHelper.getCurrentSeconds());
}
else if(Define.LAUNCHER_HIDE_COUNTDOWN.equals(data)){ // 隐藏Launcher倒计时UI,但继续倒计时,时间到则关机
DelayShutdownHelper.sendBroadcast(Define.LAUNCHER_HIDE_COUNTDOWN, 0);
LogHelper.releaseLog(DelayShutdownHelper.TAG_DELAY_SHUTDOWN, "--onReceive--hide countdown");
}
}
}
}
}
}
5.Service中封装的工具类
public class DelayShutdownHelper {
public final static String TAG_DELAY_SHUTDOWN = "commonservice-DelayShutdown"; // 延时关机TAG
public final static String ACTION_SCREEN_OFF_ACTUALLY = "whaley.actually.standby"; // 真待机广播
public final static String ACTION_DELAY_SHUTDOWN = "com.helios.action.ACTION_DELAY_SHUTDOWN"; // 关机定时启动广播
public final static String START_TIMER = "start_timer"; // 启动timer
public final static String CANCEL_TIMER = "cancel_timer"; // 关闭timer
private final static String DELAY_SHUTDOWN = "delay_shutdown";
private static BaseTimer mBaseTimer;
private static int mSeconds = 0;
private static Context mContext;
// 初始化,在Service初始化时调用
public static void init(Context context){
mContext = context;
// initDelayTimer();
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--init");
}
/**
* 设置延时时间:单位second
* @param delaySeconds 秒数
*/
public static void setDelayTime(String delaySecond){
Common.getGlobalData().setGlobalData(DELAY_SHUTDOWN, delaySecond);
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--setDelayTime-"+delaySecond);
}
/**
* 取消延时,清空存储
*/
public static void cancelDelayTime(){
Common.getGlobalData().setGlobalData(DELAY_SHUTDOWN, "");
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--cancelDelayTime");
}
/**
* 获取延时秒数
* @return 延时秒数
*/
public static String getDelayTime(){
String delayTime = Common.getGlobalData().getGlobalData(DELAY_SHUTDOWN);
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--getDelayTime-"+delayTime);
return delayTime;
}
/**
* 启动定时
*/
public static void startTimer(){
try {
mSeconds = Integer.parseInt(getDelayTime()); // 从文件中取出延时时间,转化为秒数开始倒计时
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--getDelayTime--mSeconds--"+mSeconds);
} catch (NumberFormatException e) {
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--startTimer--parseInt has an Exception");
e.printStackTrace();
}
if (null == mBaseTimer) {
mBaseTimer = new BaseTimer();
}
if (mSeconds > 0) {
mBaseTimer.startInterval(1000, mTimerCB); // 启动timer
}
}
/**
* 取消定时
*/
public static void stopTimer(){
if(null != mBaseTimer){
mBaseTimer.killTimer();
mBaseTimer = null;
mSeconds = 0;
}
}
// 获取剩余秒数
public static int getCurrentSeconds(){
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--getCurrentSeconds--"+mSeconds);
return mSeconds;
}
// 发送广播,通知Launcher执行相应动作
public static void sendBroadcast(String function, int seconds){
Intent intent = new Intent();
intent.setAction(Define.ACTION_NOTIFICATION);
Bundle data = new Bundle();
data.putInt(Define.KEY_NOTIFICATION_TYPE, Define.TYPE_NOTIFICATION_LAUNCHER_COUNTDOWN);
data.putString(Define.KEY_NOTIFICATION_TIME, seconds+"");
data.putString(Define.KEY_NOTIFICATION_FUNCTION, function);
intent.putExtra("data", data);
mContext.sendBroadcast(intent);
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--sendBroadcast--data:"+data+"--seconds:"+seconds);
}
// 初始化保护,赞未用到
private static void initDelayTimer() {
if(!TextUtils.isEmpty(getDelayTime())){
startTimer();
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--initDelayTimer--startTimer");
}
}
// timer计时回调,每秒钟执行一次
private static TimerCallBack mTimerCB = new TimerCallBack() {
@Override
public void callback() {
if(mSeconds > 0){
mSeconds--; // 剩余时间-1
setDelayTime(mSeconds+""); // 存储时间到文件中,因为时间参数共享(关机App中取消Dialog、关机Service共用)
if(mSeconds == 60){ // 倒计时剩余60秒,通知Launcher显示倒计时
sendBroadcast(Define.LAUNCHER_SHOW_COUNTDOWN, 60);
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--has 60 seconds left, send LAUNCHER_SHOW_COUNTDOWN broadcast");
}
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--mTimerCB--mSeconds-"+mSeconds);
}
else if(mSeconds == 0){ // 倒计时结束,停止Timer
stopTimer();
LogHelper.releaseLog(TAG_DELAY_SHUTDOWN, "--mTimerCB--stopTimer");
}
}
};
}
Launcher模块
Launcher模块主要负责倒计时UI的实现,以及倒计时结束后执行关机逻辑。
主要是和Service进行通信。需要监听广播,根据命令执行相应功能,此处不着重讲解。
以上分析:
关机Service主要负责中转命令和执行倒计时功能。
关机APP与Launcher之间无耦合现象。
关机逻辑到此说完,欢迎各位讨论和指正,谢谢。