FusedLocationApi method getLastLocation() always null during first call - java

Looking for some help with a problem in my app concerning getting the current device location. Below is the GPSLocationListener class I am using.
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
/**
* This class takes care of capturing the location of the device.
*/
public class GPSLocationListener implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
protected static final String TAG = "location-updates-sample";
public static final int LOCATION_RESQUEST = 1;
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
protected LocationRequest mLocationRequest;
/**
* Represents a geographical location.
*/
protected Location mCurrentLocation;
private Activity mActivity;
public double lat;
public double lon;
public GPSLocationListener(Activity activity) {
this.mActivity = activity;
// Kick off the process of building a GoogleApiClient and requesting the LocationServices API.
buildGoogleApiClient();
}
/**
* Builds a GoogleApiClient. Uses the {#code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Sets up the location request. Android has two location request settings:
* {#code ACCESS_COARSE_LOCATION} and {#code ACCESS_FINE_LOCATION}. These settings control
* the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
* the AndroidManifest.xml.
* <p/>
* When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
* interval (5 seconds), the Fused Navigation Provider API returns location updates that are
* accurate to within a few feet.
* <p/>
* These settings are appropriate for mapping applications that show real-time location
* updates.
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Requests location updates from the FusedLocationApi.
*/
public void startLocationUpdates(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
//return;
}else {
try {
ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET},
LOCATION_RESQUEST);
}catch (Exception e){
e.printStackTrace();
}
}
// If the initial location was never previously requested, we use
// FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store
// its value in the Bundle and check for it in onCreate().
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}
/**
* Removes location updates from the FusedLocationApi.
*/
protected void stopLocationUpdates() {
// It is a good practice to remove location requests when the activity is in a paused or
// stopped state. Doing so helps battery performance and is especially
// recommended in applications that request frequent location updates.
// The final argument to {#code requestLocationUpdates()} is a LocationListener
// (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html).
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
public void onStart() {
mGoogleApiClient.connect();
//createLocationRequest();
// Within {#code onPause()}, we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
}
public void onStop() {
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "Connected to GoogleApiClient");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onConnected: Just empty if statement");
}else {
try {
ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET},
LOCATION_RESQUEST);
}catch (Exception e){
e.printStackTrace();
}
}
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation == null) {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Log.i(TAG, "onConnected " + String.valueOf(mCurrentLocation));
}
}
}
/**
* Callback that fires when the location changes.
*/
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLongitude()));
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mActivity.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
switch (requestCode){
case LOCATION_RESQUEST:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
startLocationUpdates(); // Calling this here is the only place that does not make the app crash
getCurrentLocation();
}else {
Log.i(TAG, "onRequestPermissionsResult: Need Permissions");
return;
}
break;
default:
break;
}
return;
}
public void getCurrentLocation(){
if (mCurrentLocation != null){
lat = mCurrentLocation.getLatitude();
lon = mCurrentLocation.getLongitude();
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude()));
}
}
public GoogleApiClient getGoogleApiClient(){
return mGoogleApiClient;
}
}
Trying this out on my actual device with the GPS already enabled in the settings, I get some odd behavior. If I do not at all, call the startLocationUpdates() method or I call it in the onRequestPermissionsResult() method, the app launches fine and when I grant Device Location Permissions, the mCurrentLocation object is null, but does not crash. I stop the app and then launch again, and the mCurrentLocation has latitude and longitude coordinates that I can see in the logcat, which is what I am wanting in the first place, but they only hold any values, after the second launch. Now if I uninstall the app and try to call the startLocationUpdates() method anywhere, the app crashes upon launch with the error:
Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations.
But I am checking for permissions in the onConnected() method and also in the startLocationUpdates() method as well, although I do not think this is correct but this is the only way that I can get Android Studio to not underline the
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
statement in red with a Permissions warning.
Here is the Activity where I am trying to get the location updates with the mapItBtnRespond() method.
package com.example.bigdaddy.as_built_weldmapper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.example.bigdaddy.as_built_weldmapper.utilities.BendHelper;
import com.example.bigdaddy.as_built_weldmapper.utilities.GPSLocationListener;
public class SagActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
MajorButtonFragment.OnFragmentInteractionListener, Communicator{
/* Using this to insert into the Bend Direction field. */
public static String SAG_DIRECTION = "SAG";
/* This spinner holds the bend types */
Spinner mSagBendTypesSpinner;
/* Using this string to collect what was selected for the spinner type */
private String mBendTypeSpinnerVal;
/* All the EditText for the Activity */
private EditText mSagGpsShotEt;
private EditText mSagExistingGpsEt;
private EditText mSagCoverEt;
private EditText mSagDegreeEt;
private EditText mSagDistanceFromEt;
private EditText mSagNotesEt;
private EditText mSagOccupyIdEt;
private EditText mSagStationNumEt;
private GPSLocationListener mGPSLocationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sag);
mGPSLocationListener = new GPSLocationListener(SagActivity.this);
/* checking if the MajorButtonFragment is null */
if (findViewById(R.id.majorButtonFragment) != null) {
if (savedInstanceState != null) {
return;
}
}
/* Referencing the spinner and setting the itemsSelectedListener */
mSagBendTypesSpinner = (Spinner) findViewById(R.id.bend_types_spinner);
mSagBendTypesSpinner.setOnItemSelectedListener((AdapterView.OnItemSelectedListener) this);
/* Create an ArrayAdapter using the string array and a default spinner layout */
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.bend_types_array, android.R.layout.simple_spinner_item);
/* Specify the layout to use when the list of choices appears */
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
/* Apply the adapter to the spinner */
mSagBendTypesSpinner.setAdapter(adapter);
/* Referencing and calling all the EditText for the Activity */
mSagGpsShotEt = (EditText) findViewById(R.id.eTextGpsShotForSag);
mSagExistingGpsEt = (EditText) findViewById(R.id.eTextExistGradeForSag);
mSagCoverEt = (EditText) findViewById(R.id.eTextCoverForSag);
mSagDegreeEt = (EditText) findViewById(R.id.eTextDegreeForSag);
mSagDistanceFromEt = (EditText) findViewById(R.id.eTextDistanceFromForSag);
mSagNotesEt = (EditText) findViewById(R.id.eTextNotesForSagActivity);
mSagOccupyIdEt = (EditText) findViewById(R.id.eTextJointIdSagActivity);
mSagStationNumEt = (EditText) findViewById(R.id.eTextStationNumSagActivity);
} /*onCreate() ends here.*/
#Override
protected void onStart() {
super.onStart();
Log.i("SagActivity", "onStart: ");
/* Starting the location listener here (GoogleApiClient) */
if (mGPSLocationListener != null){
mGPSLocationListener.onStart();
}
}
#Override
protected void onStop() {
super.onStop();
Log.i("SagActivity", "onStop: ");
/* Stopping the location listener here (GoogleApiClient) */
if (mGPSLocationListener != null){
mGPSLocationListener.onStop();
}
}
#Override
public void onLocalVoiceInteractionStopped() {
super.onLocalVoiceInteractionStopped();
}
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mBendTypeSpinnerVal = mSagBendTypesSpinner.getSelectedItem().toString();
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
#Override
public void exitBtnRespond() {
}
/**
* This overridden method comes from the Communicator Interface and is used globally in all
* Activities that implement it to Store (write) a transaction to the database.
* The utility class saveAndInsertBend() method is invoked here.
*/
#Override
public void storeBtnRespond() {
BendHelper.saveAndInsertBend(SagActivity.this, SAG_DIRECTION, mBendTypeSpinnerVal, mSagStationNumEt,
mSagOccupyIdEt, mSagDegreeEt, mSagDistanceFromEt, mSagGpsShotEt, mSagExistingGpsEt,
mSagCoverEt, mSagNotesEt);
}
#Override
public void mapItBtnRespond() {
Toast.makeText(this, "MapItBtn clicked in SagActivity",Toast.LENGTH_LONG).show();
mGPSLocationListener.getCurrentLocation();
Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lat));
Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lon));
}
#Override
public void onFragmentInteraction() {
}
}
What am I doing wrong here with all of this? Any help would be greatly appreciated as I am confused with the Permissions apparently. Thanks so much for any guidance.

