com.trellmor.mocklocationpicture.MLPActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.trellmor.mocklocationpicture.MLPActivity.java

Source

/*
 * Mock Locations from Picture
 * Copyright (C) 2013 Daniel Triendl <daniel@pew.cc>
 *   Copyright (C) 2013 Patrik Mallaun <patrik@mallaun.com>
 * 
 * This program 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.
 * 
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.trellmor.mocklocationpicture;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.v4.app.ShareCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.Toast;

public class MLPActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
    private static final String TAG = MLPActivity.class.getName();

    private static final String KEY_IMAGE_URI = "IMAGE_URI";

    private final static int ACTIVITY_SELECT_IMAGE = 0;

    private ImageView mImagePreview;
    private MenuItem mMenuShare;

    private Uri mImageUri = null;

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

        mImagePreview = (ImageView) findViewById(R.id.image_preview);

        Intent intent = getIntent();
        String action = intent.getAction();
        String type = intent.getType();

        if (Intent.ACTION_SEND.equals(action) && type != null && type.startsWith("image/")) {
            // Started by share intent, display preview image
            setImageUri((Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
            intent.setAction("");
        } else if (savedInstanceState != null) {
            setImageUri((Uri) savedInstanceState.getParcelable(KEY_IMAGE_URI));
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        if (!isMockLocationEnabled()) {
            AlertDialog.Builder dialog = new AlertDialog.Builder(this);
            dialog.setTitle(R.string.mock_locations_disabled);
            dialog.setMessage(R.string.enable_mock_locations);
            dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    startDevelopmentSettings();
                }
            });
            dialog.setNegativeButton(android.R.string.cancel, null);
            dialog.create().show();
        }
    };

    @Override
    protected void onPause() {
        super.onPause();

        this.finish();
    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.mlpactivity, menu);

        mMenuShare = menu.findItem(R.id.action_share);

        // Return true to display menu
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_settings:
            startDevelopmentSettings();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mImageUri != null) {
            outState.putParcelable(KEY_IMAGE_URI, mImageUri);
        } else {
            outState.remove(KEY_IMAGE_URI);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
        case ACTIVITY_SELECT_IMAGE:
            if (resultCode == RESULT_OK) {
                Uri imageUri = data.getData();
                setImageUri(imageUri);
            }
            break;
        }
    }

    public void onButtonClearClick(View v) {
        clear();
    }

    public void onButtonLoadClick(View v) {
        load();
    }

    private void clear() {
        setImageUri(null);
        stopService(new Intent(this, MockLocationService.class));
        mImagePreview.setImageBitmap(null);
        configureShareItem(mMenuShare, null, null);
    }

    private void load() {
        clear();
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
        startActivityForResult(intent, ACTIVITY_SELECT_IMAGE);
    }

    private boolean isMockLocationEnabled() {
        return !Settings.Secure.getString(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
    }

    private void startDevelopmentSettings() {
        Intent intent = new Intent();
        intent.setClassName("com.android.settings", "com.android.settings.DevelopmentSettings");
        startActivity(intent);
    }

    private void setImageUri(Uri uri) {
        mImageUri = uri;

        if (mImageUri != null) {
            final int maxHeight = mImagePreview.getHeight();
            final int maxWidth = mImagePreview.getWidth();

            if (maxHeight == 0 || maxWidth == 0) {
                // Layout not loaded yet, delay
                mImagePreview.getViewTreeObserver().addOnGlobalLayoutListener(this);
                return;
            }

            // Cache image locally
            LoadImageTask task = new LoadImageTask();
            task.execute(mImageUri);
        }
    }

    @SuppressWarnings("deprecation")
    @SuppressLint("NewApi")
    @Override
    public void onGlobalLayout() {
        ViewTreeObserver obs = mImagePreview.getViewTreeObserver();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }

        if (mImageUri != null) {
            setImageUri(mImageUri);
        }
    }

    private void configureShareItem(MenuItem item, Uri uri, String mimeType) {
        if (uri != null && mimeType != null) {
            item.setVisible(true);
            ShareCompat.IntentBuilder shareIntent = ShareCompat.IntentBuilder.from(MLPActivity.this);
            shareIntent.setStream(uri);
            shareIntent.setType(mimeType);
            ShareCompat.configureMenuItem(item, shareIntent);
        } else {
            item.setVisible(false);
        }
    }

    private class LoadImageTask extends AsyncTask<Uri, Void, Boolean> {
        private Uri mUri = null;
        private int mMaxWidth = 0;
        private int mMaxHeight = 0;
        private Bitmap mPreview = null;
        private String mMimeType = null;

        public LoadImageTask() {
            if (mImagePreview != null) {
                mMaxWidth = mImagePreview.getWidth();
                mMaxHeight = mImagePreview.getHeight();
            }
        }

        @Override
        protected Boolean doInBackground(Uri... params) {
            boolean result = false;

            if (params.length == 0)
                return result;

            mUri = params[0];
            if (mUri == null)
                return result;

            Context context = getApplicationContext();

            InputStream is;
            OutputStream os;
            File temp = null;
            try {
                temp = File.createTempFile("tmp", null, context.getCacheDir());
                temp.getParentFile().mkdirs();
                is = context.getContentResolver().openInputStream(mUri);
                try {
                    os = new FileOutputStream(temp);
                    try {
                        byte[] buffer = new byte[1024];
                        int read;

                        while ((read = is.read(buffer)) != -1) {
                            os.write(buffer, 0, read);
                        }

                        os.flush();
                    } finally {
                        os.close();
                    }

                    result = setMockLocation(temp.getAbsolutePath());
                    mPreview = createPreview(temp.getAbsolutePath());
                } finally {
                    is.close();
                }
            } catch (FileNotFoundException e) {
                Log.wtf(TAG, e);
                return result;
            } catch (IOException e) {
                Log.e(TAG, e.getMessage(), e);
                return result;
            } finally {
                if (temp != null && temp.exists()) {
                    temp.delete();
                }
            }

            return result;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (mImagePreview != null) {
                mImagePreview.setImageBitmap(mPreview);
            }

            if (mMenuShare != null) {
                configureShareItem(mMenuShare, mUri, mMimeType);
            }

            if (!result) {
                if (!isMockLocationEnabled())
                    Toast.makeText(getApplicationContext(), R.string.mock_locations_disabled, Toast.LENGTH_SHORT)
                            .show();
                else
                    Toast.makeText(getApplicationContext(), R.string.exif_no_latlong, Toast.LENGTH_SHORT).show();
            }
        }

        static final int MAX_BITMAP_DIM = 2048;

        private Bitmap createPreview(String path) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, options);

            int height = options.outHeight;
            int width = options.outWidth;
            mMimeType = options.outMimeType;
            int inSampleSize = 1;

            while (true) {
                if (width <= MAX_BITMAP_DIM && height <= MAX_BITMAP_DIM) {
                    if (width <= mMaxWidth && height <= mMaxHeight) {
                        break;
                    }
                }

                width /= 2;
                height /= 2;
                inSampleSize *= 2;
            }
            options.inSampleSize = inSampleSize;
            options.inJustDecodeBounds = false;

            return BitmapFactory.decodeFile(path, options);
        }

        private boolean setMockLocation(String path) {
            if (isMockLocationEnabled()) {

                try {
                    ExifInterface exif = new ExifInterface(path);

                    float[] latlong = new float[2];
                    if (exif.getLatLong(latlong)) {
                        Intent intent = new Intent(getApplicationContext(), MockLocationService.class);
                        intent.putExtra(MockLocationService.EXTRA_LATITUDE, latlong[0]);
                        intent.putExtra(MockLocationService.EXTRA_LONGITUDE, latlong[1]);
                        startService(intent);
                        return true;
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Failed get location from image", e);
                }
            }
            return false;
        }
    }
}