Search code examples
androidhere-api

Here Maps Android SDK call to PositioningManager start method returns false


I've read this question and tried its answer and it doesn't work for me.

I made a very simple test application, here's the manifest:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="22"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<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"
    tools:ignore="GoogleAppIndexingWarning">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.here.android.maps.appid"
        android:value="itkC4uIay69MXXXXXXXX" />
    <meta-data
        android:name="com.here.android.maps.apptoken"
        android:value="NdT8laoCmRysyhXXXXXXXX" />

    <service
        android:enabled="true"
        android:exported="false"
        android:name="com.here.services.internal.LocationService"
        android:process=":remote">
    </service>

</application>

I should make clear that I added in the stuff, but the line

android:name="com.here.services.internal.LocationService"

Shows up in red from the word "services" onwards in Android Studio (although all compiles, I'm assuming there is something wrong)

Here's my MainActivity

package com.company.Application;

import android.Manifest;
import android.content.pm.PackageManager;
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.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.here.android.mpa.common.GeoCoordinate;
import com.here.android.mpa.common.GeoPosition;
import com.here.android.mpa.common.PositioningManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    private static final String[] REQUIRED_SDK_PERMISSIONS = new String[] {
            Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE };

    // permissions request code
    private final static int REQUEST_CODE_ASK_PERMISSIONS = 9893;

    private Timer tickMinTimer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkPermissions();
    }

    private void setUpPositioning() {
        PositioningManager pm = PositioningManager.getInstance();
        PositioningManager.LocationStatus  ls = pm.getLocationStatus(PositioningManager.LocationMethod.GPS_NETWORK);
        Log.i("Position", "Setting up positioning");
        if (ls ==  PositioningManager.LocationStatus.AVAILABLE) {
            Log.i("Position", "Positioning is available");
        } else {
            Log.w("Position", "Positioning not available right now: " + ls.toString());
        }
        boolean ret = pm.start(PositioningManager.LocationMethod.GPS_NETWORK);
        Log.i("Position", "Positioning start returns " + ret);
        timerTickEveryMinute();
    }

    private void timerTickEveryMinute() {
        tickMinTimer = new Timer();
        tickMinTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                // going to try to get the location here - if not once a minute then once every x minutes
                GeoPosition pos = PositioningManager.getInstance().getPosition();
                if (pos == null) {
                    Log.w("Position", "GeoPosition is Null");
                } else {
                    GeoCoordinate coord = pos.getCoordinate();
                    Log.i("Position", "Location: Latitude = " + coord.getLatitude() + ", Longitude = " + coord.getLongitude());
                    Log.i("Position", "Accuracy = " + pos.getLatitudeAccuracy() + ", " + pos.getLongitudeAccuracy());
                }
            }
        }, 5000, 1000*60);
    }

    // check for permissions
    /**
     * Checks the dynamically controlled permissions and requests missing permissions from end user.
     */
    protected void checkPermissions() {
        final List<String> missingPermissions = new ArrayList<String>();
        // check all required dynamic permissions
        for (final String permission : REQUIRED_SDK_PERMISSIONS) {
            final int result = ContextCompat.checkSelfPermission(this, permission);
            if (result != PackageManager.PERMISSION_GRANTED) {
                missingPermissions.add(permission);
            }
        }
        if (!missingPermissions.isEmpty()) {
            // request all missing permissions
            final String[] permissions = missingPermissions
                    .toArray(new String[missingPermissions.size()]);
            ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_ASK_PERMISSIONS);
        } else {
            final int[] grantResults = new int[REQUIRED_SDK_PERMISSIONS.length];
            Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
            onRequestPermissionsResult(REQUEST_CODE_ASK_PERMISSIONS, REQUIRED_SDK_PERMISSIONS,
                    grantResults);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_PERMISSIONS:
                for (int index = permissions.length - 1; index >= 0; --index) {
                    if (grantResults[index] != PackageManager.PERMISSION_GRANTED) {
                        // exit the app if one permission is not granted
                        Toast.makeText(this, "Required permission '" + permissions[index]
                                + "' not granted, exiting", Toast.LENGTH_LONG).show();
                        finish();
                        return;
                    }
                }
                final List<String> missingPermissions = new ArrayList<String>();

                for (final String permission : REQUIRED_SDK_PERMISSIONS) {
                    final int result = ContextCompat.checkSelfPermission(this, permission);
                    if (result != PackageManager.PERMISSION_GRANTED) {
                        missingPermissions.add(permission);
                    }
                }
                if (missingPermissions.isEmpty()) {
                    // all permissions were granted
                    setUpPositioning();
                }
                break;
        }
    }

}

So, pm.start() always returns false and of course the GeoPosition is always null. All permissions have been granted, and all GPS etc is turned on on the phone.

Perhaps it's something simple, but can anyone see what is missing? - all I want is to make my app check the position once a minute. Does this code not work with the freemium model?


Solution

  • On advice from @HERE Developer Support, I have got this example working = the code is changed as follows:

    private void setUpPositioning() {
        // new lines from HERE
        MapEngine.getInstance().init(this, new OnEngineInitListener() {
            @Override
            public void onEngineInitializationCompleted(Error error) {
                if (error == Error.NONE) {
                    Log.i("Position", "correctly started map engine");
                } else {
                    Log.i("Position", "Problem setting up map engine: " + error);
                }
            }
        });
        //end of lines from HERE
        PositioningManager pm = PositioningManager.getInstance();
        PositioningManager.LocationStatus  ls = pm.getLocationStatus(PositioningManager.LocationMethod.GPS_NETWORK);
        Log.i("Position", "Setting up positioning");
        if (ls ==  PositioningManager.LocationStatus.AVAILABLE) {
            Log.i("Position", "Positioning is available");
        } else {
            Log.w("Position", "Positioning not available right now: " + ls.toString());
        }
        boolean ret = pm.start(PositioningManager.LocationMethod.GPS_NETWORK);
        Log.i("Position", "Positioning start returns " + ret);
        timerTickEveryMinute();
    }
    

    Now I receive Logs like this:

    2019-01-27 12:02:51.716 1790-1790/com.company.app I/Position: Setting up positioning
    2019-01-27 12:02:51.716 1790-1790/com.company.app W/Position: Positioning not available right now: TEMPORARILY_UNAVAILABLE
    2019-01-27 12:02:51.745 1790-1790/com.company.app I/Position: Positioning start returns true
    2019-01-27 12:02:51.760 1790-1790/com.company.app I/Position: Problem setting up map engine: MISSING_PERMISSION
    2019-01-27 12:02:56.749 1790-2674/com.company.app I/Position: Location: Latitude = 31.8051461, Longitude = 35.092536
    2019-01-27 12:02:56.750 1790-2674/com.company.app I/Position: Accuracy = 19.71, 19.71
    

    I'm not sure what permission I'm missing, but it doesn't seem to matter since the code now works... unfortunately, it is not working in my more complex app :-( . The more complex app is mentioned here