You are asking for FINE_LOCATION permission in onConnected(), but onConnected is called when GPS is connected. That's the reason you are getting permission error.
You should remove this:
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
From onConnected(). Add this to getCurrentLocation() with permission request:
public void getCurrentLocation(){
//Request permission here
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation != null){
lat = mCurrentLocation.getLatitude();
lon = mCurrentLocation.getLongitude();
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude()));
Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude()));
}
}
Then also call this method in onConnected():
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "Connected to GoogleApiClient");
getCurrentLocation();
}

Related

SQLite Database not being created in Android Studio when the project is run on a new machine or if the Database folder is deleted

I have built an application where using fusedlocation provider I get the location and based on the location on I display a report card of a particular location from an SQLiteDatabase.
The database worked fine initially but then when I ran the same android project on another machine it wasn't creating the database. Once the database folder was being created by Android in Device File Explorer -> Data -> Data -> Package Name -> Databases. I was manually loading the following Database file by right clicking on the the Database folder and clicking upload.
Database file link: https://drive.google.com/file/d/197MHiLl8nvFZ5eHStrBR9WfeYvQTtDKm/view?usp=sharing
To try to understand what the issue is I deleted the database folder from my project on my own machine as well and now the Database folder isn't created on my machine as well.
Before you mark this as a duplicate I have already tried the methods from the following questions but it still didn't work.
Android SQLite database table not being created
sqlite database not created
https://alvinalexander.com/android/sqliteopenhelper-does-not-call-oncreate-failing-database
Please find my code below:
DatabaseHelper.java
package edu.cpsc6150.co2ut;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper {
public static String DATABASE_NAME = "states";
public static final int DATABASE_VERSION = 1;
public static final String TABLE_NAME = "States_Report";
public static final String KEY_ID = "id";
public static final String STATE_NAME = "name";
public static final String STATE_GRADE = "grade";
public static final String EXTREME_HEAT = "heat";
public static final String DROUGHT = "Drought";
public static final String WILDFIRES = "wildfires";
public static final String INLAND_FLOODING = "inlandflooding";
public static final String COASTAL_FLOODING = "coastalflooding";
public static final String CREATE_TABLE_STUDENTS = "CREATE TABLE "
+ TABLE_NAME + "(" + KEY_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ STATE_NAME + " TEXT,"
+ STATE_GRADE + " TEXT,"
+ EXTREME_HEAT + " TEXT,"
+ DROUGHT + " TEXT,"
+ WILDFIRES + " TEXT,"
+ INLAND_FLOODING + " TEXT,"
+ COASTAL_FLOODING + " TEXT)";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
//Log.d("table", CREATE_TABLE_STUDENTS);
} //end DatabaseHelper constructor
/**
* Functionality: Creates tables
* PreConditions: needs table names and column names
* PostConditions: Table is created
*/
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_STUDENTS);
} //end onCreate method
/**
* Functionality: Drop existing table and create new table if table already exists
* PreConditions: Database name, oldversion number and newVersion number are required to create a new table
* PostConditions: Old table should be dropped and new table should be created
*/
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS '" + TABLE_NAME + "'");
onCreate(db);
} //end onUpgrade method
/*
public long addStudentDetail(String state, String grade, String heat, String drought, String wildfires, String iflooding, String cflooding) {
SQLiteDatabase db = this.getWritableDatabase();
// Creating content values
ContentValues values = new ContentValues();
values.put(STATE_NAME, state);
values.put(STATE_GRADE, grade);
values.put(EXTREME_HEAT, heat);
values.put(DROUGHT, drought);
values.put(WILDFIRES, wildfires);
values.put(INLAND_FLOODING, iflooding);
values.put(COASTAL_FLOODING, cflooding);
// insert row in students table
long insert = db.insert(TABLE_NAME, null, values);
return insert;
}*/
/**
* Functionality: Get data from database and Update UI
* PreConditions: requires existing populated database
* PostConditions: Update reportcard in the UI from the database
*/
public String[] getData(String state) {
/*SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery( "select * from States_Report where name = '"+state+"'", null );
return res;*/
String State = state;
String[] name = new String[7];
String password;
//SQLiteDatabase db = getWritableDatabase();
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {DatabaseHelper.STATE_NAME,DatabaseHelper.STATE_GRADE,DatabaseHelper.EXTREME_HEAT,DatabaseHelper.DROUGHT,DatabaseHelper.WILDFIRES,DatabaseHelper.INLAND_FLOODING,DatabaseHelper.COASTAL_FLOODING};
Cursor cursor =db.query(DatabaseHelper.TABLE_NAME,columns,"name = '"+state+"' ",null,null,null,null);
StringBuffer buffer= new StringBuffer();
while (cursor.moveToNext())
{
name[0] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.STATE_NAME));
name[1] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.STATE_GRADE));
name[2] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.EXTREME_HEAT));
name[3] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.DROUGHT));
name[4] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.WILDFIRES));
name[5] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.INLAND_FLOODING));
name[6] =cursor.getString(cursor.getColumnIndex(DatabaseHelper.COASTAL_FLOODING));
}
return name;
} //end getData method
} //end DatabaseHelper class
ReportCardActivity.java (Which is like the MainActivity.java for this particular feature)
package edu.cpsc6150.co2ut;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteDatabase;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.provider.Settings;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.PermissionListener;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class ReportCardActivity extends AppCompatActivity {
private static final String TAG = ReportCardActivity.class.getSimpleName();
#BindView(R.id.location_result)
TextView txtLocationResult;
#BindView(R.id.btn_start_location_updates)
Button btnStartUpdates;
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 5000;
private static final int REQUEST_CHECK_SETTINGS = 100;
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private Location mCurrentLocation;
private Boolean mRequestingLocationUpdates;
private DatabaseHelper databaseHelper;
private TextView statedisplay, gradedisplay, heat, drought, wildfires, inlandFlooding,coastalFlooding;
/**
* Functionality: Instantiates the DatabaseHelper class and other UI Components like textviews
* PreConditions: DatabaseHelper and textviews must be declared
* PostConditions: Textviews are assigned and DatabaseHelper initialized
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_report_card);
ButterKnife.bind(this);
databaseHelper = new DatabaseHelper(this);
SQLiteDatabase db = new DatabaseHelper(this).getReadableDatabase();
statedisplay = (TextView) findViewById(R.id.statedisplay);
gradedisplay = (TextView) findViewById(R.id.gradedisplay);
heat = (TextView) findViewById(R.id.heat);
drought = (TextView) findViewById(R.id.drought);
wildfires = (TextView) findViewById(R.id.wildfires);
inlandFlooding = (TextView) findViewById(R.id.inlandFlooding);
coastalFlooding = (TextView) findViewById(R.id.coastalFlooding);
// initialize the necessary libraries
init();
// restore the values from saved instance state
restoreValuesFromBundle(savedInstanceState);
} //end onCreate method
/**
* Functionality: Initializes the necessary libraries to get location updates
* PreConditions: Library's required for the location updates must be declared
* PostConditions: All necessary Libraries are intialized
*/
private void init() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationCallback = new LocationCallback() {
/**
* Functionality: Updates Last location on receiving location updates
* PreConditions: Needs to receive locationResult as a parameter
* PostConditions: Return updated last location to the UI
*/
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
// location is received
mCurrentLocation = locationResult.getLastLocation();
updateLocationUI();
}
};
mRequestingLocationUpdates = false;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
} //end init method
/**
* Functionality: Restores the savedState of the activity
* PreConditions: Needs the instance state to be saved
* PostConditions: Retrieve the saved state and update the UI
*/
private void restoreValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("is_requesting_updates")) {
mRequestingLocationUpdates = savedInstanceState.getBoolean("is_requesting_updates");
}
if (savedInstanceState.containsKey("last_known_location")) {
mCurrentLocation = savedInstanceState.getParcelable("last_known_location");
}
}
updateLocationUI();
} //end restoreValuesFromBundle method
/**
* Functionality: Update the UI displaying the location data
* PreConditions: Requires the current location
* PostConditions: Updates the UI with the current location and the states report card from the database
*/
String state;
private void updateLocationUI() {
if (mCurrentLocation != null) {
Geocoder gcd = new Geocoder(this, Locale.getDefault());
try{
List<Address> addresses = gcd.getFromLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), 1);
if (addresses.size() > 0) {
state = addresses.get(0).getAdminArea();
String output[] = databaseHelper.getData(state);
statedisplay.setText(" State: "+output[0]);
gradedisplay.setText(" Average: "+output[1]);
heat.setText(" Extreme Heat: "+output[2]);
drought.setText(" Drought: "+output[3]);
wildfires.setText(" Wildfires: "+output[4]);
inlandFlooding.setText(" Inland Flooding: "+output[5]);
coastalFlooding.setText(" Coastal Flooding: "+output[6]);
/*Cursor rs = databaseHelper.getData(state);
if (rs.moveToFirst()){
// do the work
String username = rs.getString(1);
String password = rs.getString(2);
//String nam = rs.getString(rs.getColumnIndex(DatabaseHelper.STATE_NAME));
//String phon = rs.getString(rs.getColumnIndex(DatabaseHelper.STATE_GRADE));
statedisplay.setText(username);
gradedisplay.setText(password);
}*/
//arrayList = databaseHelper.getAllStudentsList();
//tvnames.setText("");
/*for (int i = 0; i < arrayList.size(); i++){
tvnames.setText(tvnames.getText().toString()+", "+arrayList.get(i));
}*/
}
else {
// do your stuff
}
} catch (IOException e1) {
e1.printStackTrace();
} //end try-catch block
txtLocationResult.setText(
getString(R.string.welcome_message,state)
);
// location last updated time
}
} //end updateLocationUI method
/**
* Functionality: Saves the Activities current state
* PreConditions: Needs the values of mCurrentLocation and mRequestingLocationUpdates
* PostConditions: The Instance state should be saved to the Bundle
*/
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("is_requesting_updates", mRequestingLocationUpdates);
outState.putParcelable("last_known_location", mCurrentLocation);
} //end onSaveInstanceState method
/**
* Functionality: Starting location updates
* PreConditions: Check whether location settings are satisfied
* PostConditions: Location updates will be requested
*/
private void startLocationUpdates() {
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#SuppressLint("MissingPermission")
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "All location settings are satisfied.");
Toast.makeText(getApplicationContext(), "Started location updates!", Toast.LENGTH_SHORT).show();
//noinspection MissingPermission
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
updateLocationUI();
} //end onSuccess method
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade " +
"location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the
// result in onActivityResult().
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(ReportCardActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sie) {
Log.i(TAG, "PendingIntent unable to execute request.");
} //end try-catch block
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
String errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
Log.e(TAG, errorMessage);
Toast.makeText(ReportCardActivity.this, errorMessage, Toast.LENGTH_LONG).show();
} //end switch statement
updateLocationUI();
} //end onFailure method
});
} //end startLocationUpdates method
/**
* Functionality: OnClick will start receiving location updates
* PreConditions: Permissions must be granted
* PostConditions: Location Updates started
*/
#OnClick(R.id.btn_start_location_updates)
public void startLocationButtonClick() {
// Requesting ACCESS_FINE_LOCATION using Dexter library
Dexter.withActivity(this)
.withPermission(Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse response) {
mRequestingLocationUpdates = true;
startLocationUpdates();
} //end onPermissionGranted method
#Override
public void onPermissionDenied(PermissionDeniedResponse response) {
if (response.isPermanentlyDenied()) {
// open device settings when the permission is
// denied permanently
openSettings();
}
} //end onPermuissionDenied method
#Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
token.continuePermissionRequest();
} //end onPermissionRationaleShouldBeShown method
}).check();
} //end startLocationButtonClick method
/**
* Functionality: Stop or pause location updates when the app pauses
* PreConditions: FusedLocationClient must be intialized
* PostConditions: Stop Location updates
*/
public void stopLocationUpdates() {
// Removing location updates
mFusedLocationClient
.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(this, new OnCompleteListener<Void>() {
/**
* Functionality:
* PreConditions:
* PostConditions:
*/
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(getApplicationContext(), "Location updates stopped!", Toast.LENGTH_SHORT).show();
}
});
} //end stopLocationUpdates method
/**
* Functionality: Check whether user has granted permissions or not
* PreConditions: Needs requestCode, resultCode and data as parameters
* PostConditions: Log the ActivityResult as an error log
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
Log.e(TAG, "User agreed to make required location settings changes.");
// Nothing to do. startLocationupdates() gets called in onResume again.
break;
case Activity.RESULT_CANCELED:
Log.e(TAG, "User chose not to make required location settings changes.");
mRequestingLocationUpdates = false;
break;
} //end switch statement
break;
} //end switch statement
} //end onActivityResult method
/**
* Functionality: Open settings if permissions is denied
* PreConditions: Settings URI
* PostConditions: Open Application details settings page
*/
private void openSettings() {
Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} //end openSettings method
/**
* Functionality: Check for permissions again onResume
* PreConditions: App must be paused or stopped before this function is called
* PostConditions: onResume the locationupdates must be resume and the UI must be updated
*/
#Override
public void onResume() {
super.onResume();
// Resuming location updates depending on button state and
// allowed permissions
if (mRequestingLocationUpdates && checkPermissions()) {
startLocationUpdates();
}
updateLocationUI();
} //end onResume()
/**
* Functionality: Checks if permission to access location is granted
* PreConditions: Permission must be mentioned in the manifest file
* PostConditions: Return permission granted if Uses-Permission is mentioned in the activity file
*/
private boolean checkPermissions() {
int permissionState = ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
return permissionState == PackageManager.PERMISSION_GRANTED;
} //end checkPermissions method
/**
* Functionality: Stops location updates when the application is paused
* PreConditions: Application must be paused
* PostConditions: Location updates must be stopped
*/
#Override
protected void onPause() {
super.onPause();
if (mRequestingLocationUpdates) {
// pausing location updates
stopLocationUpdates();
}
} //end onPause method
} //end ReportCardActivity class
Let me know if you need any more information regarding the code or dependencies.
I believe that the database is being created BUT you don't appear to be populating it.
Using your Databasehelper (with addStudentDetail uncommented as the only change) then using :-
public class MainActivity extends AppCompatActivity {
DatabaseHelper mDBHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHelper = new DatabaseHelper(this);
mDBHelper.addStudentDetail("STATE1","GRADE1","HIGH","YES","NO","NO","NO");
mDBHelper.addStudentDetail("STATE1","GRADE2","HIGH","YES","NO","NO","NO");
mDBHelper.addStudentDetail("STATE1","GRADE3","HIGH","YES","NO","NO","NO");
mDBHelper.addStudentDetail("STATE1","GRADE4","HIGH","YES","NO","NO","NO");
for (String s: mDBHelper.getData("STATE1")){
Log.d("INFO",s);
}
}
}
results in :-
12-05 16:38:19.211 3764-3764/? D/INFO: STATE1
12-05 16:38:19.211 3764-3764/? D/INFO: GRADE4
12-05 16:38:19.211 3764-3764/? D/INFO: HIGH
12-05 16:38:19.211 3764-3764/? D/INFO: YES
12-05 16:38:19.211 3764-3764/? D/INFO: NO
12-05 16:38:19.211 3764-3764/? D/INFO: NO
12-05 16:38:19.211 3764-3764/? D/INFO: NO
I can't see anywhere in your code where you are adding data to the database. rather you just try to get data using String output[] = databaseHelper.getData(state);, which will retrieve nothing as there is no data.
Below I have attached a solution where you just need to add two lines of code to the ReportCardActivity.java code. The two lines of code to be added are commented as "//add this line" and have a line of astrix (*) before and after it.
private Boolean mRequestingLocationUpdates;
DatabaseHelper databaseHelper;
*********************************************************
SQLiteDatabase database; //add this line
*********************************************************
private TextView statedisplay, gradedisplay, heat, drought, wildfires, inlandFlooding,coastalFlooding;
/**
* Functionality: Instantiates the DatabaseHelper class and other UI Components like textviews
* PreConditions: DatabaseHelper and textviews must be declared
* PostConditions: Textviews are assigned and DatabaseHelper initialized
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_report_card);
ButterKnife.bind(this);
databaseHelper = new DatabaseHelper(this);
*********************************************************
database = databaseHelper.getWritableDatabase(); //add this line
*********************************************************
statedisplay = (TextView) findViewById(R.id.statedisplay);
gradedisplay = (TextView) findViewById(R.id.gradedisplay);
heat = (TextView) findViewById(R.id.heat);
drought = (TextView) findViewById(R.id.drought);
wildfires = (TextView) findViewById(R.id.wildfires);
inlandFlooding = (TextView) findViewById(R.id.inlandFlooding);
coastalFlooding = (TextView) findViewById(R.id.coastalFlooding);
// initialize the necessary libraries
init();
// restore the values from saved instance state
restoreValuesFromBundle(savedInstanceState);
} //end onCreate method
One you paste the code run the application. This should create the database directory in the Device File Explorer -> Data -> Data -> Package Name directory.
The database folder might not be visible immediately. You may have to restart android studio after you run the app once.
When you restart android studio and go to Device File Explorer -> Data -> Data -> Package Name directory the databases directory should be created.
Once it is created right click on the databases folder and click upload then upload the database file you have provided in the link.

Google-API Start Activity as Service or hide Activity

I've got a problem with my Google-API Activity. I used the sample code from Google and changed some lines to fill on create an static int with my total mail count. So far so good, this works fine. Every time I have to update my mail_count value I execute the following code:
Intent intent2 = new Intent(getBaseContext(), MainActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startService(intent2);
This works fine, but the problem is that every time I start the activity it'll show up for some seconds. I really know that's the point of activities, but I didn't get how to use the GOOGLE-API Activity in my project to communicate in Background with the API and don't show up every time (after User has confirmed the access).
Here's my Google-API Activity Code (MainActivity):
.widgetNew;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.*;
import android.Manifest;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.EasyPermissions;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
//ProgressDialog mProgress;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003;
static int EMAIL_COUNT = 0;
private static final String BUTTON_TEXT = "Call Gmail API";
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { GmailScopes.GMAIL_LABELS, GmailScopes.GMAIL_READONLY , GmailScopes.MAIL_GOOGLE_COM};
/**
* Create the main activity.
* #param savedInstanceState previously saved instance data.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// LinearLayout activityLayout = new LinearLayout(this);
// LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.MATCH_PARENT,
// LinearLayout.LayoutParams.MATCH_PARENT);
// activityLayout.setLayoutParams(lp);
// activityLayout.setOrientation(LinearLayout.VERTICAL);
// activityLayout.setPadding(16, 16, 16, 16);
// ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
// ViewGroup.LayoutParams.WRAP_CONTENT,
// ViewGroup.LayoutParams.WRAP_CONTENT);
// mCallApiButton = new Button(this);
// mCallApiButton.setText(BUTTON_TEXT);
// mCallApiButton.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// mCallApiButton.setEnabled(false);
// mOutputText.setText("");
// mCallApiButton.setEnabled(true);
// }
// });
//activityLayout.addView(mCallApiButton);
// mOutputText = new TextView(this);
//mOutputText.setLayoutParams(tlp);
// mOutputText.setPadding(16, 16, 16, 16);
// mOutputText.setVerticalScrollBarEnabled(true);
// mOutputText.setMovementMethod(new ScrollingMovementMethod());
// mOutputText.setText(
// "Click the \'" + BUTTON_TEXT +"\' button to test the API.");
//activityLayout.addView(mOutputText);
// mProgress = new ProgressDialog(this);
// mProgress.setMessage("Calling Gmail API ...");
//setContentView(activityLayout);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
getResultsFromApi();
finish();
}
/**
* Attempt to call the API, after verifying that all the preconditions are
* satisfied. The preconditions are: Google Play Services installed, an
* account was selected and the device currently has online access. If any
* of the preconditions are not satisfied, the app will prompt the user as
* appropriate.
*/
private void getResultsFromApi() {
if (! isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} else if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else if (! isDeviceOnline()) {
//mOutputText.setText("No network connection available.");
} else {
new MakeRequestTask(mCredential).execute();
}
}
/**
* Attempts to set the account used with the API credentials. If an account
* name was previously saved it will use that one; otherwise an account
* picker dialog will be shown to the user. Note that the setting the
* account to use with the credentials object requires the app to have the
* GET_ACCOUNTS permission, which is requested here if it is not already
* present. The AfterPermissionGranted annotation indicates that this
* function will be rerun automatically whenever the GET_ACCOUNTS permission
* is granted.
*/
#AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS)
private void chooseAccount() {
if (EasyPermissions.hasPermissions(
this, Manifest.permission.GET_ACCOUNTS)) {
String accountName = getPreferences(Context.MODE_PRIVATE)
.getString(PREF_ACCOUNT_NAME, null);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
} else {
// Start a dialog from which the user can choose an account
startActivityForResult(
mCredential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
} else {
// Request the GET_ACCOUNTS permission via a user dialog
EasyPermissions.requestPermissions(
this,
"This app needs to access your Google account (via Contacts).",
REQUEST_PERMISSION_GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS);
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* #param requestCode code indicating which activity result is incoming.
* #param resultCode code indicating the result of the incoming
* activity result.
* #param data Intent (containing result data) returned by incoming
* activity result.
*/
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
//mOutputText.setText(
// "This app requires Google Play Services. Please install " +
// "Google Play Services on your device and relaunch this app.");
} else {
getResultsFromApi();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null &&
data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
SharedPreferences settings =
getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == RESULT_OK) {
getResultsFromApi();
}
break;
}
}
/**
* Respond to requests for permissions at runtime for API 23 and above.
* #param requestCode The request code passed in
* requestPermissions(android.app.Activity, String, int, String[])
* #param permissions The requested permissions. Never null.
* #param grantResults The grant results for the corresponding permissions
* which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null.
*/
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
/**
* Callback for when a permission is granted using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Callback for when a permission is denied using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Checks whether the device currently has a network connection.
* #return true if the device has a network connection, false otherwise.
*/
private boolean isDeviceOnline() {
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
/**
* Check that Google Play services APK is installed and up to date.
* #return true if Google Play Services is available and up to
* date on this device; false otherwise.
*/
private boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
return connectionStatusCode == ConnectionResult.SUCCESS;
}
/**
* Attempt to resolve a missing, out-of-date, invalid or disabled Google
* Play Services installation via a user dialog, if possible.
*/
private void acquireGooglePlayServices() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
}
}
/**
* Display an error dialog showing that Google Play Services is missing
* or out of date.
* #param connectionStatusCode code describing the presence (or lack of)
* Google Play Services on this device.
*/
void showGooglePlayServicesAvailabilityErrorDialog(
final int connectionStatusCode) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
Dialog dialog = apiAvailability.getErrorDialog(
MainActivity.this,
connectionStatusCode,
REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
/**
* An asynchronous task that handles the Gmail API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private com.google.api.services.gmail.Gmail mService = null;
private Exception mLastError = null;
public MakeRequestTask(GoogleAccountCredential credential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.gmail.Gmail.Builder(
transport, jsonFactory, credential)
.setApplicationName("Gmail API Android Quickstart")
.build();
}
/**
* Background task to call Gmail API.
* #param params no parameters needed for this task.
*/
#Override
protected List<String> doInBackground(Void... params) {
try {
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* Fetch a list of Gmail labels attached to the specified account.
* #return List of Strings labels.
* #throws IOException
*/
private List<String> getDataFromApi() throws IOException {
// Get the labels in the user's account.
String user = "me";
List<String> labels = new ArrayList<String>();
Profile profile = mService.users().getProfile("me").execute();
labels.add("E-Mails: " + profile.getMessagesTotal());
EMAIL_COUNT = profile.getMessagesTotal();
//tv.setText("TEST");
return labels;
}
#Override
protected void onPreExecute() {
// mOutputText.setText("");
// mProgress.show();
}
#Override
protected void onPostExecute(List<String> output) {
//mProgress.hide();
if (output == null || output.size() == 0) {
// mOutputText.setText("No results returned.");
} else {
//output.add(0, "Data retrieved using the Gmail API:");
//mOutputText.setText(TextUtils.join("\n", output));
finish();
}
}
#Override
protected void onCancelled() {
// mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
MainActivity.REQUEST_AUTHORIZATION);
} else {
// mOutputText.setText("The following error occurred:\n"
// + mLastError.getMessage());
}
} else {
// mOutputText.setText("Request cancelled.");
}
}
}
}

