Android系統亮屏、鎖屏、屏幕解鎖事件(解決部分手機亮屏後未解鎖即進入resume狀態)

有一部分三星的手機關閉屏幕以後,剛打開屏幕,前臺的activity就會resume狀態,因為我們使用cocos2d-x引擎,默認resume和activity的resume事件是一致的,我們在resume裡把關閉的聲音重新打開,所以導致,用戶點亮屏幕以後(尚未解鎖),就會聽到遊戲內的聲音(如果在關閉屏幕時我們遊戲處於前臺)。

為瞭解決這個問題,我們需要修改我們resume觸發的時機。確保在解鎖以後才進入我們遊戲的resume狀態。
那麼我們遊戲應該在什麼時機進入resume狀態呢?

系統activity進入resume狀態時刻,並且屏幕是亮的,屏幕未鎖定屏幕剛剛亮起,並且屏幕 未鎖定,系統activity已經進入resume狀態屏幕 解鎖,這是屏幕肯定是亮的,並且activity已經進入resume狀態

那麼有瞭上面的三點相信邏輯代碼不難寫,下面介紹一下如何堅挺系統屏幕滅,屏幕亮,解鎖屏幕 的事件,以及如何判斷當前屏幕 是否是解鎖狀態(因為用戶可以設置關閉屏幕後是否鎖定屏幕 ,所以解鎖屏幕 事件可能根本就不會被觸發,那麼我們就不能通過跟蹤事件來確定其狀態)

要堅挺屏幕亮、屏幕滅、屏幕 解鎖三個事件我們需要在代碼中註冊監聽ACTION_SCREEN_ON、ACTION_SCREEN_OFF、ACTION_USER_PRESENT三個Action,具體的寫法如下:

	/**
	 * screen狀態廣播接收者
	 */
	private class ScreenBroadcastReceiver extends BroadcastReceiver{
		@Override
		public void onReceive(Context context, Intent intent) {
			if(Intent.ACTION_SCREEN_ON.equals(intent.getAction())){				
				mScreenStateListener.onScreenOn();
			}else if(Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
				mScreenStateListener.onScreenOff();
			}else if(Intent.ACTION_USER_PRESENT.equals(intent.getAction())){
				mScreenStateListener.onUserPresent();
			}
		}
	}

	/**
	 * 停止screen狀態更新
	 */
	public void stopScreenStateUpdate() {
		mContext.unregisterReceiver(mScreenReceiver);
	}

	/**
	 * 啟動screen狀態廣播接收器
	 */
	private void startScreenBroadcastReceiver() {
		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);
	}

因為屏幕在滅瞭以後是否鎖定可以由用戶設置,所以我們不能通過跟蹤解鎖事件來判斷其狀態,需要一個可以時時獲取狀態的函數:

	//判斷屏幕是否被鎖定
	public final static boolean isScreenLocked(Context c) {
		android.app.KeyguardManager mKeyguardManager = (KeyguardManager) c.getSystemService(c.KEYGUARD_SERVICE);
		return mKeyguardManager.inKeyguardRestrictedInputMode();
	}

需要註意的是,大部分事件都可以在AndroidManifest.xml中註冊,但是ACTION_SCREEN_ON、ACTION_SCREEN_OFF、ACTION_USER_PRESENT這幾個事件在PowerManager那邊做瞭限制,必須像上面那樣在代碼中註冊,才能監聽到,所以大傢不要踩到坑哦~~~

下面是包裝屏幕事件的一個類代碼,僅供參考:

package com.example.myfirstapp;

import java.lang.reflect.Method;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PowerManager;
import android.util.Log;

/**
 * 監聽屏幕ON和OFF PRESENT狀態
 * 
 * @author
 * @2014
 * 
 */
public class ScreenObserver {
	private static String TAG = "ScreenObserver";
	private Context mContext;
	private ScreenBroadcastReceiver mScreenReceiver;
	private ScreenStateListener mScreenStateListener;
	private static Method mReflectScreenState;

	public ScreenObserver(Context context) {
		mContext = context;
		mScreenReceiver = new ScreenBroadcastReceiver();
		try {
			mReflectScreenState = PowerManager.class.getMethod("isScreenOn",
					new Class[] {});
		} catch (Exception nsme) {
			Log.d(TAG, "API < 7," + nsme);
		}
	}

	/**
	 * screen狀態廣播接收者
	 */
	private class ScreenBroadcastReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
				mScreenStateListener.onScreenOn();
			} else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
				mScreenStateListener.onScreenOff();
			} else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
				mScreenStateListener.onUserPresent();
			}
		}
	}

	/**
	 * 請求screen狀態更新
	 */
	public void requestScreenStateUpdate(ScreenStateListener listener) {
		mScreenStateListener = listener;
		startScreenBroadcastReceiver();
		firstGetScreenState();
	}

	/**
	 * 第一次請求screen狀態
	 */
	private void firstGetScreenState() {
		PowerManager manager = (PowerManager) mContext
				.getSystemService(Activity.POWER_SERVICE);
		if (isScreenOn(manager)) {
			if (mScreenStateListener != null) {
				mScreenStateListener.onScreenOn();
			}
		} else {
			if (mScreenStateListener != null) {
				mScreenStateListener.onScreenOff();
			}
		}
	}

	/**
	 * 停止screen狀態更新
	 */
	public void stopScreenStateUpdate() {
		mContext.unregisterReceiver(mScreenReceiver);
	}

	/**
	 * 啟動screen狀態廣播接收器
	 */
	private void startScreenBroadcastReceiver() {
		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是否打開狀態
	 */
	private static boolean isScreenOn(PowerManager pm) {
		boolean screenState;
		try {
			screenState = (Boolean) mReflectScreenState.invoke(pm);
		} catch (Exception e) {
			screenState = false;
		}
		return screenState;
	}

	// 外部調用接口
	public interface ScreenStateListener {
		public void onScreenOn();

		public void onScreenOff();

		public void onUserPresent();
	}

	public final static boolean isScreenLocked(Context c) {
		android.app.KeyguardManager mKeyguardManager = (KeyguardManager) c
				.getSystemService(c.KEYGUARD_SERVICE);
		return mKeyguardManager.inKeyguardRestrictedInputMode();
	}
}

上面代碼參考:https://blog.csdn.net/m_changgong/article/details/7608911,特此註明。

發佈留言