package com.thibaudperso.sonycamera.timelapse.ui.processing; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageRequest; import com.android.volley.toolbox.Volley; import com.thibaudperso.sonycamera.R; import com.thibaudperso.sonycamera.sdk.CameraAPI; import com.thibaudperso.sonycamera.sdk.TakePictureListener; import com.thibaudperso.sonycamera.timelapse.TimelapseApplication; import com.thibaudperso.sonycamera.timelapse.control.TimelapseSettings; import com.thibaudperso.sonycamera.timelapse.ui.finish.FinishActivity; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; public class ProcessingFragment extends Fragment { private final static String TIME_FORMAT = "HH:mm"; private CameraAPI mCameraAPI; private TextView batteryView; private TextView framesCountView; private ImageView imageReviewView; private ProgressBar nextPictureProgressBar; private TextView nextPictureProgressValue; private ProgressBar overallProgressBar; private TextView overallProgressValue; private TextView processingErrorMessageView; private boolean showLastFramePreview; private int intervalTime; private int framesCount; private boolean isUnlimitedMode; private WakeLock wakeLock; private int overlapsNumber; private RequestQueue imagesQueue; private Calendar nextPictureCalendar; private Handler mCountdownHandler; private Handler mTimelapseHandler; private int totalFrames; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); int initialDelay = preferences.getInt(TimelapseSettings.PREFERENCES_INITIAL_DELAY, TimelapseSettings.DEFAULT_INITIAL_DELAY); intervalTime = preferences.getInt(TimelapseSettings.PREFERENCES_INTERVAL_TIME, TimelapseSettings.DEFAULT_INTERVAL_TIME); totalFrames = preferences.getInt(TimelapseSettings.PREFERENCES_FRAMES_COUNT, TimelapseSettings.DEFAULT_FRAMES_COUNT); showLastFramePreview = preferences.getBoolean(TimelapseSettings.PREFERENCES_LAST_PICTURE_REVIEW, TimelapseSettings.DEFAULT_LAST_PICTURE_REVIEW); isUnlimitedMode = totalFrames == 0; framesCount = 0; overlapsNumber = 0; mCameraAPI = ((TimelapseApplication) getActivity().getApplication()).getCameraAPI(); //prepare wakelock for capture PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TimelapseProcessWakeLock"); imagesQueue = Volley.newRequestQueue(getActivity()); View rootView = inflater.inflate(R.layout.fragment_processing, container, false); TextView startTimeView = ((TextView) rootView.findViewById(R.id.startTime)); TextView framesCountTitleView = ((TextView) rootView.findViewById(R.id.framesCountTitle)); framesCountView = ((TextView) rootView.findViewById(R.id.framesCount)); batteryView = ((TextView) rootView.findViewById(R.id.battery)); overallProgressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); overallProgressValue = (TextView) rootView.findViewById(R.id.progress); nextPictureProgressBar = (ProgressBar) rootView.findViewById(R.id.nextPictureProgressBar); nextPictureProgressValue = (TextView) rootView.findViewById(R.id.nextPictureProgress); imageReviewView = (ImageView) rootView.findViewById(R.id.imageReview); processingErrorMessageView = (TextView) rootView.findViewById(R.id.processingErrorMessage); /* * Set activity fields */ // Set start time nextPictureCalendar = Calendar.getInstance(); nextPictureCalendar.add(Calendar.SECOND, initialDelay); String beginTime = new SimpleDateFormat(TIME_FORMAT, Locale.getDefault()) .format(nextPictureCalendar.getTime()); startTimeView.setText(beginTime); // Set frame counts framesCountTitleView.setText(isUnlimitedMode ? R.string.capture_frames_count : R.string.capture_frames_count_down); framesCountView.setText(String.valueOf(isUnlimitedMode ? 0 : totalFrames)); // Set progress bar if (!isUnlimitedMode) { overallProgressBar.setProgress(0); overallProgressBar.setMax(totalFrames); overallProgressValue.setText(getString(R.string.capture_progress_default)); } else { rootView.findViewById(R.id.progressLayout).setVisibility(View.GONE); } // Set next picture progress bar nextPictureProgressBar.setMax(intervalTime * 100); nextPictureProgressBar.setProgress(0); overallProgressValue.setText(String.format(getString(R.string.percent), 0)); mTimelapseHandler = new Handler(); mTimelapseHandler.postDelayed(mTimelapseRunnable, initialDelay * 1000); // Register wake lock to make sure the CPU keeps the app running wakeLock.acquire(); rootView.findViewById(R.id.processingStop).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mTimelapseHandler.removeCallbacks(mTimelapseRunnable); Intent intent = new Intent(getContext(), FinishActivity.class); startActivity(intent); } }); return rootView; } @Override public void onResume() { super.onResume(); getActivity().registerReceiver(this.myBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); mCountdownHandler = new Handler(); mCountdownHandler.post(mCountdownRunnable); } @Override public void onPause() { super.onPause(); mCountdownHandler.removeCallbacks(mCountdownRunnable); getActivity().unregisterReceiver(myBatteryReceiver); } @Override public void onDestroy() { super.onDestroy(); mTimelapseHandler.removeCallbacks(mTimelapseRunnable); wakeLock.release(); } private Runnable mCountdownRunnable = new Runnable() { @Override public void run() { double timeToNextPicture = (nextPictureCalendar.getTimeInMillis() - System.currentTimeMillis()) / 1000.; nextPictureProgressBar.setProgress((int) ((intervalTime - timeToNextPicture) * 100)); nextPictureProgressValue.setText(String.format(getString(R.string.seconds), (int) timeToNextPicture + 1)); mCountdownHandler.postDelayed(this, 100); } }; private Runnable mTimelapseRunnable = new Runnable() { @Override public void run() { takePicture(); nextPictureCalendar.add(Calendar.SECOND, intervalTime); framesCount++; if (isUnlimitedMode) framesCountView.setText(String.valueOf(framesCount)); else { float progressPercent = (float) framesCount / totalFrames * 100; overallProgressBar.setProgress(framesCount); overallProgressValue.setText(String.format(getString(R.string.percent), (int) progressPercent)); framesCountView.setText(String.valueOf(totalFrames - framesCount)); } if (isUnlimitedMode || totalFrames != framesCount) mTimelapseHandler.postDelayed(this, intervalTime * 1000); else { mCountdownHandler.removeCallbacks(mCountdownRunnable); nextPictureProgressValue.setText(String.format(getString(R.string.seconds), 0)); } } }; private void takePicture() { /* * Take a picture and notify the counter when it is done * this is necessary in order to avoid a further takePicture() while the camera * is still working on the last one */ mCameraAPI.takePicture(new TakePictureListener() { @Override public void onResult(String url) { if (showLastFramePreview) { ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap bitmap) { setPreviewImage(bitmap); } }, 0, 0, ImageView.ScaleType.CENTER_INSIDE, null, new Response.ErrorListener() { public void onErrorResponse(VolleyError error) { Log.v("DEBUG", error.getLocalizedMessage()); } }); imagesQueue.add(request); } } @Override public void onError(CameraAPI.ResponseCode responseCode, String responseMsg) { // Had an error, let's see which overlapsNumber++; String errorMessage; switch (responseCode) { case LONG_SHOOTING: // Shooting not yet finished // await picture and call this listener when finished // (or when again an error occurs) mCameraAPI.awaitTakePicture(this); errorMessage = getString(R.string.capture_frames_overlapping_message); break; default: errorMessage = getString(R.string.capture_frames_overlapping_message_old_api); } processingErrorMessageView.setText(String.format(errorMessage, overlapsNumber)); processingErrorMessageView.setVisibility(View.VISIBLE); } }); } private void setPreviewImage(final Bitmap preview) { if (getActivity() == null) { return; } getActivity().runOnUiThread(new Runnable() { @Override public void run() { imageReviewView.setImageBitmap(preview); } }); } /** * Handler for battery state */ private BroadcastReceiver myBatteryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context arg0, Intent arg1) { int bLevel = arg1.getIntExtra("level", 0); batteryView.setText(String.format(getString(R.string.percent), bLevel)); } }; }