Searching a Google Spreadsheet with Android App

I was wondering how I could find an integer in a cell of a Google Spreadsheet, for Android Studio (java).
I was using the Android Sheets API's Quickstart as an entire guideline/reference, because my coding isn't really great, so I was hoping if anyone could give me direct help on this.
Heres my code:
package com.package.Test;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.*;
import android.Manifest;
import android.accounts.AccountManager;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.*;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.EasyPermissions;
/**
* Created by terminal on 9/2/2016.
*/
public class AttendanceActivity extends AppCompatActivity
implements EasyPermissions.PermissionCallbacks{
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
private EditText editText;
private TextView textView7;
private TextView textView6;
private TextView textView5;
private Button checker;
ProgressDialog mProgress;
public int iString;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003;
private static final String BUTTON_TEXT = "Check";
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { SheetsScopes.SPREADSHEETS_READONLY };
/**
* Create the main activity.
* #param savedInstanceState previously saved instance data.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout activityLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
activityLayout.setLayoutParams(lp);
activityLayout.setOrientation(LinearLayout.VERTICAL);
activityLayout.setPadding(16, 16, 16, 16);
ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
textView6 = new TextView(this);
textView6.setText("Attendance");
textView6.setTextSize(50);
textView6.setGravity(Gravity.CENTER);
editText = new EditText(this);
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setHint("Enter ID Number...");
LinearLayout.LayoutParams etLP = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
etLP.setMargins(40, 50, 40, 0);
int maxLength = 8;
editText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(maxLength)});
mCallApiButton = new Button(this);
mCallApiButton.setText(BUTTON_TEXT);
mCallApiButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallApiButton.setEnabled(false);
mOutputText.setText("");
iString = Integer.parseInt(editText.getText().toString());
getResultsFromApi();
mCallApiButton.setEnabled(true);
}
});
textView5 = new TextView(this);
textView5.setText("-You currently have-");
textView5.setGravity(Gravity.CENTER);
textView7 = new TextView(this);
textView7.setText("Hours!");
textView7.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams tv7lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv7lp.setMargins(0, 30, 0, 0);
mOutputText = new TextView(this);
mOutputText.setTextSize(30);
mOutputText.setLayoutParams(tlp);
mOutputText.setPadding(16, 16, 16, 16);
mOutputText.setVerticalScrollBarEnabled(true);
mOutputText.setMovementMethod(new ScrollingMovementMethod());
mOutputText.setText("");
activityLayout.addView(textView6);
activityLayout.addView(editText, etLP);
activityLayout.addView(mCallApiButton);
activityLayout.addView(textView5);
activityLayout.addView(mOutputText);
activityLayout.addView(textView7, tv7lp);
mProgress = new ProgressDialog(this);
mProgress.setMessage("Searching for your ID Number ...");
setContentView(activityLayout);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
}
public boolean onOptionsItemSelected(MenuItem item){
Intent myIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivityForResult(myIntent, 0);
return true;
}
/**
* Attempt to call the API, after verifying that all the preconditions are
* satisfied. The preconditions are: Google Play Services installed, an
* account was selected and the device currently has online access. If any
* of the preconditions are not satisfied, the app will prompt the user as
* appropriate.
*/
private void getResultsFromApi() {
if (! isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} else if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else if (! isDeviceOnline()) {
mOutputText.setText("No network connection available.");
} else {
new MakeRequestTask(mCredential).execute();
}
}
/**
* Attempts to set the account used with the API credentials. If an account
* name was previously saved it will use that one; otherwise an account
* picker dialog will be shown to the user. Note that the setting the
* account to use with the credentials object requires the app to have the
* GET_ACCOUNTS permission, which is requested here if it is not already
* present. The AfterPermissionGranted annotation indicates that this
* function will be rerun automatically whenever the GET_ACCOUNTS permission
* is granted.
*/
#AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS)
private void chooseAccount() {
if (EasyPermissions.hasPermissions(
this, Manifest.permission.GET_ACCOUNTS)) {
String accountName = getPreferences(Context.MODE_PRIVATE)
.getString(PREF_ACCOUNT_NAME, null);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
} else {
// Start a dialog from which the user can choose an account
startActivityForResult(
mCredential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
} else {
// Request the GET_ACCOUNTS permission via a user dialog
EasyPermissions.requestPermissions(
this,
"This app needs to access your Google account (via Contacts).",
REQUEST_PERMISSION_GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS);
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* #param requestCode code indicating which activity result is incoming.
* #param resultCode code indicating the result of the incoming
* activity result.
* #param data Intent (containing result data) returned by incoming
* activity result.
*/
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
mOutputText.setText(
"This app requires Google Play Services. Please install " +
"Google Play Services on your device and relaunch this app.");
} else {
getResultsFromApi();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null &&
data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
SharedPreferences settings =
getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == RESULT_OK) {
getResultsFromApi();
}
break;
}
}
/**
* Respond to requests for permissions at runtime for API 23 and above.
* #param requestCode The request code passed in
* requestPermissions(android.app.Activity, String, int, String[])
* #param permissions The requested permissions. Never null.
* #param grantResults The grant results for the corresponding permissions
* which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null.
*/
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
/**
* Callback for when a permission is granted using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Callback for when a permission is denied using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Checks whether the device currently has a network connection.
* #return true if the device has a network connection, false otherwise.
*/
private boolean isDeviceOnline() {
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
/**
* Check that Google Play services APK is installed and up to date.
* #return true if Google Play Services is available and up to
* date on this device; false otherwise.
*/
private boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
return connectionStatusCode == ConnectionResult.SUCCESS;
}
/**
* Attempt to resolve a missing, out-of-date, invalid or disabled Google
* Play Services installation via a user dialog, if possible.
*/
private void acquireGooglePlayServices() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
}
}
/**
* Display an error dialog showing that Google Play Services is missing
* or out of date.
* #param connectionStatusCode code describing the presence (or lack of)
* Google Play Services on this device.
*/
void showGooglePlayServicesAvailabilityErrorDialog(
final int connectionStatusCode) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
Dialog dialog = apiAvailability.getErrorDialog(
AttendanceActivity.this,
connectionStatusCode,
REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
/**
* An asynchronous task that handles the Google Sheets API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private com.google.api.services.sheets.v4.Sheets mService = null;
private Exception mLastError = null;
public MakeRequestTask(GoogleAccountCredential credential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.sheets.v4.Sheets.Builder(
transport, jsonFactory, credential)
.setApplicationName("Google Sheets API Android Quickstart")
.build();
}
/**
* Background task to call Google Sheets API.
* #param params no parameters needed for this task.
*/
#Override
protected List<String> doInBackground(Void... params) {
try {
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* Fetch a list of names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
* #return List of names and majors
* #throws IOException
*/
private List<String> getDataFromApi() throws IOException {
String spreadsheetId = "1PWNdgkcmKVbzWc2e0rc5XWlI7pkF7xaYK7JQcq8Feyg";
String range = "Sheet1!A2:B300";
// It is "WorksheetName!StartingCell:NextColumn Convert Letters into numbers, and find the value of the difference
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(spreadsheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
for (List column : values) {
results.add(column.get(0) + "");
// The last value must be 1 less of the value of the difference above
}
}
return results;
}
#Override
protected void onPreExecute() {
mOutputText.setText("");
mProgress.show();
}
#Override
protected void onPostExecute(List<String> output) {
mProgress.hide();
if (output == null || output.size() == 0) {
mOutputText.setText("Invalid ID Number!");
} else {
//output.add(0, "This is a string before the list");
mOutputText.setText(TextUtils.join("\n", output));
}
}
#Override
protected void onCancelled() {
mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
AttendanceActivity.REQUEST_AUTHORIZATION);
} else {
mOutputText.setText("The following error occurred:\n"
+ mLastError.getMessage());
}
} else {
mOutputText.setText("Request cancelled.");
}
}
}
}
However, I specifically need help on this part.
private List<String> getDataFromApi() throws IOException {
String spreadsheetId = "1PWNdgkcmKVbzWc2e0rc5XWlI7pkF7xaYK7JQcq8Feyg";
String range = "Sheet1!A2:B300";
// It is "WorksheetName!StartingCell:NextColumn Convert Letters into numbers, and find the value of the difference
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(spreadsheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
for (List column : values) {
results.add(column.get(0) + "");
// The last value must be 1 less of the value of the difference above
}
}
return results;
}
So what I have done is that I have an editText input field consisting of only numbers, and it's input is put into a public integer iString when I click a button.
Now, I have to declare SOMEHOW that Google Spreadsheets will search the first column(Column A) for iString. If it exists, then give the value of the adjacent column (Column B).
I know this was a bit long, but thank you for any particular insight or solutions you guys may have. Cheers!
Checking out the Reading & Writing Value section of the documentation, it doesn't indicate an easy way of retrieving the cell number of your use case. The spreadsheet.values.get API call will need the spreadsheetId and range, the request body only indicates a view VariableRenderOptions (formatted, unformatted, formula).
With this limitation, you can make use of the 2d array values from the response to check the array[x][0] if its the value of iString. Use that x value to update array[x][1] and call the update API.
Hopefully this could help you a bit for your scenario.
Happy coding!

