How to Automatically Fill Addresses in Lifestyle Apps
Tags: location, lifestyle
Published: 2022-04-02 08:40:40

Filling in addresses is a task that users of lifestyle apps and mini programs that provide services such as group buying, takeout, package delivery, housekeeping, logistics, and moving services often have to perform. Generally, this requires users to manually fill in their address information, for example, selecting California, Los Angeles, and Hollywood Blvd in sequence using several drop-down list boxes and then manually entering their names and phone numbers. This process usually takes some time and is prone to input error.

Wouldn't it be handy if there was an automatic way for users to fill in addresses quickly and accurately? With HMS Core Location Kit's fused location and geocoding capabilities, a lifestyle app can automatically pinpoint the current location of a user or obtain the street address of a map location, and fill that information in the address box. Thanks to this, users are freed from the hassle of having to manually enter addresses, as well preventing human error. In this article, I will explain how you can easily integrate this feature into your app and provide you with sample code.

## Demo

![Demo Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nwxag4if42lxe6acykx.gif)

## Development Procedure
### Prepare for the development
1.Sign in to AppGallery Connect and click **My projects**. Find your project, go to **Project settings > Manage APIs**, and toggle on the **Location Kit** switch. Then, click the app for which you need to configure the signing certificate fingerprint, and go to **Project settings > General information**. In the **App information** area, click **Add** next to **SHA-256 certificate fingerprint**, and enter the SHA-256 certificate fingerprint.

2.Go to **Project settings > General information**. In the **App information** area, click **agconnect-services.json** to download the configuration file. Then, copy the configuration file to the app's root directory.

3.Configure the project-level **build.gradle** file.

```
buildscript {
    repositories {
        google()
        jcenter()
        maven { url 'https://developer.huawei.com/repo/' }
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.2'
        classpath 'com.huawei.agconnect:agcp:1.6.0.300'
    }
}

allprojects {
    repositories {
        maven { url 'https://developer.huawei.com/repo/' }
        google()
        jcenter()
        mavenCentral()
    }
}
```
Configure the app-level **build.gradle** file.

```
plugins {
    id 'com.android.application'
    id 'com.huawei.agconnect'
}
```
Add the following build dependency in the **dependencies** block in the app-level **build.gradle** file:

```
implementation 'com.huawei.hms:location:6.3.0.300'
```
## Check permissions
1.Declare the **ACCESS_COARSE_LOCATION** (approximate location permission), **ACCESS_FINE_LOCATION** (precise location permission), and **ACCESS_BACKGROUND_LOCATION** permissions in the **AndroidManifest.xml** file. 

```
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
```
2.Dynamically apply for related location permissions (according to requirements for dangerous permissions in Android 6.0 or later).

```
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
    Log.i(TAG, "android sdk < 28 Q");
    if (ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        String[] strings =
                {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
        ActivityCompat.requestPermissions(this, strings, 1);
    }
} else {
    if (ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(this,
            "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
        String[] strings = {Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                "android.permission.ACCESS_BACKGROUND_LOCATION"};
        ActivityCompat.requestPermissions(this, strings, 2);
    }
}
```
## Obtain the location result
1.Set location parameters, including the location update interval and location type

```
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// Set the location update interval, in milliseconds. 
mLocationRequest.setInterval(5000);
// Set the priority.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
```
2.Call the **getSettingsClient()** method to obtain a **SettingsClient** instance, and call **checkLocationSettings()** to check the device location settings.

```
LocationSettingsRequest locationSettingsRequest = builder.build();
// Before requesting location updates, call checkLocationSettings to check the device location settings.
Task<LocationSettingsResponse> locationSettingsResponseTask =
        mSettingsClient.checkLocationSettings(locationSettingsRequest);
```
After checking that the device location function is enabled, call **requestLocationUpdates()** to request location updates.

```
locationSettingsResponseTask.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
    @Override
    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
        Log.i(TAG, "check location settings success");
        mFusedLocationProviderClient
                .requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
                .addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess");
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(Exception e) {
                        Log.e(TAG, "requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
                    }
                });
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(Exception e) {
        Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
        int statusCode = 0;
        if (e instanceof ApiException) {
            statusCode = ((ApiException) e).getStatusCode();
        }
        switch (statusCode) {
            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                try {
                    // When startResolutionForResult is called, a popup will 
                    // appear, asking the user to grant relevant permissions.
                    if (e instanceof ResolvableApiException) {
                        ResolvableApiException rae = (ResolvableApiException) e;
                        rae.startResolutionForResult(MainActivity.this, 0);
                    }
                } catch (IntentSender.SendIntentException sie) {
                    Log.e(TAG, "PendingIntent unable to execute request.");
                }
                break;
            default:
                break;
        }
    }
});
```
## Obtain the address of the current location through reverse geocoding

After obtaining the longitude and latitude of a location, pass them to the geocoding service (**GeocoderService**) to obtain a geocoding request object. Then, call the **getFromLocation** method and set request (**GetFromLocationRequest**) parameters to obtain the address of the location.

```
if (null == mLocationCallback) {
    mLocationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult != null) {
                List<Location> locations = locationResult.getLocations();
                if (!locations.isEmpty()) {
                    ExecutorUtil.getInstance().execute(new Runnable() {
                        @Override
                        public void run() {
                            Locale locale = new Locale("zh", "CN");
                            GeocoderService geocoderService = LocationServices.getGeocoderService(MainActivity.this, locale);
                            GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(locations.get(0).getLatitude(), locations.get(0).getLongitude(), 1);
                            geocoderService.getFromLocation(getFromLocationRequest)
                                    .addOnSuccessListener(new OnSuccessListener<List<HWLocation>>() {
                                        @Override
                                        public void onSuccess(List<HWLocation> hwLocation) {
                                            printGeocoderResult(hwLocation);
                                        }
                                    })
                                    .addOnFailureListener(new OnFailureListener() {
                                        @Override
                                        public void onFailure(Exception e) {
                                            Log.i(TAG, e.getMessage());
                                        }
                                    });
                        }
                    });
                }
            }
        }
        @Override
        public void onLocationAvailability(LocationAvailability locationAvailability) {
            if (locationAvailability != null) {
                boolean flag = locationAvailability.isLocationAvailable();
                Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
            }
        }
    };
}
```
Finally, display the obtained address on the screen to complete the implementation.

## References
Location Kit [official website](https://developer.huawei.com/consumer/en/hms/huawei-locationkit/?ha_source=hms1)
Location Kit [Development Guide](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050706106?ha_source=hms1)
[Reddit](https://www.reddit.com/r/HMSCore/) to join developer discussions
[GitHub](https://github.com/HMS-Core) to download the sample code
[Stack Overflow](https://stackoverflow.com/questions/tagged/huawei-mobile-services?tab=Votes) to solve integration problems