I'm completely new to Android development, but I have worked with Java (and other programming languages) before.
I'm using Android Studio to develop my application and I've become stuck when following the developer tutorial on accessing Location information (http://developer.android.com/training/location/index.html). I understand that the Location services require the android.permission.ACCESS_COARSE_LOCATION and/or android.permission.ACCESS_FINE_LOCATION permissions but upon adding them to my ApplicationManifest my application still crashes with a SecurityException
java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any location operations.
I've come across several other instances of people having trouble, but these have generally been the result of mis-placing (java.lang.SecurityException: Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission), mis-spelling (ACCESS_FINE_LOCATION AndroidManifest Permissions Not Being Granted) or incorrect capitalization of the permission string.
Here is my ApplicationManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="scd.tt" >
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher_tt_v2"
android:label="#string/app_name"
android:theme="#style/TT_Theme">
<activity
android:name=".MainActivity"
android:theme="#style/TT_Theme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".LoginActivity" android:theme="#style/TT_Theme.NoActionBar" />
<activity android:name=".IndexActivity" />
</application>
</manifest>
I've even tried to remove ACCESS_NETWORK_STATE and INTERNET to see if this would cause other SecurityExceptions as the application is required to communicate with an HTTP server (which it performs successfully) before it gets attempts to get Location information.
It seems as though modifications I make to the permissions on the AndroidManifest aren't being updated when I run the program. I've also tried to Clean and Rebuild the application using the Build menu.
UPDATE:
Here is the core of the Activity; I've removed some of the unrelated methods (such as onCreateOptionsMenu() and onBackPressed() as they have nothing to do with the Location)
package scd.tt;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
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;
import java.util.Map;
/**
* Created by Liam on 08/09/2015
*/
public class IndexActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location mLastLocation;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
if(debug) Log.d(TAG, "onCreate() called: savedInstanceState is " + (savedInstanceState == null ? "null" : "not null"));
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
buildGoogleApiClient();
if (findViewById(R.id.index_fragment_container) != null) {
if (savedInstanceState != null) return;
Fragment index = new IndexFragment();
index.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.index_fragment_container, index).commit();
}
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
}
#Override
public void onConnected(Bundle bundle) {
if(debug) Log.d(TAG, "onConnected");
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
if(debug) Log.d(TAG, "Connection Suspended");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if(debug) Log.d(TAG, "Connection Failed");
}
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
if(debug) Log.d(TAG, "buildGoogleAPIClient()");
}
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
Check these 3 links. They might help -
Android - Unable to get the gps location on the emulator
ACCESS_FINE_LOCATION permission error emulator only
http://www.gitshah.com/2011/02/android-fixing-no-internet-connection.html
As quoted by you in comments -
Permissions with a protection level of dangerous must be granted at runtime by prompting the user as of SDK 23 and can not be defined solely in the Manifest any more.
Related
I would like to figure out the cause of not registering a listener for a step counter sensor and how to overcome it.
MainActivity.java
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private SensorManager sensorManager;
private TextView count;
boolean activityRunning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
count = (TextView) findViewById(R.id.counter);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}
#Override
protected void onResume() {
super.onResume();
activityRunning = true;
Sensor countSensor = sensorManager
.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
if (countSensor != null) {
if (sensorManager.registerListener(this, countSensor, SensorManager.SENSOR_DELAY_UI)) {
Toast.makeText(this, "registered", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "NOT registered", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Count sensor not available", Toast.LENGTH_LONG).show();
}
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR)) {
Toast.makeText(getApplicationContext(), "STEP DETECTOR -> SUPPORTED", Toast.LENGTH_LONG).show();
Log.i("onResume", "step detector is supported");
} else {
Toast toast = Toast.makeText(getApplicationContext(), "STEP DETECTOR -> NO", Toast.LENGTH_LONG).show();
Log.i("onResume", "step detector is NOT supported");
}
}
#Override
protected void onPause() {
super.onPause();
activityRunning = false;
}
#Override
public void onSensorChanged(SensorEvent event) {
if (activityRunning) {
count.setText(String.valueOf(event.values[0]));
Toast.makeText(this, "onSensorChanged", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "changed, else branch", Toast.LENGTH_LONG).show();
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-feature android:name="android.hardware.sensor.stepcounter" android:required="true"/>
<uses-feature android:name="android.hardware.SensorManager"/>
<uses-feature android:name="android.hardware.Sensor"/>
<uses-feature android:name="android.hardware.SensorEvent"/>
<uses-feature android:name="android.hardware.SensorEventListener"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
It shows a Toast with NOT registered and this error in Logcat
E/SensorManager: registerListenerImpl sensorName:Step Counter,isWakeUpSensor:false
P.S. It pops up the STEP DETECTOR -> SUPPORTED toast for the check of the presence of this sensor. Is there something else that must be added to the manifest? Or probably, it is a wrong way of registering a listener?
Try adding the activity recognition permission to your manifest:
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
If you app targets Android 10+ (API 29 or later), you may need to request the permission at runtime as well:
https://developer.android.com/about/versions/10/privacy/changes#physical-activity-recognition
This question already has answers here:
Android permission doesn't work even if I have declared it
(11 answers)
Closed 2 years ago.
Upon accessing the Maps Activity, it crashes. I've tried switching out the Activity with a generic Maps Activity which does work, and I've rolled back to a previous version that I know worked all to no avail.
This is the Android Java:
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Camera;
import android.location.Location;
import com.firebase.geofire.GeoFire;
import com.firebase.geofire.GeoLocation;
import com.google.android.gms.location.LocationListener;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApi;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.internal.GoogleApiAvailabilityCache;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
public class DriverMapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap;
GoogleApiClient mGoogleApiClient;
Location driverLastLocation;
LocationRequest driverLocationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_driver_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
Button buttonLogout = findViewById(R.id.buttonLogout);
buttonLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseAuth.getInstance().signOut();
Intent intent = new Intent(DriverMapsActivity.this, MainActivity.class);
startActivity(intent);
finish();
return;
}
});
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
protected synchronized void buildGoogleApiClient(){
mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
driverLastLocation = location;
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("driversClear");
GeoFire geoFire = new GeoFire(ref);
geoFire.setLocation(userID, new GeoLocation(location.getLatitude(), location.getLongitude()));
}
#Override
public void onConnected(#Nullable Bundle bundle) {
driverLocationRequest = new LocationRequest();
driverLocationRequest.setInterval(1000);
driverLocationRequest.setFastestInterval(2000);
driverLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, driverLocationRequest, (com.google.android.gms.location.LocationListener) this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onStop(){
super.onStop();
String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("driversClear");
GeoFire geoFire = new GeoFire(ref);
geoFire.removeLocation(userID);
}
}
I'm new to Android Dev so I'm not sure if it is particularly vital to debugging this kind of issue but here is the layout XML thing
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DriverMapsActivity" >
<Button
android:id="#+id/buttonLogout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout" />
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
and I'm not sure if I should share the AndroidManifest but I feel like it is important
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<activity android:name=".CustomerMapsActivity" >
</activity>
<activity android:name=".TestClass" />
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_maps_key" />
<activity
android:name=".DriverMapsActivity"
android:label="#string/title_activity_driver_maps" />
<activity android:name=".DriverLogin" />
<activity android:name=".DriverRegistration" />
<activity android:name=".CustomerLogin" />
<activity android:name=".CustomerRegistration" />
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Also if anyone can tell me why the built in debugger isn't notifying me of this error that would be appreciated (as in do I need to toggle a setting or install something extra?)
Thanks
Can you check the 'Run' tab for error, instead of Logcat. If the app crashes as soon as it starts, logs may be present in 'Run' tab.
I am implementing a Google Map into my application which includes setting the current location of the user. I have added the ACCESS_FINE_LOCATION into the application manifest and my gradle file uses a minimum SDK of 23. The device emulator that I am running is also 23.
My understanding is that with version 23 I do not need to ask for permission, as that is handled with the app installation or upgrade.
The application is crashing saying that I need to allow location access (see attached logcat entry). It is on the statement (line 64) on the attached MapsActivity.java
mMap.setMyLocationEnabled(true);
MapAcitivity.java
package com.grgapps.checkingin;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity implements GoogleMap.OnMyLocationButtonClickListener,
GoogleMap.OnMyLocationClickListener, ActivityCompat.OnRequestPermissionsResultCallback ,
OnMapReadyCallback {
private GoogleMap mMap;
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
private MapView mMapView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY); }
//mMapView = (MapView) findViewById(R.id.map);
//mMapView.onCreate(mapViewBundle);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Gordon and move the camera
LatLng gordon = new LatLng(46.218972, -91.910414);
mMap.addMarker(new MarkerOptions().position(gordon).title("Home"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(gordon));
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//UiSettings.setZoomControlsEnabled(true);
mMap.setMyLocationEnabled(true);
mMap.setOnMyLocationButtonClickListener(this::onMyLocationButtonClick);
mMap.setOnMyLocationClickListener(this::onMyLocationClick);
}
public void onMyLocationClick(#NonNull Location location) {
Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG).show();
}
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 onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
}
mMapView.onSaveInstanceState(mapViewBundle);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode != 0) {
return;
}
if (PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION)) {
// Enable the my location layer if the permission has been granted.
enableMyLocation();
} else {
// Permission was denied. Display an error message
// ...
}
}
private void enableMyLocation() {
// [START maps_check_location_permission]
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mMap != null) {
mMap.setMyLocationEnabled(true);
}
} else {
// Permission to access the location is missing. Show rationale and request permission
PermissionUtils.requestPermission(this, 0,
Manifest.permission.ACCESS_FINE_LOCATION, true);
}
}
/*
#Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
#Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
#Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
#Override
protected void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
*/
}
Application Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.grgapps.checkingin">
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyAPQCMFgUWQp4RSDDO0EjpCPuDLhTUjcfg" />
<activity
android:name=".MapsActivity"
android:label="#string/title_activity_maps">
android:label="#string/title_activity_maps_and_directions"
android:theme="#style/AppTheme.NoActionBar"
</activity>
<!--
Set custom default icon. This is used when no icon is set for incoming notification messages.
-->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher" />
<!--
Set color used with incoming notification messages. This is used when no color is set for the incoming
notification message.
-->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel_id" />
<activity
android:name=".SettingsActivity"
android:label="#string/title_activity_settings" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
<activity
android:name=".Emergency"
android:label="#string/title_activity_emergency"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Contacts"
android:label="#string/title_activity_contacts"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".PeepsLocator"
android:label="#string/title_activity_peeps_locator"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".RequestCheckIn"
android:label="#string/title_activity_request_check_in"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".ViewCheckIns"
android:label="#string/title_activity_view_check_ins"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".RoadTrip"
android:label="#string/title_activity_road_trip"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Commute"
android:label="#string/title_activity_commute"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Settings"
android:label="#string/title_activity_settings"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".CheckIn"
android:label="#string/title_activity_check_in"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".CheckInNew"
android:label="CheckInNew"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_SERVICE" />
</intent-filter>
</service>
</application>
</manifest>
Logcat entry
03-18 06:27:54.442 5342-5342/com.grgapps.checkingin E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.grgapps.checkingin, PID: 5342
java.lang.SecurityException: my location requires permission ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION
at com.google.maps.api.android.lib6.impl.bf.c(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):569)
at com.google.android.gms.maps.internal.l.a(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):361)
at fw.onTransact(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):4)
at android.os.Binder.transact(Binder.java:387)
at com.google.android.gms.internal.maps.zza.zzb(Unknown Source)
at com.google.android.gms.maps.internal.zzg.setMyLocationEnabled(Unknown Source)
at com.google.android.gms.maps.GoogleMap.setMyLocationEnabled(Unknown Source)
at com.grgapps.checkingin.MapsActivity.onMapReady(MapsActivity.java:64)
at com.google.android.gms.maps.zzak.zza(Unknown Source)
at com.google.android.gms.maps.internal.zzaq.dispatchTransaction(Unknown Source)
at com.google.android.gms.internal.maps.zzb.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:387)
at fv.b(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):14)
at com.google.android.gms.maps.internal.bd.a(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):4)
at com.google.maps.api.android.lib6.impl.bk.run(:com.google.android.gms.dynamite_mapsdynamite#16089052#16.0.89 (040700-239467275):4)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
As per Android Document:
Android 6.0 Marshmallow introduced a new permissions model that lets apps request permissions from the user at runtime, rather than prior to installation. Apps that support the new model request permissions when the app actually requires the services or data protected by the services. While this doesn't (necessarily) change overall app behavior, it does create a few changes relevant to the way sensitive user data is handled:
For SDK version 23, you need to ask run time permission to access the device location. For that, please call enableMyLocation() method in onCreate() function
I did everything by following a tutorial, the map gets displayed in the tutorial but it doesn't get displayed in mine even when I did the exact same thing.
MainActivity.Java
package com.example.ankit.mrestro;
import android.app.Dialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final int GPS_ERRORDIALOGUE_REQUEST = 9001;
GoogleMap mMap;
MapView mMapView;
Button bLogout;
EditText etFName, etLName, etAge, etEmail, etUserName;
UserLocalStorage userLocalStorage;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (servicesOK()){
Toast.makeText(this, "Ready to map", Toast.LENGTH_SHORT).show();
setContentView(R.layout.activity_mapview);
mMapView = (MapView) findViewById(R.id.map);
mMapView.onCreate(savedInstanceState);
}
setContentView(R.layout.activity_main);
etFName = (EditText) findViewById(R.id.etFName);
etLName = (EditText) findViewById(R.id.etLName);
etAge = (EditText) findViewById(R.id.etAge);
etEmail = (EditText) findViewById(R.id.etEmail);
etUserName = (EditText) findViewById(R.id.etUserName);
bLogout = (Button) findViewById(R.id.bLogout);
bLogout.setOnClickListener(this);
userLocalStorage = new UserLocalStorage(this);
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
#Override
protected void onStart() {
super.onStart();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
if (authenticate() == true) {
DisplaysUserDetails();
}
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
Action viewAction = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://com.example.ankit.mrestro/http/host/path")
);
AppIndex.AppIndexApi.start(client, viewAction);
}
private boolean authenticate() {
return userLocalStorage.getUserLoggedIn();
}
private void DisplaysUserDetails() {
User user = userLocalStorage.GetLoggedInUser();
etUserName.setText(user.UserName);
etFName.setText(user.FirstName);
etLName.setText(user.LastName);
etAge.setText(user.Age + "");
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bLogout:
userLocalStorage.ClearUserData();
userLocalStorage.SetUserLoggedIn(false);
startActivity(new Intent(this, Login.class));
break;
}
}
public boolean servicesOK() {
int isAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (isAvailable == ConnectionResult.SUCCESS) {
return true;
} else if (GooglePlayServicesUtil.isUserRecoverableError(isAvailable)) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(isAvailable, this, GPS_ERRORDIALOGUE_REQUEST);
dialog.show();
}
else {
Toast.makeText(this, "Can't connect to google play services", Toast.LENGTH_SHORT).show();
}
return false;
}
#Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
#Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
#Override
public void onStop() {
super.onStop();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
Action viewAction2 = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://com.example.ankit.mrestro/http/host/path")
);
AppIndex.AppIndexApi.end(client, viewAction2);
client.disconnect();
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.ankit.mrestro">
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="23"/>
<permission android:name="com.example.ankit.mrestro.permission.MAPS_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsg.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:glEsVersion="0x00020000"
android:required="true"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:replace="android:icon, android:theme, android:label">
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="<<APIKEY>>"/>
<activity
android:name=".Login"
android:label="#string/title_activity_login"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Register"
android:label="#string/title_activity_register"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Main2Activity"
android:label="#string/title_activity_main2"
android:theme="#style/AppTheme.NoActionBar"></activity>
<!-- ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
activity_mapview
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
I've noticed that I've not created a separate button for displaying the map. Could this be the problem? If so, how do I assign a button to Google maps? I know how to create a button and assign an activity to it but how do I do that for Maps? Please help.
Where are you getting your map?
You should implement OnMapReadyCallback in your Activity and then in onCreate do the following:
if (/* play services are OK */) {
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this);
}
And then override an onMapReady call (something like that):
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
UiSettings uiSettings = mGoogleMap.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
if (mCameraPosition != null) {
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
}
addMarkers();
}
You can check out my code:
https://github.com/dmytroKarataiev/EarthquakeSurvival/blob/master/app/src/main/java/com/adkdevelopment/earthquakesurvival/MapviewFragment.java
Also very important: NEVER show anyone your API key. It's against the Google rules and also not safe for you.
I'm having an Android GPS project for my CS class. Right now I'm working through tutorials (using Eclipse with ADT plugin) to have an idea of how to use the Android library, but along the way, I received the Installation error: INSTALL_FAILED_MISSING_SHARED_LIBRARY
I checked on LogCat and it seems the error starts on this line:
03-29 23:05:14.721: E/PackageManager(72): Package virginia.edu.cs2110 requires unavailable shared library android.location; failing!
I have looked up this problem and did all the things that I was able to find. I declared the uses-library field in the manifest file:
<uses-library android:name="android.location" />
<uses-library android:name="com.google.android.maps" />
If anyone is wondering, this is my whole manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="virginia.edu.cs2110"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".TrivialGPS"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<uses-library android:name="android.location" />
<uses-library android:name="com.google.android.maps" />
</application>
</manifest>
I also created an Android emulator with Target Name "Google API (Google Inc.)":
http://i42.tinypic.com/2dj3vd5.jpg
Also, here's the code that I wanted to run:
package virginia.edu.cs2110;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
public class TrivialGPS extends MapActivity {
private MapController mapController;
private MapView mapView;
private LocationManager locationManager;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// create a map view
mapView = new MapView(this, "C7:63:2F:C8:93:8B:E1:83:D6:4F:D3:5B:62:C1:75:90");
mapController = mapView.getController();
mapController.setZoom(22);
setContentView(mapView);
// get a hangle on the location manager
locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
new LocationUpdateHandler());
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
public class LocationUpdateHandler implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
int lat = (int) (loc.getLatitude()*1E6);
int lng = (int) (loc.getLongitude()*1E6);
GeoPoint point = new GeoPoint(lat, lng);
mapController.setCenter(point);
setContentView(mapView);
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
}
Delete <uses-library android:name="android.location" />, as there is no such library.