package com.javispedro.wallmotion; import android.content.Context; import android.content.ContextWrapper; import android.content.SharedPreferences; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.text.TextUtils; import android.util.Log; import android.view.Surface; import androidx.preference.PreferenceManager; import java.io.IOException; public class Renderer extends ContextWrapper { private static final String TAG = "Renderer"; private SharedPreferences prefs; private MediaPlayer player; private int savedPosition; public Renderer(Context context) { super(context); prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.registerOnSharedPreferenceChangeListener(new PrefsListener()); } public boolean isActive() { return player != null; } public void start(Surface surface) { preparePlayer(surface); } public void stop() { if (player != null && player.isPlaying() && shouldSaveRestorePosition()) { savedPosition = player.getCurrentPosition(); Log.d(TAG, "storing current position: " + savedPosition + " ms"); } releasePlayer(); } public void reset() { releasePlayer(); savedPosition = 0; } private class PrefsListener implements SharedPreferences.OnSharedPreferenceChangeListener { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(getString(R.string.settings_video_file_key))) { Log.d(TAG, "video file key changed"); reset(); } else if (key.equals(getString(R.string.settings_display_restart_key))) { savedPosition = 0; } } } private class PlayerListener implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnSeekCompleteListener { @Override public boolean onError(MediaPlayer mp, int what, int extra) { Log.e(TAG, "MediaPlayer error: " + what + " extra:" + extra); return false; } @Override public void onPrepared(MediaPlayer mp) { Log.d(TAG, "onPrepared"); if (player != null && !player.isPlaying()) { Log.d(TAG, "start playing"); if (savedPosition > 0 && shouldSaveRestorePosition()) { restorePlayerPosition(); } player.start(); } } @Override public void onSeekComplete(MediaPlayer mp) { Log.d(TAG, "onSeekComplete: " + mp.getCurrentPosition() + " ms"); } } private void preparePlayer(Surface surface) { releasePlayer(); int scaling = getVideoScaling(); Log.d(TAG, "video scaling mode: " + scaling); Uri uri = getVideoFileUri(); if (uri == null) { Log.d(TAG, "no video URI: using missing video URI"); uri = getResourceVideoFileUri(R.raw.video_file_missing); scaling = MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT; } try { preparePlayer(surface, uri, scaling); } catch (Exception ex) { Log.e(TAG, "Could not open video URI: " + uri.toString() + " : " + ex.toString()); ex.printStackTrace(); releasePlayer(); uri = getResourceVideoFileUri(R.raw.video_file_error); scaling = MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT; try { preparePlayer(surface, uri, scaling); } catch (Exception ex2) { Log.e(TAG, "Could not open error video URI either: " + ex2.toString()); ex2.printStackTrace(); releasePlayer(); } } } private void preparePlayer(Surface surface, Uri uri, int scaling) throws IOException { Log.d(TAG, "creating player"); player = new MediaPlayer(); PlayerListener listener = new PlayerListener(); player.setOnErrorListener(listener); player.setOnPreparedListener(listener); player.setOnSeekCompleteListener(listener); player.setLooping(true); player.setVolume(0, 0); player.setSurface(surface); Log.d(TAG, "setting data source to " + uri.toString()); player.setDataSource(this, uri); player.setVideoScalingMode(scaling); player.prepareAsync(); } private void releasePlayer() { if (player != null) { Log.d(TAG, "releasing player"); player.release(); player = null; } } private void restorePlayerPosition() { Log.d(TAG, "seeking to " + savedPosition + " ms"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { player.seekTo(savedPosition, MediaPlayer.SEEK_CLOSEST); } else { player.seekTo(savedPosition); } } private Uri getVideoFileUri() { String new_value = prefs.getString(getString(R.string.settings_video_file_key), null); if (new_value != null) { return Uri.parse(new_value); } else { return null; } } private Uri getResourceVideoFileUri(int resId) { Uri.Builder builder = new Uri.Builder(); builder.scheme("android.resource").authority(getPackageName()).appendPath(Integer.toString(resId)); return builder.build(); } private int getVideoScaling() { String value = prefs.getString(getString(R.string.settings_display_scale_key), null); if (TextUtils.equals(value, getString(R.string.settings_display_scale_to_fit_with_cropping_key))) { return MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; } else { return MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT; } } private boolean shouldSaveRestorePosition() { return !prefs.getBoolean(getString(R.string.settings_display_restart_key), false); } }