From 804018d68e0bfb1eea8c26368aea0bb878dacbd8 Mon Sep 17 00:00:00 2001 From: "Warren R. Bank" Date: Fri, 6 Mar 2020 12:44:54 -0800 Subject: [PATCH] update the behavior of playback when screen is turned off - previously * all playback would stop when screen was turned off * no media could begin while screen was in the off state - now: * if the current playlist item has a video track - pause when the screen is turned off - resume when the screen is turned back on * if the current playlist item is audio-only - allow playback to continue when the screen is turned off - allow playback to begin while screen in in the off state - for both cases: * set a partial wakelock to prevent deep sleep * remove the partial wakelock when screen is turned back on additional tweaks: * spacebar key toggles pause/resume - useful with an air-mouse on a set-top box --- .../ui/exoplayer2/PlayerManager.java | 193 ++++++++++++++++-- .../ui/exoplayer2/VideoActivity.java | 121 ++++++++++- .../ui/exoplayer2/VideoSource.java | 20 ++ .../utils/SystemUtils.java | 34 +++ .../utils/WakeLockMgr.java | 26 +++ android-studio-project/constants.gradle | 4 +- 6 files changed, 366 insertions(+), 32 deletions(-) create mode 100644 android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/SystemUtils.java create mode 100644 android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/WakeLockMgr.java diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/PlayerManager.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/PlayerManager.java index 4517fe4..1f33d46 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/PlayerManager.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/PlayerManager.java @@ -39,7 +39,7 @@ import java.util.ArrayList; -/** Manages players and an internal media queue */ +/** Manages ExoPlayer and an internal media queue */ public final class PlayerManager implements EventListener { private final class MyArrayList extends ArrayList { @@ -113,7 +113,7 @@ public void run() { }; } - // Query state of player. + // Query state of ExoPlayer. /** * @return Is the instance of ExoPlayer able to immediately play from its current position. @@ -126,6 +126,15 @@ public boolean isPlayerReady() { return (state == Player.STATE_READY); } + /** + * @return Is the instance of ExoPlayer paused, but ready to resume playback. + */ + public boolean isPlayerPaused() { + return isPlayerReady() + ? !exoPlayer.getPlayWhenReady() + : false; + } + /** * @return The duration of the current video in milliseconds, or -1 if the duration is not known. */ @@ -149,10 +158,32 @@ public long getCurrentVideoPosition() { return positionMs; } + public String getCurrentVideoMimeType() { + if (exoPlayer == null) + return null; + + Format format = exoPlayer.getVideoFormat(); + if (format == null) + return null; + + return format.sampleMimeType; + } + + public String getCurrentAudioMimeType() { + if (exoPlayer == null) + return null; + + Format format = exoPlayer.getAudioFormat(); + if (format == null) + return null; + + return format.sampleMimeType; + } + // Queue manipulation methods. /** - * Plays a specified queue item in the current player. + * Plays a specified queue item in ExoPlayer. * * @param itemIndex The index of the item to play. */ @@ -181,7 +212,7 @@ public void addItem( String referer, float startPosition ) { - addItem(uri, caption, referer, startPosition, (Handler) null, (Runnable) null); + addItem(uri, caption, referer, startPosition, handler, (Runnable) null); } /** @@ -212,7 +243,7 @@ public void addItem( * @param sample The {@link VideoSource} to append. */ public void addItem(VideoSource sample) { - addItem(sample, (Handler) null, (Runnable) null); + addItem(sample, handler, (Runnable) null); } /** @@ -227,18 +258,40 @@ public void addItem( Handler handler, Runnable onCompletionAction ) { - // this can't happen: Intents without a uri are ignored + // this shouldn't happen: VideoActivity.handleIntent() has code to detect when playerManager has been released + if ((mediaQueue == null) || (concatenatingMediaSource == null)) + return; + + // this shouldn't happen: Intents without a uri are ignored if (sample.uri == null) { if ((handler != null) && (onCompletionAction != null)) handler.post(onCompletionAction); return; } + boolean isEnded = (exoPlayer != null) && !exoPlayer.isPlaying() && exoPlayer.getPlayWhenReady(); + + if (isEnded) { + exoPlayer.setPlayWhenReady(false); + exoPlayer.retry(); + } + + Runnable runCompletionAction = new Runnable() { + @Override + public void run() { + if (isEnded) + exoPlayer.setPlayWhenReady(true); + + if ((handler != null) && (onCompletionAction != null)) + handler.post(onCompletionAction); + } + }; + mediaQueue.add(sample); concatenatingMediaSource.addMediaSource( buildMediaSource(sample), handler, - onCompletionAction + runCompletionAction ); } @@ -246,6 +299,9 @@ public void addItem( * @return The size of the media queue. */ public int getMediaQueueSize() { + if (mediaQueue == null) + return 0; + return mediaQueue.size(); } @@ -268,6 +324,9 @@ public VideoSource getItem(int position) { * @return Whether the removal was successful. */ public boolean removeItem(int itemIndex) { + if ((mediaQueue == null) || (concatenatingMediaSource == null)) + return false; + concatenatingMediaSource.removeMediaSource(itemIndex); mediaQueue.remove(itemIndex); if ((itemIndex == currentItemIndex) && (itemIndex == mediaQueue.size())) { @@ -286,6 +345,9 @@ public boolean removeItem(int itemIndex) { * @return Whether the item move was successful. */ public boolean moveItem(int fromIndex, int toIndex) { + if ((mediaQueue == null) || (concatenatingMediaSource == null)) + return false; + // Player update. concatenatingMediaSource.moveMediaSource(fromIndex, toIndex); @@ -327,6 +389,8 @@ public void AirPlay_play( * @param positionSec The position as a fixed offset in seconds. */ public void AirPlay_scrub(float positionSec) { + if (exoPlayer == null) return; + if (exoPlayer.isCurrentWindowSeekable()) { long positionMs = ((long) positionSec) * 1000; exoPlayer.seekTo(currentItemIndex, positionMs); @@ -339,9 +403,11 @@ public void AirPlay_scrub(float positionSec) { * @param rate New rate of speed for video playback. The value 0.0 is equivalent to 'pause'. */ public void AirPlay_rate(float rate) { + if (exoPlayer == null) return; + if (rate == 0f) { // pause playback - if (exoPlayer.isPlaying()) + if (exoPlayer.getPlayWhenReady()) exoPlayer.setPlayWhenReady(false); } else { @@ -351,7 +417,7 @@ public void AirPlay_rate(float rate) { ); // resume playback if paused - if (!exoPlayer.isPlaying()) + if (!exoPlayer.getPlayWhenReady()) exoPlayer.setPlayWhenReady(true); } } @@ -392,6 +458,8 @@ public void AirPlay_queue( * Skip forward to the next {@link VideoSource} in the media queue. */ public void AirPlay_next() { + if (exoPlayer == null) return; + if (exoPlayer.hasNext()) { exoPlayer.next(); } @@ -401,6 +469,8 @@ public void AirPlay_next() { * Skip backward to the previous {@link VideoSource} in the media queue. */ public void AirPlay_previous() { + if (exoPlayer == null) return; + if (exoPlayer.hasPrevious()) { exoPlayer.previous(); } @@ -412,6 +482,8 @@ public void AirPlay_previous() { * @param audioVolume New rate audio volume level. The range of acceptable values is 0.0 to 1.0. The value 0.0 is equivalent to 'mute'. The value 1.0 is unity gain. */ public void AirPlay_volume(float audioVolume) { + if (exoPlayer == null) return; + exoPlayer.setVolume(audioVolume); // range of values: 0.0 (mute) - 1.0 (unity gain) } @@ -421,6 +493,8 @@ public void AirPlay_volume(float audioVolume) { * @param showCaptions */ public void AirPlay_captions(boolean showCaptions) { + if (exoPlayer == null) return; + boolean isDisabled = !showCaptions; DefaultTrackSelector.ParametersBuilder builder = trackSelector.getParameters().buildUpon(); @@ -445,13 +519,29 @@ public void AirPlay_captions(boolean showCaptions) { // Miscellaneous methods. /** - * Dispatches a given {@link KeyEvent} to the corresponding view of the current player. + * Dispatches a given {@link KeyEvent} to the ExoPlayer PlayerView. * * @param event The {@link KeyEvent}. * @return Whether the event was handled by the target view. */ public boolean dispatchKeyEvent(KeyEvent event) { - return playerView.dispatchKeyEvent(event); + boolean isHandled = (playerView != null) && playerView.dispatchKeyEvent(event); + + if (!isHandled && (exoPlayer != null) && (event.getRepeatCount() == 0) && (event.getAction() == KeyEvent.ACTION_DOWN)) { + // apply custom handler(s) + + switch(event.getKeyCode()) { + case KeyEvent.KEYCODE_SPACE : + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE : + if (isPlayerReady()) { + // toggle pause + exoPlayer.setPlayWhenReady( !exoPlayer.getPlayWhenReady() ); + } + break; + } + } + + return isHandled; } /** @@ -477,16 +567,27 @@ public void release() { * Releases the instance of ExoPlayer. */ private void release_exoPlayer() { - try { - playerView.setPlayer(null); - exoPlayer.removeListener(this); - exoPlayer.stop(true); - exoPlayer.release(); + if (playerView != null) { + try { + playerView.setPlayer(null); + } + catch (Exception e) {} + finally { + playerView = null; + } + } - playerView = null; - exoPlayer = null; + if (exoPlayer != null) { + try { + exoPlayer.stop(true); + exoPlayer.removeListener(this); + exoPlayer.release(); + } + catch (Exception e) {} + finally { + exoPlayer = null; + } } - catch (Exception e){} } // Player.EventListener implementation. @@ -510,6 +611,8 @@ public void onTimelineChanged( @Override public void onPlayerError(ExoPlaybackException error) { + if (exoPlayer == null) return; + if (error.type == ExoPlaybackException.TYPE_SOURCE) { exoPlayer.next(); } @@ -518,11 +621,16 @@ public void onPlayerError(ExoPlaybackException error) { // Internal methods. private void init() { + if (exoPlayer == null) return; + // Media queue management. exoPlayer.prepare(concatenatingMediaSource); } private void truncateQueue() { + if ((mediaQueue == null) || (concatenatingMediaSource == null)) + return; + mediaQueue.retainLast(); int last = concatenatingMediaSource.getSize() - 1; @@ -531,6 +639,8 @@ private void truncateQueue() { } private void updateCurrentItemIndex() { + if (exoPlayer == null) return; + int playbackState = exoPlayer.getPlaybackState(); int currentItemIndex = ((playbackState != Player.STATE_IDLE) && (playbackState != Player.STATE_ENDED)) @@ -544,9 +654,11 @@ private void updateCurrentItemIndex() { * Starts playback of the item at the given position. * * @param itemIndex The index of the item to play. - * @param playWhenReady Whether the player should proceed when ready to do so. + * @param playWhenReady Whether ExoPlayer should begin playback when item is ready. */ private void setCurrentItem(int itemIndex, boolean playWhenReady) { + if (exoPlayer == null) return; + maybeSetCurrentItemAndNotify(itemIndex); exoPlayer.setPlayWhenReady(playWhenReady); } @@ -563,6 +675,8 @@ private void maybeSetCurrentItemAndNotify(int currentItemIndex) { } private void seekToStartPosition(int currentItemIndex) { + if (exoPlayer == null) return; + VideoSource sample = getItem(currentItemIndex); if (sample == null) return; @@ -581,6 +695,9 @@ else if (position >= 1f) { long positionMs = ((long) position) * 1000; exoPlayer.seekTo(currentItemIndex, positionMs); } + else { + exoPlayer.seekToDefaultPosition(currentItemIndex); + } } private void setHttpRequestHeaders(int currentItemIndex) { @@ -597,6 +714,8 @@ private void setHttpRequestHeaders(int currentItemIndex) { } private void setHttpRequestHeader(String name, String value) { + if (httpDataSourceFactory == null) return; + httpDataSourceFactory.getDefaultRequestProperties().set(name, value); } @@ -610,6 +729,9 @@ private MediaSource buildMediaSource(VideoSource sample) { } private MediaSource buildUriMediaSource(VideoSource sample) { + if (httpDataSourceFactory == null) + return null; + Uri uri = Uri.parse(sample.uri); switch (sample.uri_mimeType) { @@ -625,6 +747,9 @@ private MediaSource buildUriMediaSource(VideoSource sample) { } private MediaSource buildCaptionMediaSource(VideoSource sample) { + if (httpDataSourceFactory == null) + return null; + if ((sample.caption == null) || (sample.caption_mimeType == null)) return null; @@ -635,13 +760,16 @@ private MediaSource buildCaptionMediaSource(VideoSource sample) { } private MediaSource buildRawVideoMediaSource(int rawResourceId) { + if (rawDataSourceFactory == null) + return null; + Uri uri = RawResourceDataSource.buildRawResourceUri(rawResourceId); return new ExtractorMediaSource.Factory(rawDataSourceFactory).createMediaSource(uri); } private void addRawVideoItem(int rawResourceId) { - addRawVideoItem(rawResourceId, (Handler) null, (Runnable) null); + addRawVideoItem(rawResourceId, handler, (Runnable) null); } private void addRawVideoItem( @@ -649,13 +777,34 @@ private void addRawVideoItem( Handler handler, Runnable onCompletionAction ) { + if ((mediaQueue == null) || (concatenatingMediaSource == null)) + return; + VideoSource sample = VideoSource.createVideoSource("raw", /* caption= */ (String) null, /* referer= */ (String) null, /* startPosition= */ 0f); + boolean isEnded = (exoPlayer != null) && !exoPlayer.isPlaying() && exoPlayer.getPlayWhenReady(); + + if (isEnded) { + exoPlayer.setPlayWhenReady(false); + exoPlayer.retry(); + } + + Runnable runCompletionAction = new Runnable() { + @Override + public void run() { + if (isEnded) + exoPlayer.setPlayWhenReady(true); + + if ((handler != null) && (onCompletionAction != null)) + handler.post(onCompletionAction); + } + }; + mediaQueue.add(sample); concatenatingMediaSource.addMediaSource( buildRawVideoMediaSource(rawResourceId), handler, - onCompletionAction + runCompletionAction ); } diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoActivity.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoActivity.java index a83512c..e3f489a 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoActivity.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoActivity.java @@ -1,6 +1,8 @@ package com.github.warren_bank.exoplayer_airplay_receiver.ui.exoplayer2; import com.github.warren_bank.exoplayer_airplay_receiver.R; +import com.github.warren_bank.exoplayer_airplay_receiver.utils.SystemUtils; +import com.github.warren_bank.exoplayer_airplay_receiver.utils.WakeLockMgr; import android.content.Intent; import android.os.Bundle; @@ -23,6 +25,9 @@ public class VideoActivity extends AppCompatActivity implements PlayerControlVie private PlayerView playerView; private Button selectTracksButton; private boolean isShowingTrackSelectionDialog; + private boolean isPlayingAudioWithScreenOff; + private boolean didPauseVideo; + private boolean didWakeLock; public PlayerManager playerManager; @@ -43,6 +48,9 @@ protected void onCreate(Bundle savedInstanceState) { selectTracksButton = (Button) findViewById(R.id.select_tracks_button); selectTracksButton.setOnClickListener(this); isShowingTrackSelectionDialog = false; + isPlayingAudioWithScreenOff = false; + didPauseVideo = false; + didWakeLock = false; playerManager = PlayerManager.createPlayerManager(/* context= */ this, playerView); @@ -57,11 +65,67 @@ public void onNewIntent(Intent intent) { @Override protected void onStop() { super.onStop(); - if (playerManager != null) { - playerManager.release(); - playerManager = null; + + if (isPlayingAudioWithScreenOff) + return; + + boolean isScreenOn, shouldFinish, shouldPause, shouldWakeLock; + + isScreenOn = SystemUtils.isScreenOn(/* context= */ this); + shouldFinish = isScreenOn + || (playerManager == null) + || !playerManager.isPlayerReady(); + shouldPause = !shouldFinish + && !playerManager.isPlayerPaused() + && !TextUtils.isEmpty(playerManager.getCurrentVideoMimeType()); + shouldWakeLock = !shouldFinish + && !shouldPause; + + if (shouldFinish) { + if (playerManager != null) { + playerManager.release(); + playerManager = null; + } + finish(); + } + else if (shouldPause) { + // screen is turned off, player is ready and not paused, source contains a video track. + playerManager.AirPlay_rate(0f); + } + else if (shouldWakeLock) { + // screen is turned off, player is ready and not paused, source only contains an audio track. + // allow it to continue with the screen turned off. + + // this wakelock is to keep the Activity responsive to HTTP commands. + // ExoPlayer would continue playing music in the queue without it. + WakeLockMgr.acquire(/* context= */ this); } - finish(); + + didPauseVideo = shouldPause; + didWakeLock = shouldWakeLock; + } + + @Override + protected void onRestart () { + super.onRestart(); + + if (isPlayingAudioWithScreenOff) { + boolean isScreenOn = SystemUtils.isScreenOn(/* context= */ this); + + if (isScreenOn) + isPlayingAudioWithScreenOff = false; + else + return; + } + + if (didPauseVideo && (playerManager != null)) + playerManager.AirPlay_rate(1f); + + if (didWakeLock) + WakeLockMgr.release(); + + didPauseVideo = false; + didWakeLock = false; } // Activity input. @@ -109,15 +173,12 @@ private void handleIntent(Intent intent) { if (intent == null) return; - if (isFinishing()) { + if (isFinishing() || (playerManager == null)) { setIntent(intent); recreate(); return; } - if (playerManager == null) - return; - String mode = intent.getStringExtra("mode"); String uri = intent.getStringExtra("uri"); String caption = intent.getStringExtra("caption"); @@ -143,6 +204,50 @@ private void handleIntent(Intent intent) { else /* if ((mode != null) && mode.equals("play")) */ { playerManager.AirPlay_play(uri, caption, referer, startPosition); Log.d(tag, "play video: url = " + uri + "; position = " + startPosition + "; captions = " + caption + "; referer = " + referer); + + if (!isPlayingAudioWithScreenOff) { + boolean isScreenOn = SystemUtils.isScreenOn(/* context= */ this); + + if (!isScreenOn) { + // user has initiated media playback while the screen is turned off + // + // lifecycle with screen off: + // - onCreate() => handleIntent() => onStop() + // - onNewIntent() => handleIntent() => onRestart() => onStop() + // + // onStop() runs immediately + // - need to be careful that the HTTP command to begin playback + // doesn't construct an instance of ExoPlayer.. + // only to immediately send it to garbage collection + // + // - under normal conditions: + // * media playback is started with the screen on + // * the Activity opens in the foreground + // * ExoPlayer has time to load metadata for items in the playlist + // * when the screen is subsequently turned off, + // onStop() has the ability to query whether the current playlist item is audio-only + // + // - in this situation: + // * onStop() can't query metadata about the current playlist item, + // because ExoPlayer hasn't been given time to gather this info + // + // only audio media should be allowed to begin playback when the screen is off. + // since the URL for the media is currently known, a viable workaround is to: + // - use a regex to test whether the URL matches a known audio file extension + // - set a variable to serves as a flag that indicates when this feature is active + // - clear the flag when the screen is turned back on + + isPlayingAudioWithScreenOff = VideoSource.isAudioFileUrl(uri); + + if (isPlayingAudioWithScreenOff) { + // this wakelock is to keep the Activity responsive to HTTP commands. + // ExoPlayer would continue playing music in the queue without it. + + WakeLockMgr.acquire(/* context= */ this); + didWakeLock = true; + } + } + } } } diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoSource.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoSource.java index b6a63d8..9c29dbf 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoSource.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/ui/exoplayer2/VideoSource.java @@ -152,5 +152,25 @@ public static String get_caption_mimeType(String caption) { return mimeType; } + // =========================================================================== + // audio file-extension + + public static Pattern audio_regex = Pattern.compile("\\.(mp3|m4a|ogg|wav|flac)(?:[\\?#]|$)"); + + public static String get_audio_fileExtension(String uri) { + if (uri == null) return null; + + Matcher matcher = VideoSource.audio_regex.matcher(uri.toLowerCase()); + String file_ext = matcher.find() + ? matcher.group(1) + : null; + + return file_ext; + } + + public static boolean isAudioFileUrl(String uri) { + return (get_audio_fileExtension(uri) != null); + } + // =========================================================================== } diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/SystemUtils.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/SystemUtils.java new file mode 100644 index 0000000..1c5d66b --- /dev/null +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/SystemUtils.java @@ -0,0 +1,34 @@ +package com.github.warren_bank.exoplayer_airplay_receiver.utils; + +import android.content.Context; +import android.os.Build; +import android.os.PowerManager; +import android.hardware.display.DisplayManager; +import android.view.Display; + +public class SystemUtils { + + /** + * Is the power state of the display screen on? + * @param context + * @return true when (at least one) screen is turned on + * + * source: https://stackoverflow.com/a/28747907 + */ + public static boolean isScreenOn(Context context) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + boolean screenOn = false; + for (Display display : dm.getDisplays()) { + if (display.getState() != Display.STATE_OFF) { + screenOn = true; + } + } + return screenOn; + } else { + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + return pm.isScreenOn(); + } + } + +} diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/WakeLockMgr.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/WakeLockMgr.java new file mode 100644 index 0000000..a8b143c --- /dev/null +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/WakeLockMgr.java @@ -0,0 +1,26 @@ +package com.github.warren_bank.exoplayer_airplay_receiver.utils; + +import android.content.Context; +import android.os.PowerManager; + +public final class WakeLockMgr { + private static PowerManager.WakeLock wakeLock; + + public static void acquire(Context context) { + release(); + + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, + "WakeLock" + ); + wakeLock.acquire(); + } + + public static void release() { + if (wakeLock != null) { + wakeLock.release(); + wakeLock = null; + } + } +} diff --git a/android-studio-project/constants.gradle b/android-studio-project/constants.gradle index 6273b0a..23d1df7 100644 --- a/android-studio-project/constants.gradle +++ b/android-studio-project/constants.gradle @@ -1,6 +1,6 @@ project.ext { - releaseVersionCode = Integer.parseInt("001000616", 10) - releaseVersion = '001.00.06-16API' + releaseVersionCode = Integer.parseInt("001000716", 10) + releaseVersion = '001.00.07-16API' minSdkVersion = 16 targetSdkVersion = 28 compileSdkVersion = 28