> 鎖屏聽音樂(音頻),沒有鎖屏看視頻
Android系統亮屏、鎖屏、屏幕解鎖事件(解決部分手機亮屏後未解鎖即進入resume狀態)- http://blog.csdn.net/oracleot/article/details/20378453
Android 實現鎖屏的較完美方案- https://segmentfault.com/a/1190000003075989
https://github.com/android/platform_frameworks_policies_base/blob/master/phone/com/android/internal/policy/impl/KeyguardViewManager.java
Android QQ音樂/酷狗音樂鎖屏控制實現原理,酷狗鎖屏- https://blog.csdn.net/yangxi_pekin/article/details/50456763
Android 監聽屏幕鎖屏,用戶解鎖- http://blog.csdn.net/mengweiqi33/article/details/18094221
最近在做視頻播放器的時候,遇到一個問題,在用戶播放視頻然後鎖屏之後,視頻播放器仍然在繼續播放,遇到類似手機系統狀態改變的問題的時候,首先想到了廣播(don't call me,i will call you);在網上搜羅了一個方法,做個總結;
public class ScreenListener {
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private ScreenStateListener mScreenStateListener;
public ScreenListener(Context context) {
mContext = context;
mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
* screen狀態廣播接收者
*/
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { // 開屏
mScreenStateListener.onScreenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 鎖屏
mScreenStateListener.onScreenOff();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解鎖
mScreenStateListener.onUserPresent();
}
}
}
/**
* 開始監聽screen狀態
*
* @param listener
*/
public void begin(ScreenStateListener listener) {
mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
* 獲取screen狀態
*/
private void getScreenState() {
PowerManager manager = (PowerManager) mContext
.getSystemService(Context.POWER_SERVICE);
if (manager.isScreenOn()) {
if (mScreenStateListener != null) {
mScreenStateListener.onScreenOn();
}
} else {
if (mScreenStateListener != null) {
mScreenStateListener.onScreenOff();
}
}
}
/**
* 停止screen狀態監聽
*/
public void unregisterListener() {
mContext.unregisterReceiver(mScreenReceiver);
}
/**
* 啟動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);
}
public interface ScreenStateListener {// 返回給調用者屏幕狀態信息
public void onScreenOn();
public void onScreenOff();
public void onUserPresent();
}
}
在上面的代碼中,用到了動態註冊廣播,在需要監聽屏幕狀態的activity中,當不需要監聽的時候,如activity finish的時候,使用unregisterListener解除廣播監聽;
下面是在Activity中調用;
ScreenListener l = new ScreenListener(this);
l.begin(new ScreenStateListener() {
@Override
public void onUserPresent() {
Log.e("onUserPresent", "onUserPresent");
}
@Override
public void onScreenOn() {
Log.e("onScreenOn", "onScreenOn");
}
@Override
public void onScreenOff() {
Log.e("onScreenOff", "onScreenOff");
}
});
通過以上步驟即實現了對屏幕狀態的監聽.
> 音視頻播放焦點及暫停
MediaPlayer聲音自動停止、恢復,一鍵靜音等功能。
-- 音頻焦點
Android音頻焦點詳解(上)- http://blog.csdn.net/wangjihuanghun/article/details/54957459
Android音頻焦點詳解(下)源碼詳解- http://blog.csdn.net/wangjihuanghun/article/details/56069283
Android AudioManager處理兩個播放器同時有聲音- http://blog.csdn.net/shuaicike/article/details/39930823
博客Demo- https://github.com/landptf/BlogDemo
// 獲取AudioManager實例
final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener l = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {// 焦點獲取到了,那繼續播放,並恢復音量。
AudioTrack audioTrack = mAudioTrack;
if (audioTrack != null) {
audioTrack.setStereoVolume(1.0f, 1.0f);
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
audioTrack.flush();
audioTrack.play();
}
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {// 焦點丟失了,暫停播放。
AudioTrack audioTrack = mAudioTrack;
if (audioTrack != null) {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.pause();
}
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // 焦點丟失了,但是允許在降低音量的前提下繼續播放,那麼降低聲音。
AudioTrack audioTrack = mAudioTrack;
if (audioTrack != null) {
audioTrack.setStereoVolume(0.5f, 0.5f);
}
}
}
};
// 因為這裡要獲得的焦點無法預知時長,因此用AUDIOFOCUS_GAIN模式。
int requestCode = am.requestAudioFocus(l, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (requestCode == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// 成功獲取到了焦點。那啟動播放
AudioTrack audioTrack = mAudioTrack;
if (audioTrack != null) {
audioTrack.setStereoVolume(1.0f, 1.0f);
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
audioTrack.flush();
audioTrack.play();
}
}
}else{ // 沒有獲取到音頻焦點。那不播放聲音
AudioTrack audioTrack = mAudioTrack;
if (audioTrack != null) {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.pause();
}
}
}
> 音頻焦點
Android 音頻焦點(Audio Focus)- https://blog.csdn.net/suyimin2010/article/details/79479323
Android音頻焦點處理- https://blog.csdn.net/zwlove5280/article/details/84881019
從Android 8.0開始(API 26),請求音頻焦點的方式以及系統對音頻焦點變化的管理有些微妙的變化。首先,對音頻焦點變化的管理的變化體現在兩個方面,延遲獲取焦點和自動降低音量。
-- 實例1
public class AudioFocusManager implements AudioManager.OnAudioFocusChangeListener {
private AudioManager mAudioManager;
private AudioFocusRequest mFocusRequest;
private AudioAttributes mAudioAttributes;
private onRequestFocusResultListener mOnRequestFocusResultListener;
private OnAudioFocusChangeListener mAudioFocusChangeListener;
public AudioFocusManager(Context context) {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
/**
* Request audio focus.
*/
public void requestFocus() {
int result;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (mFocusRequest == null) {
if (mAudioAttributes == null) {
mAudioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
}
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(mAudioAttributes)
.setWillPauseWhenDucked(true)
.setOnAudioFocusChangeListener(this)
.build();
}
result = mAudioManager.requestAudioFocus(mFocusRequest);
} else {
result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
if (mOnRequestFocusResultListener != null) {
mOnRequestFocusResultListener.onHandleResult(result);
}
}
@Override
public void onAudioFocusChange(int focusChange) {
if (mAudioFocusChangeListener != null) {
mAudioFocusChangeListener.onAudioFocusChange(focusChange);
}
}
/**
* Release audio focus.
*/
public void releaseAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mAudioManager.abandonAudioFocusRequest(mFocusRequest);
} else {
mAudioManager.abandonAudioFocus(this);
}
}
/**
* Handle the result of audio focus.
*/
public interface onRequestFocusResultListener {
void onHandleResult(int result);
}
public void setOnHandleResultListener(onRequestFocusResultListener listener) {
mOnRequestFocusResultListener = listener;
}
/**
* Same as AudioManager.OnAudioFocusChangeListener.
*/
public interface OnAudioFocusChangeListener {
void onAudioFocusChange(int focusChange);
}
public void setOnAudioFocusChangeListener(OnAudioFocusChangeListener listener) {
mAudioFocusChangeListener = listener;
}
}
-- 實例2
public class AudioFocusUtils {
private static AudioFocusUtils mInstance;
private AudioManager mAudioManager;
private AudioFocusRequest mFocusRequest;
private AudioAttributes mAudioAttributes;
private AudioFocusUtils() {}
public static AudioFocusUtils getInstance() {
if (mInstance == null) {
synchronized (AudioFocusUtils.class) {
mInstance = new AudioFocusUtils();
}
}
return mInstance;
}
/**
* 獲取音頻焦點
*/
public void requestAudioFocus(Context context) {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (mAudioManager != null) {
// mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
int result;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (mFocusRequest == null) {
if (mAudioAttributes == null) {
mAudioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
}
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(mAudioAttributes)
.setWillPauseWhenDucked(true)
.setOnAudioFocusChangeListener(mAudioFocusListener)
.build();
}
result = mAudioManager.requestAudioFocus(mFocusRequest);
} else {
result = mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
}
}
private int mLossTransientCount;
/**
* 音頻焦點監聽
*/
public AudioManager.OnAudioFocusChangeListener mAudioFocusListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch(focusChange){
case AudioManager.AUDIOFOCUS_LOSS:
Log.d("desaco", "AUDIOFOCUS_LOSS");
// 對應AUDIOFOCUS_GAIN
// 表示音頻焦點請求者需要長期佔有焦點,這裡一般需要stop播放和釋放
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Log.d("desaco", "AUDIOFOCUS_LOSS_TRANSIENT");
// 對應AUDIOFOCUS_GAIN_TRANSIENT
// 表示音頻焦點請求者需要短暫佔有焦點,這裡一般需要pause播放
mLossTransientCount ++;
// if (mLossTransientCount == 2) {
// Log.d("desaco", "mLossTransientCount == 2");
// VoiceMainController.getInstance().dismissVr();
// }
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Log.d("desaco", "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
// 對應AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
// 表示音頻焦點請求者需要佔有焦點,但是我也可以繼續播放,只是需要降低音量或音量置為0
break;
case AudioManager.AUDIOFOCUS_GAIN:
Log.d("desaco", "AUDIOFOCUS_GAIN");
// 獲得焦點,這裡可以進行恢復播放
mLossTransientCount = 0;
break;
}
}
};
/**
* 釋放音頻焦點及資源
* @param context
*/
public void abandonAudioFocus(Context context) {
if (mAudioManager != null) {
mAudioManager.abandonAudioFocus(mAudioFocusListener);
}
}
}
> 音頻焦點
/** * 音頻焦點處理 */public class AudioFocusUtils { private static AudioFocusUtils mInstance; private AudioFocusUtils() {} public static AudioFocusUtils getInstance() { if (mInstance == null) { synchronized (AudioFocusUtils.class) { mInstance = new AudioFocusUtils(); } } return mInstance; } /** * 獲取音頻焦點 */ public void requestAudioFocus(Context context) { AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (am != null) { am.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } } /** * 音頻焦點監聽 */ public AudioManager.OnAudioFocusChangeListener mAudioFocusListener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { switch(focusChange){ case AudioManager.AUDIOFOCUS_LOSS: Log.d("desaco", "AUDIOFOCUS_LOSS"); // 對應AUDIOFOCUS_GAIN // 表示音頻焦點請求者需要長期佔有焦點,這裡一般需要stop播放和釋放 break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: Log.d("desaco", "AUDIOFOCUS_LOSS_TRANSIENT"); // 對應AUDIOFOCUS_GAIN_TRANSIENT // 表示音頻焦點請求者需要短暫佔有焦點,這裡一般需要pause播放 break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: Log.d("desaco", "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"); // 對應AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK // 表示音頻焦點請求者需要佔有焦點,但是我也可以繼續播放,只是需要降低音量或音量置為0 break; case AudioManager.AUDIOFOCUS_GAIN: Log.d("desaco", "AUDIOFOCUS_GAIN"); // 獲得焦點,這裡可以進行恢復播放 break; } } }; /** * 釋放音頻焦點及資源 * @param context */ public void abandonAudioFocus(Context context) { AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (am != null) { am.abandonAudioFocus(mAudioFocusListener); } }}