<repo_name>7odri9o/Lanterna<file_sep>/app/src/main/java/br/com/kimstorm/lanterna/LanternaApplication.java
package br.com.kimstorm.lanterna;

import android.app.Application;

public class LanternaApplication extends Application {

    private static boolean isActivityVisible;

    public static boolean isActivityVisible() {
        return isActivityVisible;
    }

    public static void activityResumed() {
        isActivityVisible = true;
    }

    public static void activityPaused() {
        isActivityVisible = false;
    }
}
<file_sep>/app/src/main/java/br/com/kimstorm/lanterna/MainFragment.java
package br.com.kimstorm.lanterna;

import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.os.BatteryManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainFragment extends Fragment {

    public static final int CAMERA_ACCESS_REQUEST_CODE = 100;
    public static final float BATTERY_MINIMAL_PERCENTAGE = (float) 0.25;

    private Activity activity;
    private BroadcastReceiver mBatteryOkayReceiver;

    private CaptureRequest.Builder mBuilder;
    private CameraCaptureSession mSession;
    private CameraDevice mCameraDevice;
    private CameraManager mCameraManager;
    private SurfaceTexture mSurfaceTexture;

    private ImageButton flashSwitchButton;
    private boolean isFlashOn;
    private boolean isShowingLowBatteryMessage;

    public MainFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        flashSwitchButton = (ImageButton) rootView.findViewById(R.id.flashlight_switch_button);
        flashSwitchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isFlashOn) {
                    turnOffFlash();
                } else {
                    turnOnFlash();
                }
            }
        });

        return rootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        this.activity = getActivity();
    }

    @Override
    public void onStart() {
        super.onStart();
        startCamera();
    }

    @Override
    public void onResume() {
        super.onResume();
        verifyLowBattery();
    }

    @Override
    public void onStop() {
        super.onStop();
        close();
        if (mBatteryOkayReceiver != null) {
            activity.unregisterReceiver(mBatteryOkayReceiver);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case CAMERA_ACCESS_REQUEST_CODE:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(activity, getString(R.string.camera_permission_not_granted_message), Toast.LENGTH_SHORT).show();
                } else {
                    startCamera();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                break;
        }
    }

    private void startCamera() {
        mCameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        String cameraId = getCameraId();

        if (!cameraId.isEmpty()) {
            try {
                if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(
                            activity,
                            new String[] {  android.Manifest.permission.CAMERA},
                            CAMERA_ACCESS_REQUEST_CODE);
                    return;
                }
                mCameraManager.openCamera(cameraId, new MyCameraDeviceStateCallback(), null);
            } catch (CameraAccessException e) {
                Toast.makeText(activity,
                        getString(R.string.follow_problem_ocurr_message) + e.getMessage(),
                        Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(activity, getString(R.string.camera_not_found_message), Toast.LENGTH_SHORT).show();
        }
    }

    @SuppressWarnings("ConstantConditions")
    @NonNull
    private String getCameraId() {
        String cameraId = "";
        try {
            for (String id : mCameraManager.getCameraIdList()) {
                CameraCharacteristics characteristics =  mCameraManager
                        .getCameraCharacteristics(id);
                if (characteristics.get(CameraCharacteristics.LENS_FACING)
                        == CameraCharacteristics.LENS_FACING_FRONT) {
                    continue;
                }
                if (characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
                    cameraId = id;
                    break;
                }
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return cameraId;
    }

    private void turnOnFlash() {
        try {
            mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
            mSession.capture(mBuilder.build(), null, null);
            isFlashOn = true;
            toggleButtonImage();
        } catch (CameraAccessException e) {
            Toast.makeText(activity, getString(R.string.problem_when_starting_flashlight_message), Toast.LENGTH_SHORT).show();
            if (isFlashOn) {
                turnOffFlash();
            }
        }
    }

    private void turnOffFlash() {
        try {
            mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
            mSession.capture(mBuilder.build(), null, null);
            isFlashOn = false;
            toggleButtonImage();
        } catch (CameraAccessException e) {
            Toast.makeText(activity, getString(R.string.problem_when_finish_flashlight_message), Toast.LENGTH_SHORT).show();
        }
    }

    private void toggleButtonImage() {
        if (isFlashOn) {
            flashSwitchButton.setImageResource(R.drawable.switch_button_on);
            flashSwitchButton.setContentDescription(getString(R.string.switch_button_turn_on_content_description));
        } else {
            flashSwitchButton.setImageResource(R.drawable.switch_button_off);
            flashSwitchButton.setContentDescription(getString(R.string.switch_button_turn_off_content_description));
        }
    }

    @SuppressWarnings("ConstantConditions")
    private Size getSmallestSize(String cameraId) throws CameraAccessException {
        Size[] outputSizes = mCameraManager.getCameraCharacteristics(cameraId)
                .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                .getOutputSizes(SurfaceTexture.class);
        if (outputSizes == null || outputSizes.length == 0) {
            throw new IllegalStateException(
                    "Camera " + cameraId + "doesn't support any outputSize.");
        }
        Size chosen = outputSizes[0];
        for (Size s : outputSizes) {
            if (chosen.getWidth() >= s.getWidth() && chosen.getHeight() >= s.getHeight()) {
                chosen = s;
            }
        }
        return chosen;
    }

    private void close() {
        if (mCameraDevice == null || mSession == null) {
            return;
        }
        try {
            mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
            mSession.capture(mBuilder.build(), null, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        mBuilder = null;
        mSession.close();
        mSurfaceTexture.release();
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        if (isFlashOn) {
            isFlashOn = false;
            toggleButtonImage();
        }
        mSession = null;
    }

    private void verifyLowBattery() {
        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = activity.registerReceiver(null, ifilter);

        assert batteryStatus != null;
        int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

        float batteryPct = level / (float)scale;

        if (batteryPct < BATTERY_MINIMAL_PERCENTAGE) {
            showLowBatterMessage(true);
            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_OKAY);
            mBatteryOkayReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (LanternaApplication.isActivityVisible()) {
                        if (intent.getAction().equals(Intent.ACTION_BATTERY_OKAY)) {
                            if (isShowingLowBatteryMessage) {
                                showLowBatterMessage(false);
                            }
                        }
                    }
                }
            };
            activity.registerReceiver(mBatteryOkayReceiver, filter);
        }
    }

    private void showLowBatterMessage(boolean mustShowMessage) {
        TextView messageTextView = (TextView) activity.findViewById(R.id.low_battery_message_textview);
        messageTextView.setVisibility(mustShowMessage ? View.VISIBLE : View.GONE);
        isShowingLowBatteryMessage = mustShowMessage;
    }

    private class MyCameraDeviceStateCallback extends CameraDevice.StateCallback {

        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCameraDevice = camera;
            try {
                mBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                mBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);

                mSurfaceTexture = new SurfaceTexture(1);
                Size size = getSmallestSize(mCameraDevice.getId());
                mSurfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
                Surface surface = new Surface(mSurfaceTexture);

                List<Surface> surfaceList = new ArrayList<>();
                surfaceList.add(surface);
                mBuilder.addTarget(surface);

                mCameraDevice.createCaptureSession(surfaceList, new MyCameraCaptureSessionStateCallback(), null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
        }
    }

    private class MyCameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback {

        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            mSession = session;
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
        }
    }
}