onLocationChanged does not get called using fusedLocationAPI.requestLocationUpdates

I've been trying to use the fusedLocationApi to get my current location. I'm using android studio with an emulated Nexus 6. According to the online documentation https://developer.android.com/training/location/receive-location-updates.html?hl=es
we can request location updates using:
FusedLocationApi.requestLocationUpdates
and the callback goes to:
onLocationChanged(Location location)
However, onLocationChanged is not getting called at all. If it did, it would print something in the log cause I put a Log.d line there. Note that startLocationUpdates() does get called. Below is my code. It would be great if someone could shed some light on this =) I'm really new to Android so I'm a bit clueless rn. Could it be something about the emulator (GPS,.. idk) that is causing this issue?
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap; // google map works well just as default project
private GoogleApiClient mGoogleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
private LocationRequest mLocationRequest;
private static final int REQUEST_LOCATION = 2;
private Location location;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(1000)
.setFastestInterval(100);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION);
} else {
location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
startLocationUpdates();
}
else {
handleNewLocation(location);
};
}
}
protected void startLocationUpdates() {
Log.d(TAG, "Requesting location updates");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d(TAG, msg);
}
manifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Gradle build:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.google.android.gms:play-services:9.0.0'
}
Are you sure your GPS is turned on? You can try going through this sample project by Google Google on GitHub. In this project they have also provided code for checking if Location services are enabled. If they are not, user will be given a message so they can activate their location services.
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.mapdemo;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
/**
* This demo shows how GMS Location can be used to check for changes to the users location. The
* "My Location" button uses GMS Location to set the blue dot representing the users location.
* Permission for {#link android.Manifest.permission#ACCESS_FINE_LOCATION} is requested at run
* time. If the permission has not been granted, the Activity is finished with an error message.
*/
public class MyLocationDemoActivity extends AppCompatActivity
implements
OnMyLocationButtonClickListener,
OnMapReadyCallback,
ActivityCompat.OnRequestPermissionsResultCallback {
/**
* Request code for location permission request.
*
* #see #onRequestPermissionsResult(int, String[], int[])
*/
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
/**
* Flag indicating whether a requested permission has been denied after returning in
* {#link #onRequestPermissionsResult(int, String[], int[])}.
*/
private boolean mPermissionDenied = false;
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_location_demo);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
mMap.setOnMyLocationButtonClickListener(this);
enableMyLocation();
}
/**
* Enables the My Location layer if the fine location permission has been granted.
*/
private void enableMyLocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Permission to access the location is missing.
PermissionUtils.requestPermission(this, LOCATION_PERMISSION_REQUEST_CODE,
Manifest.permission.ACCESS_FINE_LOCATION, true);
} else if (mMap != null) {
// Access to the location has been granted to the app.
mMap.setMyLocationEnabled(true);
}
}
#Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
return;
}
if (PermissionUtils.isPermissionGranted(permissions, grantResults,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Enable the my location layer if the permission has been granted.
enableMyLocation();
} else {
// Display the missing permission error dialog when the fragments resume.
mPermissionDenied = true;
}
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mPermissionDenied) {
// Permission was not granted, display error dialog.
showMissingPermissionError();
mPermissionDenied = false;
}
}
/**
* Displays a dialog with error message explaining that the location permission is missing.
*/
private void showMissingPermissionError() {
PermissionUtils.PermissionDeniedDialog
.newInstance(true).show(getSupportFragmentManager(), "dialog");
}
}
Old question but unless something has changed since I tried it last, the emulator doesn't know its location. You have to send it coordinates.

