mardi 28 juin 2016

Location services across multiple activities

I was wondering if there was an elegant way to separate google fused location services away from activities. My warning class currently implements location services but I have another activity that takes photos. When a photo is taken I want to associate a location with the image. My current idea is to just use my broadcast receiver in my Bluetooth warning class to listen for a broadcast my camera will send and associate it then with a location. I'm not a fan of the idea because it doesn't separate functionality very well so was hoping for some suggestions or patterns. Code for classes below.

CAMERA CLASS

import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CameraOperations extends AppCompatActivity {
    ImageView mImageView;
    String photoPath;
    int REQUEST_IMAGE_CAPTURE = 1;
    File photoFile = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera_view);
        mImageView = (ImageView) findViewById(R.id.imageView);

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            Toast.makeText(CameraOperations.this, "No Camera", Toast.LENGTH_SHORT).show();
        } else {
            dispatchTakePictureIntent();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK){
            if(data == null){
                Toast.makeText(this, "Data is null", Toast.LENGTH_SHORT);
                Bitmap pictureMap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
                mImageView.setImageBitmap(pictureMap);
            }else {
                Toast.makeText(this, "Error Occurred", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(imageFileName, ".jpg", storageDir);

        photoPath = "file:" + image.getAbsolutePath();
        return image;
    }

    private void dispatchTakePictureIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        try{
            photoFile = createImageFile();
        }catch(IOException e){
            e.printStackTrace();
        }

        if(photoFile != null){
            Uri photoUri = Uri.fromFile(photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
        }
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);

    }
}

BLUETOOTH WARNING CLASS

import android.Manifest;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

