de.bahnhoefe.deutschlands.bahnhofsfotos.DetailsActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.bahnhoefe.deutschlands.bahnhofsfotos.DetailsActivity.java

Source

package de.bahnhoefe.deutschlands.bahnhofsfotos;

import android.animation.ValueAnimator;
import android.app.ActionBar;
import android.app.ProgressDialog;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NavUtils;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLConnection;

import static android.content.Intent.createChooser;
import static android.graphics.Color.WHITE;
import de.bahnhoefe.deutschlands.bahnhofsfotos.Dialogs.MyDataDialogFragment;
import de.bahnhoefe.deutschlands.bahnhofsfotos.Dialogs.SimpleDialogs;
import de.bahnhoefe.deutschlands.bahnhofsfotos.db.BahnhofsDbAdapter;
import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Bahnhof;
import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
import de.bahnhoefe.deutschlands.bahnhofsfotos.model.License;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.BitmapAvailableHandler;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.BitmapCache;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.ConnectionUtil;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.NavItem;
import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Timetable;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class DetailsActivity extends AppCompatActivity
        implements ActivityCompat.OnRequestPermissionsResultCallback, BitmapAvailableHandler {

    // Names of Extras that this class reacts to
    public static final String EXTRA_TAKE_FOTO = "DetailsActivityTakeFoto";
    public static final String EXTRA_BAHNHOF = "bahnhof";
    public static final int STORED_FOTO_WIDTH = 1920;
    public static final int STORED_FOTO_QUALITY = 95;

    private static final String TAG = DetailsActivity.class.getSimpleName();
    private static final int REQUEST_TAKE_PICTURE_PERMISSION = 0;
    private static final int REQUEST_SELECT_PICTURE_PERMISSION = 1;
    private static final int REQUEST_TAKE_PICTURE = 2;
    private static final int REQUEST_SELECT_PICTURE = 3;
    private static final int REQUEST_REPORT_GHOST_PERMISSION = 4;
    private static final int ALPHA = 128;

    private static final String LINK_FORMAT = "<b><a href=\"%s\">%s</a></b>";

    private ImageButton takePictureButton;
    private ImageButton selectPictureButton;
    private ImageButton reportGhostStationButton;
    private ImageView imageView;
    private Bahnhof bahnhof;
    private Country country;
    private TextView tvBahnhofName;
    private boolean localFotoUsed = false;
    private License license;
    private boolean photoOwner;
    private String nickname;
    private String email;
    private String token;
    private String countryCode;
    private TextView licenseTagView;
    private TextView coordinates;
    private ViewGroup detailsLayout;
    private boolean fullscreen;
    private BaseApplication baseApplication;
    private LinearLayout header;
    private Bitmap publicBitmap;
    private RSAPI rsapi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);

        baseApplication = (BaseApplication) getApplication();
        rsapi = baseApplication.getRSAPI();
        BahnhofsDbAdapter dbAdapter = baseApplication.getDbAdapter();
        countryCode = baseApplication.getCountryCode();
        country = dbAdapter.fetchCountryByCountryCode(countryCode);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        detailsLayout = findViewById(R.id.content_details);
        header = findViewById(R.id.header);
        tvBahnhofName = findViewById(R.id.tvbahnhofname);
        coordinates = findViewById(R.id.coordinates);
        imageView = findViewById(R.id.imageview);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onPictureClicked();
            }
        });
        takePictureButton = findViewById(R.id.button_take_picture);
        takePictureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePictureWithPermissionCheck();
            }
        });
        selectPictureButton = findViewById(R.id.button_select_picture);
        selectPictureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectPictureWithPermissionCheck();
            }
        });
        reportGhostStationButton = findViewById(R.id.button_remove_station);
        reportGhostStationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                reportGhostStationWithPermissionCheck();
            }
        });

        licenseTagView = findViewById(R.id.license_tag);
        licenseTagView.setMovementMethod(LinkMovementMethod.getInstance());

        // switch off image and license view until we actually have a foto
        imageView.setVisibility(View.INVISIBLE);
        licenseTagView.setVisibility(View.INVISIBLE);
        setPictureButtonsVisibility(View.INVISIBLE);

        fullscreen = false;

        readPreferences();
        Intent intent = getIntent();
        boolean directPicture = false;
        if (intent != null) {
            bahnhof = (Bahnhof) intent.getSerializableExtra(EXTRA_BAHNHOF);
            if (bahnhof == null) {
                Log.w(TAG, "EXTRA_BAHNHOF in intent data missing");
                Toast.makeText(this, R.string.station_not_found, Toast.LENGTH_LONG).show();
                finish();
                return;
            }

            directPicture = intent.getBooleanExtra(EXTRA_TAKE_FOTO, false);
            tvBahnhofName.setText(bahnhof.getTitle() + " (" + bahnhof.getId() + ")");
            coordinates.setText(bahnhof.getLat() + ", " + bahnhof.getLon());

            if (bahnhof.hasPhoto()) {
                if (ConnectionUtil.checkInternetConnection(this)) {
                    BitmapCache.getInstance().getFoto(this, bahnhof.getPhotoUrl());
                }
                setPictureButtonsVisibility(
                        TextUtils.equals(nickname, bahnhof.getPhotographer()) ? View.VISIBLE : View.INVISIBLE);
            } else {
                setLocalBitmap();
            }
        }

        if (directPicture) {
            takePictureWithPermissionCheck();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        readPreferences();
    }

    private void readPreferences() {
        license = baseApplication.getLicense();
        photoOwner = baseApplication.getPhotoOwner();
        nickname = baseApplication.getNickname();
        email = baseApplication.getEmail();
        token = baseApplication.getUploadToken();
    }

    private void checkMyData() {
        MyDataDialogFragment myDataDialog = new MyDataDialogFragment();
        myDataDialog.show(getFragmentManager(), "mydata_dialog");
    }

    /**
     * Method to request permission for taking picture
     */
    private void requestPermissionAndTakePicture() {
        // Camera and Write permission has not been granted yet. Request it directly.
        ActivityCompat
                .requestPermissions(this,
                        new String[] { android.Manifest.permission.CAMERA,
                                android.Manifest.permission.WRITE_EXTERNAL_STORAGE },
                        REQUEST_TAKE_PICTURE_PERMISSION);
    }

    /**
     * Method to request permission for specific action
     */
    private void requestStoragePermission(int requestCode) {
        // Write permission has not been granted yet. Request it directly.
        ActivityCompat.requestPermissions(this, new String[] { android.Manifest.permission.WRITE_EXTERNAL_STORAGE },
                requestCode);
    }

    public void selectPicture() {
        if (!canSetPhoto()) {
            return;
        }

        if (isMyDataIncomplete()) {
            checkMyData();
        } else {
            File file = getCameraMediaFile();
            if (file != null) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent, getString(R.string.select_picture)),
                        REQUEST_SELECT_PICTURE);
            } else {
                Toast.makeText(this, R.string.unable_to_create_folder_structure, Toast.LENGTH_LONG).show();
            }
        }
    }

    private boolean canSetPhoto() {
        return !bahnhof.hasPhoto() || TextUtils.equals(nickname, bahnhof.getPhotographer());
    }

    public void takePicture() {
        if (!canSetPhoto()) {
            return;
        }

        if (isMyDataIncomplete()) {
            checkMyData();
        } else {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File file = getCameraMediaFile();
            if (file != null) {
                Uri photoURI = FileProvider.getUriForFile(this,
                        "de.bahnhoefe.deutschlands.bahnhofsfotos.fileprovider", file);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                intent.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, getResources().getString(R.string.app_name));
                intent.putExtra(MediaStore.EXTRA_MEDIA_TITLE, bahnhof.getTitle());
                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                startActivityForResult(intent, REQUEST_TAKE_PICTURE);
            } else {
                Toast.makeText(this, R.string.unable_to_create_folder_structure, Toast.LENGTH_LONG).show();
            }
        }
    }

    public void reportGhostStationWithConfirmation() {
        if (!canSetPhoto()) {
            return;
        }

        if (isMyDataIncomplete()) {
            checkMyData();
        } else {
            if (localFotoUsed || bahnhof.hasPhoto()) {
                new SimpleDialogs().confirm(this, R.string.confirm_replace_with_ghost,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                reportGhostStation();
                            }
                        });
            } else {
                reportGhostStation();
            }
        }
    }

    public void reportGhostStation() {
        File file = getStoredMediaFile();
        if (file != null) {
            try {
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ghost_station);
                int sampling = bitmap.getWidth() / STORED_FOTO_WIDTH;
                Bitmap scaledScreen = bitmap;
                if (sampling > 1) {
                    scaledScreen = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / sampling,
                            bitmap.getHeight() / sampling, false);
                }

                saveScaledBitmap(file, scaledScreen);
                Toast.makeText(getApplicationContext(), getString(R.string.report_ghost_station), Toast.LENGTH_LONG)
                        .show();
            } catch (Exception e) {
                Log.e(TAG, "Error processing photo", e);
                Toast.makeText(getApplicationContext(), getString(R.string.error_processing_photo) + e.getMessage(),
                        Toast.LENGTH_LONG).show();
            }
        } else {
            Toast.makeText(this, R.string.unable_to_create_folder_structure, Toast.LENGTH_LONG).show();
        }
    }

    private boolean isMyDataIncomplete() {
        return TextUtils.isEmpty(nickname) || license == License.UNKNOWN || !photoOwner;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == REQUEST_TAKE_PICTURE_PERMISSION) {
            Log.i(TAG, "Received response for Camera permission request.");

            // Check if the only required permission has been granted
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                // Camera and Write permission has been granted, preview can be displayed
                takePicture();
            } else {
                //Permission not granted
                Toast.makeText(DetailsActivity.this, R.string.grant_camera_permission, Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == REQUEST_SELECT_PICTURE_PERMISSION) {
            Log.i(TAG, "Received response for select image permission request.");

            // Check if the only required permission has been granted
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Write permission has been granted, preview can be displayed
                selectPicture();
            } else {
                //Permission not granted
                Toast.makeText(DetailsActivity.this, R.string.grant_external_storage, Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == REQUEST_REPORT_GHOST_PERMISSION) {
            Log.i(TAG, "Received response for report ghost permission request.");

            // Check if the only required permission has been granted
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Write permission has been granted, preview can be displayed
                reportGhostStationWithConfirmation();
            } else {
                //Permission not granted
                Toast.makeText(DetailsActivity.this, R.string.grant_external_storage, Toast.LENGTH_LONG).show();
            }
        }
    }

    /**
     * Method to check permission before taking a picture
     */
    void takePictureWithPermissionCheck() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ActivityCompat.checkSelfPermission(this,
                    android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // Camera permission has not been granted.
                requestPermissionAndTakePicture();
            } else {
                takePicture();
            }
        } else {
            takePicture();
        }
    }

    /**
     * Method to check permission before selecting a picture
     */
    void selectPictureWithPermissionCheck() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ActivityCompat.checkSelfPermission(this,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                // Write permission has not been granted.
                requestStoragePermission(REQUEST_SELECT_PICTURE_PERMISSION);
            } else {
                selectPicture();
            }
        } else {
            selectPicture();
        }
    }

    /**
     * Method to check permission before selecting a picture
     */
    void reportGhostStationWithPermissionCheck() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ActivityCompat.checkSelfPermission(this,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                // Write permission has not been granted.
                requestStoragePermission(REQUEST_REPORT_GHOST_PERMISSION);
            } else {
                reportGhostStationWithConfirmation();
            }
        } else {
            reportGhostStationWithConfirmation();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK) {
            return;
        }

        try {
            File storagePictureFile = getStoredMediaFile();
            if (requestCode == REQUEST_TAKE_PICTURE) {
                // die Kamera-App sollte auf temporren Cache-Speicher schreiben, wir laden das Bild von
                // dort und schreiben es in Standard-Gre in den permanenten Speicher
                File cameraRawPictureFile = getCameraMediaFile();
                if (cameraRawPictureFile == null || storagePictureFile == null) {
                    throw new RuntimeException(getString(R.string.photofile_not_existing));
                }

                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true; // just query the image size in the first step
                BitmapFactory.decodeFile(cameraRawPictureFile.getPath(), options);

                int sampling = options.outWidth / STORED_FOTO_WIDTH;
                if (sampling > 1) {
                    options.inSampleSize = sampling;
                }
                options.inJustDecodeBounds = false;

                Bitmap scaledScreen = BitmapFactory.decodeFile(cameraRawPictureFile.getPath(), options);

                saveScaledBitmap(storagePictureFile, scaledScreen);
                // temp file begone!
                cameraRawPictureFile.delete();
            } else if (requestCode == REQUEST_SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();
                Bitmap bitmap = getBitmapFromUri(selectedImageUri);

                int sampling = bitmap.getWidth() / STORED_FOTO_WIDTH;
                Bitmap scaledScreen = bitmap;
                if (sampling > 1) {
                    scaledScreen = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / sampling,
                            bitmap.getHeight() / sampling, false);
                }

                saveScaledBitmap(storagePictureFile, scaledScreen);
            }
        } catch (Exception e) {
            Log.e(TAG, "Error processing photo", e);
            Toast.makeText(getApplicationContext(), getString(R.string.error_processing_photo) + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }
    }

    private void saveScaledBitmap(File storagePictureFile, Bitmap scaledScreen) throws FileNotFoundException {
        if (scaledScreen == null) {
            throw new RuntimeException(getString(R.string.error_scaling_photo));
        }
        Log.d(TAG, "img width " + scaledScreen.getWidth());
        Log.d(TAG, "img height " + scaledScreen.getHeight());
        if (scaledScreen.getWidth() < scaledScreen.getHeight()) {
            Toast.makeText(getApplicationContext(), R.string.photo_need_landscape_orientation, Toast.LENGTH_LONG)
                    .show();
            return;
        }

        scaledScreen.compress(Bitmap.CompressFormat.JPEG, STORED_FOTO_QUALITY,
                new FileOutputStream(storagePictureFile));
        setLocalBitmap();
    }

    private Bitmap getBitmapFromUri(Uri uri) throws IOException {
        ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        parcelFileDescriptor.close();
        return image;
    }

    /**
     * Get the base directory for storing fotos
     *
     * @return the File denoting the base directory.
     */
    @Nullable
    private File getMediaStorageDir() {
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), Constants.PHOTO_DIRECTORY);

        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                Log.e(TAG, "Cannot create directory structure " + mediaStorageDir.getAbsolutePath());
                return null;
            }
        }
        return mediaStorageDir;
    }

    /**
     * Get the file path for storing this station's foto
     *
     * @return the File
     */
    @Nullable
    public File getStoredMediaFile() {
        File mediaStorageDir = getMediaStorageDir();
        if (mediaStorageDir == null) {
            return null;
        }

        Log.d(TAG, "BahnhofNrAbfrage: " + bahnhof.getId());
        File file = new File(mediaStorageDir, String.format("%s-%s.jpg", nickname, bahnhof.getId()));
        Log.d("FilePfad", file.toString());

        return file;

    }

    /**
     * Get the file path for the Camera app to store the unprocessed foto to.
     *
     * @return the File
     */
    private File getCameraMediaFile() {
        File temporaryStorageDir = new File(getMediaStorageDir(), ".temp");
        if (!temporaryStorageDir.exists()) {
            if (!temporaryStorageDir.mkdirs()) {
                Log.e(TAG, "Cannot create directory structure " + temporaryStorageDir.getAbsolutePath());
                return null;
            }
        }

        Log.d(TAG, "Temporary BahnhofNrAbfrage: " + bahnhof.getId());
        File file = new File(temporaryStorageDir, String.format("%s-%s.jpg", nickname, bahnhof.getId()));
        Log.d("FilePfad", file.toString());

        return file;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();
        getMenuInflater().inflate(R.menu.details, menu);
        MenuItem navToStation = menu.findItem(R.id.nav_to_station);
        navToStation.getIcon().mutate();
        navToStation.getIcon().setColorFilter(WHITE, PorterDuff.Mode.SRC_ATOP);

        if (localFotoUsed) {
            enableMenuItem(menu, R.id.photo_upload);
        } else {
            disableMenuItem(menu, R.id.photo_upload);
        }

        if (localFotoUsed || bahnhof.hasPhoto()) {
            enableMenuItem(menu, R.id.share_photo);
        } else {
            disableMenuItem(menu, R.id.share_photo);
        }

        return super.onPrepareOptionsMenu(menu);
    }

    private void enableMenuItem(Menu menu, int id) {
        MenuItem menuItem = menu.findItem(id).setEnabled(true);
        menuItem.getIcon().mutate();
        menuItem.getIcon().setColorFilter(WHITE, PorterDuff.Mode.SRC_ATOP);
    }

    private void disableMenuItem(Menu menu, int id) {
        MenuItem menuItem = menu.findItem(id).setEnabled(false);
        menuItem.getIcon().mutate();
        menuItem.getIcon().setColorFilter(WHITE, PorterDuff.Mode.SRC_ATOP);
        menuItem.getIcon().setAlpha(ALPHA);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.nav_to_station:
            startNavigation(DetailsActivity.this);
            break;
        case R.id.timetable:
            final Intent timetableIntent = new Timetable().createTimetableIntent(country, bahnhof);
            if (timetableIntent != null) {
                startActivity(timetableIntent);
            } else {
                Toast.makeText(this, R.string.timetable_missing, Toast.LENGTH_LONG).show();
            }
            break;
        case R.id.photo_upload:
            if (isMyDataIncomplete()) {
                checkMyData();
            } else {
                if (TextUtils.isEmpty(email) || TextUtils.isEmpty(token)) {
                    Toast.makeText(this, R.string.registration_needed, Toast.LENGTH_LONG).show();
                } else {
                    uploadPhoto();
                }
            }
            break;
        case R.id.share_photo:
            Intent shareIntent = createFotoSendIntent();
            shareIntent.putExtra(Intent.EXTRA_TEXT, country.getTwitterTags() + " " + bahnhof.getTitle());
            shareIntent.setType("image/jpeg");
            startActivity(createChooser(shareIntent, "send"));
            break;
        case android.R.id.home:
            Intent upIntent = NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // This activity is NOT part of this app's task, so create a new task
                // when navigating up, with a synthesized back stack.
                TaskStackBuilder.create(this)
                        // Add all of this activity's parents to the back stack
                        .addNextIntentWithParentStack(upIntent)
                        // Navigate up to the closest parent
                        .startActivities();
            } else {
                onBackPressed();
            }

            break;
        default:
            return super.onOptionsItemSelected(item);
        }

        return true;
    }

    private void uploadPhoto() {
        final ProgressDialog progress = new ProgressDialog(DetailsActivity.this);
        progress.setMessage(getResources().getString(R.string.send));
        progress.setTitle(getResources().getString(R.string.app_name));
        progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progress.show();

        final File mediaFile = getStoredMediaFile();
        RequestBody file = RequestBody
                .create(MediaType.parse(URLConnection.guessContentTypeFromName(mediaFile.getName())), mediaFile);
        rsapi.photoUpload(email, token, bahnhof.getId(), countryCode.toLowerCase(), file)
                .enqueue(new Callback<Void>() {
                    @Override
                    public void onResponse(Call<Void> call, Response<Void> response) {
                        progress.dismiss();
                        switch (response.code()) {
                        case 202:
                            new SimpleDialogs().confirm(DetailsActivity.this, R.string.upload_completed);
                            break;
                        case 400:
                            new SimpleDialogs().confirm(DetailsActivity.this, R.string.upload_bad_request);
                            break;
                        case 401:
                            new SimpleDialogs().confirm(DetailsActivity.this, R.string.upload_token_invalid);
                            break;
                        case 409:
                            new SimpleDialogs().confirm(DetailsActivity.this, R.string.upload_conflict);
                            break;
                        case 413:
                            new SimpleDialogs().confirm(DetailsActivity.this, R.string.upload_too_big);
                            break;
                        default:
                            new SimpleDialogs().confirm(DetailsActivity.this,
                                    String.format(getText(R.string.upload_failed).toString(), response.code()));
                        }
                    }

                    @Override
                    public void onFailure(Call<Void> call, Throwable t) {
                        Log.e(TAG, "Error uploading photo", t);
                        progress.dismiss();
                        new SimpleDialogs().confirm(DetailsActivity.this,
                                String.format(getText(R.string.upload_failed).toString(), t.getMessage()));
                    }
                });
    }

    private Intent createFotoSendIntent() {
        Intent sendIntent = new Intent(Intent.ACTION_SEND);
        File file = getStoredMediaFile();
        if (file != null && file.canRead()) {
            sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(DetailsActivity.this,
                    "de.bahnhoefe.deutschlands.bahnhofsfotos.fileprovider", file));
        } else if (publicBitmap != null) {
            File imagePath = new File(getApplicationContext().getCacheDir(), "images");
            imagePath.mkdirs();
            File newFile = new File(imagePath, bahnhof.getId() + ".jpg");
            try {
                saveScaledBitmap(newFile, publicBitmap);
                sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(DetailsActivity.this,
                        "de.bahnhoefe.deutschlands.bahnhofsfotos.fileprovider", newFile));
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Error saving cached bitmap", e);
            }
        }
        return sendIntent;
    }

    private void startNavigation(final Context context) {
        final NavItem[] items = {
                new NavItem("   " + getString(R.string.nav_oepnv), R.drawable.ic_directions_bus_gray_24px),
                new NavItem("   " + getString(R.string.nav_car), R.drawable.ic_directions_car_gray_24px),
                new NavItem("   " + getString(R.string.nav_bike), R.drawable.ic_directions_bike_gray_24px),
                new NavItem("   " + getString(R.string.nav_walk), R.drawable.ic_directions_walk_gray_24px),
                new NavItem("   " + getString(R.string.nav_show), R.drawable.ic_info_gray_24px) };

        ListAdapter adapter = new ArrayAdapter<NavItem>(this, android.R.layout.select_dialog_item,
                android.R.id.text1, items) {
            public View getView(int position, View convertView, ViewGroup parent) {
                //Use super class to create the View
                View v = super.getView(position, convertView, parent);
                TextView tv = (TextView) v.findViewById(android.R.id.text1);

                //Put the image on the TextView
                tv.setCompoundDrawablesWithIntrinsicBounds(items[position].icon, 0, 0, 0);

                //Add margin between image and text (support various screen densities)
                int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
                int dp7 = (int) (20 * getResources().getDisplayMetrics().density);
                tv.setCompoundDrawablePadding(dp5);
                tv.setPadding(dp7, 0, 0, 0);

                return v;
            }
        };

        AlertDialog.Builder navBuilder = new AlertDialog.Builder(this);
        navBuilder.setIcon(R.mipmap.ic_launcher);
        navBuilder.setTitle(R.string.navMethod);
        navBuilder.setAdapter(adapter, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int navItem) {
                String dlocation = "";
                Intent intent = null;
                switch (navItem) {
                case 0:
                    dlocation = String.format("google.navigation:ll=%s,%s&mode=Transit", bahnhof.getLat(),
                            bahnhof.getLon());
                    Log.d("findnavigation case 0", dlocation);
                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(dlocation));
                    break;
                case 1:
                    dlocation = String.format("google.navigation:ll=%s,%s&mode=d", bahnhof.getLat(),
                            bahnhof.getLon());
                    Log.d("findnavigation case 1", dlocation);
                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(dlocation));
                    break;

                case 2:
                    dlocation = String.format("google.navigation:ll=%s,%s&mode=b", bahnhof.getLat(),
                            bahnhof.getLon());
                    Log.d("findnavigation case 2", dlocation);
                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(dlocation));
                    break;
                case 3:
                    dlocation = String.format("google.navigation:ll=%s,%s&mode=w", bahnhof.getLat(),
                            bahnhof.getLon());
                    Log.d("findnavigation case 3", dlocation);
                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(dlocation));
                    break;
                case 4:
                    dlocation = String.format("geo:0,0?q=%s,%s(%s)", bahnhof.getLat(), bahnhof.getLon(),
                            bahnhof.getTitle());
                    Log.d("findnavigation case 4", dlocation);
                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(dlocation));
                    break;

                }
                try {
                    startActivity(intent);
                } catch (Exception e) {
                    Toast toast = Toast.makeText(context, R.string.activitynotfound, Toast.LENGTH_LONG);
                    toast.show();
                }
            }
        }).show();

    }

    /**
     * This gets called if the requested bitmap is available. Finish and issue the notification.
     *
     * @param bitmapFromCache the fetched Bitmap for the notification. May be null
     */
    @Override
    public void onBitmapAvailable(final @Nullable Bitmap bitmapFromCache) {
        localFotoUsed = false;
        publicBitmap = bitmapFromCache;
        if (publicBitmap == null) {
            // keine Bitmap ausgelesen
            // switch off image and license view until we actually have a foto
            // @todo broken image anzeigen
            imageView.setVisibility(View.INVISIBLE);
            licenseTagView.setVisibility(View.INVISIBLE);
            return;
        }

        // Lizenzinfo aufbauen und einblenden
        licenseTagView.setVisibility(View.VISIBLE);
        if (bahnhof.getLicense() != null) {
            final boolean photographerUrlAvailable = bahnhof.getPhotographerUrl() != null
                    && !bahnhof.getPhotographerUrl().isEmpty();
            final boolean licenseUrlAvailable = bahnhof.getLicenseUrl() != null
                    && !bahnhof.getLicenseUrl().isEmpty();

            final String photographerText;
            if (photographerUrlAvailable) {
                photographerText = String.format(LINK_FORMAT, bahnhof.getPhotographerUrl(),
                        bahnhof.getPhotographer());
            } else {
                photographerText = bahnhof.getPhotographer();
            }

            final String licenseText;
            if (licenseUrlAvailable) {
                licenseText = String.format(LINK_FORMAT, bahnhof.getLicenseUrl(), bahnhof.getLicense());
            } else {
                licenseText = bahnhof.getLicense();
            }
            licenseTagView.setText(Html.fromHtml(
                    String.format(getText(R.string.license_tag).toString(), photographerText, licenseText)));
        } else {
            licenseTagView.setText(R.string.license_info_not_readable);
        }

        setBitmap(publicBitmap);
    }

    /**
     * Fetch bitmap from device local location, if  it exists, and set the foto view.
     */
    private void setLocalBitmap() {
        setPictureButtonsVisibility(View.VISIBLE);

        Bitmap showBitmap = checkForLocalPhoto();
        if (showBitmap == null) {
            // lokal keine Bitmap
            localFotoUsed = false;
            // switch off image and license view until we actually have a foto
            imageView.setVisibility(View.INVISIBLE);
            licenseTagView.setVisibility(View.INVISIBLE);
        } else {
            setBitmap(showBitmap);
        }
    }

    private void setPictureButtonsVisibility(int visible) {
        takePictureButton.setVisibility(visible);
        selectPictureButton.setVisibility(visible);
        reportGhostStationButton.setVisibility(visible);
    }

    private void setBitmap(final Bitmap showBitmap) {
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int targetWidth = size.x;

        if (showBitmap.getWidth() != targetWidth) {
            Bitmap scaledBitmap = Bitmap.createScaledBitmap(showBitmap, targetWidth,
                    (int) (((long) showBitmap.getHeight() * (long) targetWidth) / showBitmap.getWidth()), true);
            imageView.setImageBitmap(scaledBitmap);
        } else {
            imageView.setImageBitmap(showBitmap);
        }
        imageView.setVisibility(View.VISIBLE);
        invalidateOptionsMenu();
    }

    private class AnimationUpdateListener implements ValueAnimator.AnimatorUpdateListener {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float alpha = (float) animation.getAnimatedValue();
            if (header == null) {
                tvBahnhofName.setAlpha(alpha);
            } else {
                header.setAlpha(alpha);
            }
            licenseTagView.setAlpha(alpha);
        }
    }

    /**
     * Check if there's a local photo file for this station.
     *
     * @return the Bitmap of the photo, or null if none exists.
     */
    @Nullable
    private Bitmap checkForLocalPhoto() {
        // show the image
        Bitmap scaledScreen = null;
        File localFile = getStoredMediaFile();

        if (localFile != null && localFile.canRead()) {
            Log.d(TAG, "File: " + localFile);
            Log.d(TAG, "FileGetPath: " + localFile.getPath().toString());

            scaledScreen = BitmapFactory.decodeFile(localFile.getPath());
            Log.d(TAG, "img width " + scaledScreen.getWidth());
            Log.d(TAG, "img height " + scaledScreen.getHeight());
            localFotoUsed = true;
            return scaledScreen;
        } else {
            localFotoUsed = false;
            Log.e(TAG, String.format("Media file not available for station %s and nickname %s ", bahnhof.getId(),
                    nickname));
            return null;
        }

    }

    public void onPictureClicked() {
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE && !fullscreen) {
            ValueAnimator animation = ValueAnimator.ofFloat(header.getAlpha(), 0f);
            animation.setDuration(500);
            animation.addUpdateListener(new AnimationUpdateListener());
            animation.start();
            detailsLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE);
            ActionBar bar = getActionBar();
            if (bar != null)
                bar.hide();
            android.support.v7.app.ActionBar sbar = getSupportActionBar();
            if (sbar != null)
                sbar.hide();
            fullscreen = true;
        } else {
            ValueAnimator animation = ValueAnimator
                    .ofFloat(header == null ? tvBahnhofName.getAlpha() : header.getAlpha(), 1.0f);
            animation.setDuration(500);
            animation.addUpdateListener(new AnimationUpdateListener());
            animation.start();
            detailsLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
            ActionBar bar = getActionBar();
            if (bar != null)
                bar.show();
            android.support.v7.app.ActionBar sbar = getSupportActionBar();
            if (sbar != null)
                sbar.show();
            fullscreen = false;
        }

    }

}