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