public class Warning extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
    private final static String TAG = Warning.class.getSimpleName();
    private String mDeviceAddress;
    private HandleConnectionService mBluetoothLeService;
    private boolean quitService;
    private final int PLAY_SERVICES_REQUEST_TIME = 1000;
    private Location mLastLocation;
    private GoogleApiClient mGoogleClient;
    private boolean requestingLocationUpdates = false;
    private LocationRequest locationRequest;

    private int UPDATE_INTERVAL = 10000; // 10 seconds
    private int FASTEST_INTERVAL = 5000; // 5 seconds
    private int DISTANCEMOVED = 10; //In meters


    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((HandleConnectionService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            mBluetoothLeService.connect(mDeviceAddress);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();

            if (HandleConnectionService.ACTION_GATT_DISCONNECTED.equals(action)) {
                if (!quitService) {
                    mBluetoothLeService.connect(mDeviceAddress);
                    Log.w(TAG, "Attempting to reconnect");
                }
                Log.w(TAG, "Disconnected, activity closing");
            } else if (HandleConnectionService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                getGattService(mBluetoothLeService.getSupportedGattService());
            } else if (HandleConnectionService.ACTION_DATA_AVAILABLE.equals(action)) {
                checkWarning(intent.getByteArrayExtra(HandleConnectionService.EXTRA_DATA));
            }
        }
    };

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

        Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
        setSupportActionBar(myToolbar);

        if (checkGoogleServices()) {
            buildGoogleApiClient();
        }

        quitService = false;
        Intent intent = getIntent();
        mDeviceAddress = intent.getStringExtra(Device.EXTRA_DEVICE_ADDRESS);

        Intent gattServiceIntent = new Intent(this, HandleConnectionService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.mainmenu, menu);
        MenuItem connect = menu.findItem(R.id.connect);
        connect.setVisible(false);
        MenuItem disconnect = menu.findItem(R.id.disconnect);
        disconnect.setVisible(true);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Intent intent;
        switch (item.getItemId()) {
            case R.id.home:
                new AlertDialog.Builder(this)
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .setTitle("Return Home")
                        .setMessage("Returning home will disconnect you, continue?")
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                quitService = true;
                                mBluetoothLeService.disconnect();
                                mBluetoothLeService.close();

                                Intent intent = new Intent(Warning.this, Main.class);
                                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                startActivity(intent);
                            }
                        })
                        .setNegativeButton("No", null)
                        .show();

                return true;
            case R.id.connect:
                Toast.makeText(this, "Connect Pressed", Toast.LENGTH_SHORT).show();
                return true;

            case R.id.disconnect:
                disconnectOperation();
                intent = new Intent(Warning.this, Main.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                return true;

            case R.id.profiles:
                Toast.makeText(this, "Profiles Pressed", Toast.LENGTH_SHORT).show();
                return true;


            case R.id.camera:
                Toast.makeText(this, "Camera Pressed", Toast.LENGTH_SHORT).show();
                intent = new Intent(Warning.this, CameraOperations.class);
                startActivity(intent);
                return true;

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

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            quitService = true;
            mBluetoothLeService.disconnect();
            mBluetoothLeService.close();

            Intent intent = new Intent(Warning.this, Main.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mBluetoothLeService.disconnect();
        mBluetoothLeService.close();

        System.exit(0);
    }

    public boolean disconnectOperation(){
        this.quitService = true;
        mBluetoothLeService.disconnect();
        mBluetoothLeService.close();
        return true;
    }

    private void checkWarning(byte[] byteArray) {
        if (byteArray != null) {
            for (int i = 0; i < byteArray.length; i++) {
                if (byteArray[i] == 48) {
                   findLocation();
                }
            }
        }
    }

    private void getGattService(BluetoothGattService gattService) {
        if (gattService == null) {
            return;
        }

        BluetoothGattCharacteristic characteristicRx = gattService.getCharacteristic(HandleConnectionService.UUID_BLE_SHIELD_RX);
        mBluetoothLeService.setCharacteristicNotification(characteristicRx, true);
        mBluetoothLeService.readCharacteristic(characteristicRx);
    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(HandleConnectionService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(HandleConnectionService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(HandleConnectionService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(HandleConnectionService.ACTION_DATA_AVAILABLE);

        return intentFilter;
    }

    private boolean checkGoogleServices() {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        int available = googleAPI.isGooglePlayServicesAvailable(this);
        if (available != ConnectionResult.SUCCESS) {
            if (googleAPI.isUserResolvableError(available)) {
                googleAPI.getErrorDialog(this, available, PLAY_SERVICES_REQUEST_TIME).show();
            }
            return false;
        }

        return true;
    }

    public void findLocation() {
        int REQUEST_CODE_ASK_PERMISSIONS = 123;
        double latitude = 0.0;
        double longitude = 0.0;

        if(Build.VERSION.SDK_INT >= 23){
            boolean fineLocationAccess = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
            boolean courseLocationAccess = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
            boolean accessGranted = fineLocationAccess && courseLocationAccess;

            if (accessGranted) {
                mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleClient);
                if(mLastLocation != null) {
                    latitude = mLastLocation.getLatitude();
                    longitude = mLastLocation.getLongitude();

                    Toast.makeText(this, "latitude: " + latitude + " longitude: " + longitude, Toast.LENGTH_LONG).show();
                }else{
                    Log.i("Warning", "Unable to get Location");
                }
            }else{
                Log.i("Connection", "Request permission");
            }
        }else{
            mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleClient);
            if(mLastLocation != null) {
                latitude = mLastLocation.getLatitude();
                longitude = mLastLocation.getLongitude();

                Toast.makeText(this, "latitude: " + latitude + " longitude: " + longitude, Toast.LENGTH_LONG).show();
            }else{
                Log.i("Warning", "Unable to get Location");
            }
        }
    }

    public void buildGoogleApiClient() {
        mGoogleClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API).build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.w("Connected", " : " + mGoogleClient.isConnected());
    }

    @Override
    public void onConnectionSuspended(int i) {
        Toast.makeText(this, "Location Services Stopped", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Toast.makeText(this, "Location Services Connection Fail", Toast.LENGTH_SHORT).show();
    }

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

        if (mGoogleClient != null) {
            mGoogleClient.connect();
        }
    }
}

Aucun commentaire:

Enregistrer un commentaire