/* * Copyright 2015 Ludwig Andersson * * This file is part of Thermospy-android. * * Thermospy-android is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Thermospy-android is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermospy-android. If not, see <http://www.gnu.org/licenses/>. */ package com.luan.thermospy.android.fragments.setup; import android.app.Activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; 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 com.android.volley.RequestQueue; import com.luan.thermospy.android.R; import com.luan.thermospy.android.core.Coordinator; import com.luan.thermospy.android.core.pojo.AspectRatio; import com.luan.thermospy.android.core.pojo.Boundary; import com.luan.thermospy.android.core.rest.GetImageReq; import com.luan.thermospy.android.core.rest.ResetCameraAndGetImageReq; import com.luan.thermospy.android.core.rest.SetImgBoundsReq; import com.soundcloud.android.crop.Crop; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * The SetupBoundary class is responsible for fetching an image from the server and requesting the * user to specify the bounds of the image where the server will try to parse the temperature. * * When the view is created a request to fetch the last image is made. When the image is received * an intent is sent to the CropLib class which takes care of the cropping. * * If the user specifies a boundary and press Done the view will notify its listener. * If the user cancels the user returns to the first view of the setup. */ public class SetupBoundary extends Fragment implements GetImageReq.OnGetImgListener, SetImgBoundsReq.OnSetImgBoundsListener, ResetCameraAndGetImageReq.OnGetImgListener, DialogInterface.OnCancelListener { private File mFileTemp = null; private OnSetupBoundaryListener mListener; private final static String LOG_TAG = SetupBoundary.class.getCanonicalName(); @Override public void onCancel(DialogInterface dialog) { mListener.onSetupServerAborted(); } static interface Arguments { String IP_ADDRESS = "ipaddress"; String PORT = "port"; } private String mIpAddress; private int mPort; private RequestQueue mRequestQueue; ProgressDialog mProgress = null; GetImageReq mGetImageReq; ResetCameraAndGetImageReq mResetCameraAndGetImageReq; SetImgBoundsReq mSetImgBoundsReq; public static SetupBoundary newInstance(String ip, int port) { Bundle args = new Bundle(); args.putString(Arguments.IP_ADDRESS, ip); args.putInt(Arguments.PORT, port); SetupBoundary fragment = new SetupBoundary(); fragment.setArguments(args); return fragment; } public SetupBoundary() { // Required empty public constructor } private void takePhoto() { if (mProgress == null) { mProgress = new ProgressDialog(getActivity()); mProgress.setOnCancelListener(this); } mProgress.setCanceledOnTouchOutside(false); mProgress.setTitle("Please wait"); mProgress.setMessage("Fetching image from camera..."); mResetCameraAndGetImageReq.request(mIpAddress, mPort); mProgress.show(); } private void requestBounds(Boundary b) { Log.d(this.getClass().getName(), "Set bounds!"); mProgress.setTitle("Please wait"); mProgress.setMessage("Applying settings..."); mSetImgBoundsReq.setBounds(b); mSetImgBoundsReq.request(mIpAddress, mPort); mProgress.show(); } private void runImgCrop() { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity()); int val = Integer.parseInt(settings.getString(getString(R.string.pref_key_aspect_ratio), "1")); AspectRatio ratio = AspectRatio.fromInt(val); Uri outputUri = Uri.fromFile(new File(getActivity().getCacheDir(), "cropped")); new Crop(Uri.fromFile(mFileTemp)).output(outputUri).withAspect(ratio.getX(),ratio.getY()).start(getActivity(), this); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == Crop.REQUEST_CROP && resultCode == Activity.RESULT_OK) { Rect rect = Crop.getRect(data); Boundary b = new Boundary(rect.left, rect.top, rect.width(), rect.height()); requestBounds(b); } else if (resultCode == Crop.RESULT_REFRESH) { takePhoto(); } else { mListener.onSetupServerAborted(); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mIpAddress = savedInstanceState.getString(Arguments.IP_ADDRESS, mIpAddress); mPort = savedInstanceState.getInt(Arguments.PORT, mPort); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_set_image_bounds, container, false); // No view exists for this dude. return v; } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnSetupBoundaryListener) activity; mIpAddress = getArguments().getString(Arguments.IP_ADDRESS); mPort = getArguments().getInt(Arguments.PORT); mRequestQueue = Coordinator.getInstance().getRequestQueue(); mSetImgBoundsReq = new SetImgBoundsReq(mRequestQueue, this, new Boundary(0,0,0,0)); mGetImageReq = new GetImageReq(mRequestQueue, this); mResetCameraAndGetImageReq = new ResetCameraAndGetImageReq(mRequestQueue, this); takePhoto(); } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnAlarmFragmentListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; mSetImgBoundsReq = null; mGetImageReq = null; mResetCameraAndGetImageReq = null; } @Override public void onDestroy() { super.onDestroy(); if (mProgress != null && mProgress.isShowing()) { mProgress.dismiss(); } mSetImgBoundsReq.cancel(); mGetImageReq.cancel(); mResetCameraAndGetImageReq.cancel(); } @Override public void onStop() { super.onStop(); if (mProgress != null && mProgress.isShowing()) { mProgress.dismiss(); } mSetImgBoundsReq.cancel(); mGetImageReq.cancel(); mResetCameraAndGetImageReq.cancel(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(Arguments.IP_ADDRESS, mIpAddress); outState.putInt(Arguments.PORT, mPort); } @Override public void onGetImgRecv(Bitmap bitmap) { //create a file to write bitmap data mFileTemp = new File(getActivity().getCacheDir(), "thermospy.png"); try { mFileTemp.createNewFile(); //Convert bitmap to byte array ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos); byte[] bitmapData = bos.toByteArray(); //write the bytes in file FileOutputStream fos = new FileOutputStream(mFileTemp); fos.write(bitmapData); runImgCrop(); mProgress.dismiss(); } catch (IOException e) { Log.e(LOG_TAG, "Failed to run crop activity!", e); mProgress.dismiss(); mListener.onSetupServerAborted(); } } @Override public void onGetImgError() { mListener.onSetupServerAborted(); } @Override public void onSetImgBoundsRecv(Boundary imgBounds) { mProgress.dismiss(); mListener.onBoundsSpecified(imgBounds); } @Override public void onSetImgBoundsError() { mProgress.hide(); mListener.onSetupServerAborted(); } public interface OnSetupBoundaryListener { public void onBoundsSpecified(Boundary bounds); public void onSetupServerAborted(); } }