java.lang.IllegalArguementException:Attempt to invoke virtual method 'double android.Location.getlatitude()' on a null object reference

I am trying to develop an Android application, which can access the current location of my phone and send it to my friend with URL.
So I use location object mLocation to access latitude and longitude of my location. FectchAddressIntentService.java is a service to obtain location address.
But it gives an error:
java.lang.IllegalArguementException:Attempt to invoke virtual method 'double android.Location.getlatitude()' on a null object reference
Here is the code of my MainActivity.java:
public class MainActivity extends AppCompatActivity implements
ConnectionCallbacks, OnConnectionFailedListener {
protected static final String TAG = "main-activity";
protected static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
protected static final String LOCATION_ADDRESS_KEY = "location-address";
protected String message;
protected String phoneNo = "1234567890";
public void sendMessage() {
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, message, null, null);
Toast.makeText(MainActivity.this,"Sending SMS",Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG);
}
}
public void startGuardianActivity(){
Intent intentViewGuardian = new Intent(this, Guardians.class);
startActivity(intentViewGuardian);
}
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Represents a geographical location.
*/
protected Location mLastLocation;
protected String latitude;
protected String longitude;
/**
* Tracks whether the user has requested an address. Becomes true when the user requests an
* address and false when the address (or an error message) is delivered.
* The user requests an address by pressing the Fetch Address button. This may happen
* before GoogleApiClient connects. This activity uses this boolean to keep track of the
* user's intent. If the value is true, the activity tries to fetch the address as soon as
* GoogleApiClient connects.
*/
protected boolean mAddressRequested;
/**
* The formatted location address.
*/
protected String mAddressOutput;
/**
* Receiver registered with this activity to get the response from FetchAddressIntentService.
*/
private AddressResultReceiver mResultReceiver;
/**
* Kicks off the request to fetch an address when pressed.
*/
Button btnAlert;
Button btnAddGuardian;
Button btnRemoveGuardian;
Button btnViewGuardians;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mResultReceiver = new AddressResultReceiver(new Handler());
btnAlert = (Button) findViewById(R.id.btn_Alert);
btnAddGuardian = (Button) findViewById(R.id.btn_add_guardian);
btnRemoveGuardian = (Button) findViewById(R.id.btn_remove_guardian);
btnViewGuardians = (Button) findViewById(R.id.btn_view_guardians);
btnAddGuardian.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
btnRemoveGuardian.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
btnViewGuardians.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startGuardianActivity();
}
});
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
updateUIWidgets();
buildGoogleApiClient();
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Builds a GoogleApiClient. Uses {#code #addApi} to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
/**
* Runs when user clicks the Fetch Address button. Starts the service to fetch the address if
* GoogleApiClient is connected.
*/
public void fetchAddressButtonHandler(View view) {
// We only start the service to fetch the address if GoogleApiClient is connected.
if (mGoogleApiClient.isConnected() && mLastLocation != null) {
startIntentService();
}
// If GoogleApiClient isn't connected, we process the user's request by setting
// mAddressRequested to true. Later, when GoogleApiClient connects, we launch the service to
// fetch the address. As far as the user is concerned, pressing the Fetch Address button
// immediately kicks off the process of getting the address.
mAddressRequested = true;
updateUIWidgets();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
try {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
}
catch(Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG).show();
}
try {
if (mLastLocation != null) {
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
}
}
catch(Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG).show();
}
// It is possible that the user presses the button to get the address before the
// GoogleApiClient object successfully connects. In such a case, mAddressRequested
// is set to true, but no attempt is made to fetch the address (see
// fetchAddressButtonHandler()) . Instead, we start the intent service here if the
// user has requested an address, since we now have a connection to GoogleApiClient.
if (mAddressRequested) {
startIntentService();
}
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
protected void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
// Start the service. If the service isn't already running, it is instantiated and started
// (creating a process for it if needed); if it is running then it remains running. The
// service kills itself automatically once all intents are processed.
startService(intent);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
/**
* Updates the address in the UI.
*/
protected void displayAddressOutput() {
sendMessage();
}
private void updateUIWidgets() {
if (mAddressRequested) {
btnAlert.setEnabled(false);
} else {
btnAlert.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
protected void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
/**
* Receiver for data sent from FetchAddressIntentService.
*/
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
/**
* Receives data sent from FetchAddressIntentService and updates the UI in MainActivity.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
message = "I am in DANGER!!I need your help #"+mAddressOutput+" link: http://maps.google.com/?q="+latitude+","+longitude;
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
mAddressRequested = false;
updateUIWidgets();
}
}
}
I tried to convert
latitude = String.valueOf(mLastLocation.getLatitude());
to
longitude = String.valueOf(mLastLocation.getLongitude());
But didn't work.
I don't know what this error is, I don`t know what NullPointerException is,
I tried to follow other Questions on Stack Overflow of similar type but didn't solve problem, Can anyone help me to get through this?
Even if you feel it might be a duplicate of other question, tell me how it is or how they are related & how to solve my problem. Thanks in advance.:-)
The error means the valiable mLastLocation is null.
So the result of this line:
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
is null. I think you should null check before these lines:
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
Because they are calling methods of mLastLocation.
That is like:
if (mLastLocation == null || !Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());

Categories

Resources