Tips for Developing a Standing up Reminder - Huawei Developers

Check this out: Are you bending like this at your desk?
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Well, I am, and if you're like me, maybe we should get up and move around for a little while.
Joking aside, I know COVID-19 forced many of you to work from home. As a result, many of us have started to live a sedentary lifestyle. After reading a bunch of posts shared by my family describing how harmful sitting too long is, I decided to change this habit by developing a function that reminds me to move around, like this:
Development Overview​To develop such a function, I turned to the mobile context-awareness capabilities from HMS Core Awareness Kit. I used a time awareness capability and behavior awareness capability to create a time barrier and behavior detection barrier respectively, as well as a combination of the barriers.
More specifically, these included:
Time awareness capability: TimeBarrier.duringTimePeriod(long startTimeStamp, long endSecondsMillis); is used to define a time barrier. If the current time is within the range from startTimeStamp to endSecondsMillis, the barrier status is true. Otherwise, it is false.
Behavior awareness capability: BehaviorBarrier.keeping(BehaviorBarrier.BEHAVIOR_STILL); is used to define a behavior detection barrier. If the status of a user is still, the barrier status is true; if the status of a user changes — from being stationary to moving, for example — then the barrier will be triggered, and its status will be false.
Barrier combination: Use and to combine the above two barriers into AwarenessBarrier.and(keepStillBarrier, timePeriodBarrier). When the current time of a user is within the specified time segment, and their status is still, the barrier status will be true. Otherwise, it is false.
It's quite straightforward, right? Let's take a deeper look into how the function is developed.
Development Procedure​Making Preparations​1. Create an Android Studio project. Put agconnect-services.json and the app signing certificate to the app's root directory. If you need to know where to obtain the two files, you can check the References section to get more information.
2. Configure a Maven repository address and import a plugin.
Code:
buildscript {
repositories {
maven { url 'http://szxy1.artifactory.cd-cloud-artifact.tools.huawei.com/artifactory/sz-maven-public/' }
maven { url 'http://dgg.maven.repo.cmc.tools.huawei.com/artifactory/Product-CloudTest-snapshot/' }
maven { url 'http://dgg.maven.repo.cmc.tools.huawei.com/artifactory/Product-cloudserviceSDK-release/' }
maven { url 'http://artifactory.cde.huawei.com/artifactory/Product-Binary-Release/' }
maven { url 'http://language.cloudartifact.dgg.dragon.tools.huawei.com/artifactory/product_maven/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.3'
classpath 'com.huawei.agconnect:agcp:1.0.0.300'
}
}
allprojects {
repositories {
maven { url 'http://szxy1.artifactory.cd-cloud-artifact.tools.huawei.com/artifactory/sz-maven-public/' }
maven { url 'http://dgg.maven.repo.cmc.tools.huawei.com/artifactory/Product-CloudTest-snapshot/' }
maven { url 'http://dgg.maven.repo.cmc.tools.huawei.com/artifactory/Product-cloudserviceSDK-release/' }
maven { url 'http://artifactory.cde.huawei.com/artifactory/Product-Binary-Release/' }
maven { url 'http://language.cloudartifact.dgg.dragon.tools.huawei.com/artifactory/product_maven/' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3. Open the app-level build.gradle file, add the plugin, configure the signing certificate parameters, and add necessary building dependencies.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
android {
compileSdkVersion 31
buildToolsVersion "31.0.0"
defaultConfig {
applicationId "com.huawei.smartlifeassistant"
minSdkVersion 26
targetSdkVersion 31
versionCode 2
versionName "2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
storeFile file('Awareness.jks')
keyAlias 'testKey'
keyPassword 'lhw123456'
storePassword 'lhw123456'
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
debuggable true
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.huawei.agconnect:agconnect-core:1.5.2.300'
implementation 'com.huawei.hms:awareness:3.1.0.301'
}
4. Make sure that the app package names in agconnect-services.json and the project are the same. Then, compile the project.
Requesting Dynamic Permissions​
Code:
private static final int PERMISSION_REQUEST_CODE = 940;
private final String[] mPermissionsOnHigherVersion = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION,
Manifest.permission.ACTIVITY_RECOGNITION,
Manifest.permission.BLUETOOTH_CONNECT};
private final String[] mPermissionsOnLowerVersion = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
"com.huawei.hms.permission.ACTIVITY_RECOGNITION"};
private void checkAndRequestPermissions() {
List<String> permissionsDoNotGrant = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
for (String permission : mPermissionsOnHigherVersion) {
if (ActivityCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
permissionsDoNotGrant.add(permission);
}
}
} else {
for (String permission : mPermissionsOnLowerVersion) {
if (ActivityCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
permissionsDoNotGrant.add(permission);
}
}
}
if (permissionsDoNotGrant.size() > 0) {
ActivityCompat.requestPermissions(this,
permissionsDoNotGrant.toArray(new String[0]), PERMISSION_REQUEST_CODE);
}
}
Check whether the dynamic permissions are granted in onCreate of the activity.
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sedentary_reminder);
setTitle(getString(R.string.life_assistant));
// Check whether the dynamic permissions are granted.
checkAndRequestPermissions();
//...
}
private void checkAndRequestPermissions() {
List<String> permissionsDoNotGrant = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
for (String permission : mPermissionsOnHigherVersion) {
if (ActivityCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
permissionsDoNotGrant.add(permission);
}
}
} else {
for (String permission : mPermissionsOnLowerVersion) {
if (ActivityCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
permissionsDoNotGrant.add(permission);
}
}
}
if (permissionsDoNotGrant.size() > 0) {
ActivityCompat.requestPermissions(this,
permissionsDoNotGrant.toArray(new String[0]), PERMISSION_REQUEST_CODE);
}
}
Using the Broadcast Message to Create PendingIntent Which Is Triggered When the Barrier Status Changes, and Registering a Broadcast Receiver​
Code:
final String barrierReceiverAction = getApplication().getPackageName() + "COMBINED_BARRIER_RECEIVER_ACTION";
Intent intent = new Intent(barrierReceiverAction);
// Also, we can use getActivity() or getService() to create PendingIntent.
// This depends on what action you want to be triggered when the barrier status changes.
mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
| PendingIntent.FLAG_MUTABLE);
// Register a broadcast receiver to receive the broadcast when the barrier status changes.
mBarrierReceiver = new CombinedBarrierReceiver();
registerReceiver(mBarrierReceiver, new IntentFilter(barrierReceiverAction));
final class CombinedBarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
int barrierPresentStatus = barrierStatus.getPresentStatus();
if (label == null) {
return;
}
switch (label) {
case COMBINED_BEHAVIOR_TIME_BARRIER_LABEL:
if (barrierPresentStatus == BarrierStatus.FALSE) {
if (System.currentTimeMillis() - lastTime >= tenSecondsMillis) {
alert.show();
}
updateTimeAwarenessBarrier();
}
break;
default:
break;
}
}
}
Registering or Deleting the Barrier Combination​Use a switch on the UI to register or delete the barrier combination.
Code:
automaticAdjustSwitch = findViewById(R.id.sedentary_reminder_switch);
automaticAdjustSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
startAutomaticAdust(isChecked);
}
});
private void startAutomaticAdust(boolean isChecked) {
if (isChecked) {
addBarriers();
} else {
deleteBarriers();
}
}
private void addBarriers() {
keepStillBarrier = BehaviorBarrier.keeping(BehaviorBarrier.BEHAVIOR_STILL);
updateTimeAwarenessBarrier();
}
@NonNull
private void updateTimeAwarenessBarrier() {
long currentTimeStamp = System.currentTimeMillis();
lastTime = currentTimeStamp;
AwarenessBarrier timePeriodBarrier = TimeBarrier.duringTimePeriod(currentTimeStamp, currentTimeStamp + tenSecondsMillis);
AwarenessBarrier combinedTimeBluetoothBarrier = AwarenessBarrier.and(keepStillBarrier, timePeriodBarrier);
Utils.addBarrier(this, COMBINED_BEHAVIOR_TIME_BARRIER_LABEL,
combinedTimeBluetoothBarrier, mPendingIntent);
}
private void deleteBarriers() {
Utils.deleteBarrier(this, mPendingIntent);
}
Showing the Reminding Information​Use an AlertDialog to remind a user.
Code:
// Initialize Builder.
builder = new AlertDialog.Builder(this);
// Load and configure the custom view.
final LayoutInflater inflater = getLayoutInflater();
View view_custom = inflater.inflate(R.layout.view_dialog_custom, null, false);
builder.setView(view_custom);
builder.setCancelable(false);
alert = builder.create();
view_custom.findViewById(R.id.i_kown).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
alert.dismiss();
}
});
final class CombinedBarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
int barrierPresentStatus = barrierStatus.getPresentStatus();
if (label == null) {
return;
}
switch (label) {
case COMBINED_BEHAVIOR_TIME_BARRIER_LABEL:
if (barrierPresentStatus == BarrierStatus.FALSE) {
if (System.currentTimeMillis() - lastTime >= tenSecondsMillis) {
alert.show();
}
updateTimeAwarenessBarrier();
}
break;
default:
break;
}
}
}
And just like that, the standing up reminder function is created.
In fact, I've got some more ideas for using mobile context-awareness capabilities, such as developing a sleep reminder using the ambient light awareness capability and the time awareness capability. This reminder can notify users when it is bedtime based on a specified time and when the ambient brightness is lower than a specified value.
A schedule reminder also sounds like a good idea, which uses the time awareness capability to tell a user their schedule for a day at a specified time.
These are just some of my ideas. If you've got some other interesting inspirations for using the context-awareness capabilities, please share them in the comments section below and see how our ideas overlap.
References​>>The dangers of sitting
>>What are the risks of sitting too much?[z1]
>>Obtaining agconnect-services.json
>>Obtaining a signing certificate

Related

Setup Map on an Android Application in smart way

More articles like this, you can visit HUAWEI Developer Forum.​
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
Now days, most of the application integrate an Maps. This article I will give you the process on how to do. Millions of users look up directions, plan their commutes, catch a ride.as well as touch on the many things available through maps to enhance the user experience in mobile apps.
Let’s Start how to Integrate Map:
Step1: create a new project in Android studio.
Step 2: Configure your app into AGC.
Step 3: Enable required Api & add SHA-256.
Step 4: Download the agconnect-services.json from AGC. Paste into app directory.
Step 5: Add the below dependency in app.gradle file.
Code:
implementation 'com.huawei.hms:maps:4.0.0.301'
Step 6: Add the below dependency in root.gradle file
Code:
maven { url 'http://developer.huawei.com/repo/' }
Step 7: Add appId & permissions in AndoridManifest.xml file
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<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" />
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=*******" />
Step 8: Sync your Project
Let’s Discuss functionality:
1.OnMapReady()
2.OnMapClick()
3.OnMarkerClick()
4.Create Circle
5.Create Custom Marker
1. OnMapReady: This Callback interface for when map is ready to be used
Code:
@Override
public void onMapReady(HuaweiMap map) {
mHuaweiMap = map;
enableUiSettings();
mHuaweiMap.setMaxZoomPreference(15);
mHuaweiMap.setMinZoomPreference(2);
}
2. OnMapClick : This callback interface when the user makes tap on the map.
Code:
@Override
public void onMapClick(LatLng latLng) {
try {
createMarker(latLng);
} catch (IOException e) {
e.printStackTrace();
}
}
3. OnMarkerClick : This callback interface when a marker is clicked
Code:
@Override
public boolean onMarkerClick(Marker marker) {
marker.showInfoWindow();
return true;
}
4. How to create circle on map:
Code:
private void addCircleToCurrentLocation() {
mHuaweiMap.addCircle(new CircleOptions()
.center(new LatLng(12.9716, 77.5946))
.radius(1000)
.strokeWidth(10)
.strokeColor(Color.GREEN)
.fillColor(Color.argb(128, 255, 0, 0))
.clickable(true));
}
5. How to create marker:
Code:
private void createMarker(LatLng latLng) throws IOException {
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.snippet("Address : " + featchAddress(latLng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_location));
mHuaweiMap.addMarker(markerOptions);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng) // Sets the center of the map to location user
.zoom(20) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(40) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mHuaweiMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mHuaweiMap.setOnMarkerClickListener(this);
}
In this article I covered few basics callbacks. below is the final code
Code:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, HuaweiMap.OnMapClickListener, HuaweiMap.OnMarkerClickListener {
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
private static final int REQUEST_CODE = 100;
private static final LatLng LAT_LNG = new LatLng(12.9716, 77.5946);
private HuaweiMap mHuaweiMap;
private MapView mMapView;
private Button btnCustom;
private static final String[] RUNTIME_PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.INTERNET};
private Marker marker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCustom = findViewById(R.id.btn_custom);
if (!hasPermissions(this, RUNTIME_PERMISSIONS)) {
ActivityCompat.requestPermissions(this, RUNTIME_PERMISSIONS, REQUEST_CODE);
}
mMapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
init(mapViewBundle);
btnCustom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mHuaweiMap.setOnMapClickListener(MainActivity.this);
}
});
}
private void init(Bundle mapViewBundle) {
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
@Override
public void onMapReady(HuaweiMap map) {
mHuaweiMap = map;
enableUiSettings();
mHuaweiMap.setMaxZoomPreference(15);
mHuaweiMap.setMinZoomPreference(2);
addCircleToCurrentLocation();
}
/*
Enable Ui Settings
*/
private void enableUiSettings() {
mHuaweiMap.setMyLocationEnabled(true);
mHuaweiMap.getUiSettings().setMyLocationButtonEnabled(true);
mHuaweiMap.getUiSettings().setCompassEnabled(true);
mHuaweiMap.getUiSettings().setZoomControlsEnabled(true);
mHuaweiMap.getUiSettings().setMyLocationButtonEnabled(true);
}
/*
Create Circle to current location
*/
private void addCircleToCurrentLocation() {
mHuaweiMap.addCircle(new CircleOptions()
.center(new LatLng(12.9716, 77.5946))
.radius(1000)
.strokeWidth(10)
.strokeColor(Color.GREEN)
.fillColor(Color.argb(128, 255, 0, 0))
.clickable(true));
}
/*
Create Marker when you click on map
*/
private void createMarker(LatLng latLng) throws IOException {
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.snippet("Address : " + featchAddress(latLng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_location));
mHuaweiMap.addMarker(markerOptions);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng) // Sets the center of the map to location user
.zoom(20) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(40) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mHuaweiMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mHuaweiMap.setOnMarkerClickListener(this);
}
/*
Convert from latlong to Address
*/
private String featchAddress(LatLng latLng) throws IOException {
Geocoder geocoder = new Geocoder(this, Locale.ENGLISH);
List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.latitude, 1);
Toast.makeText(this, addresses.get(0).getLocality() + ", "
+ addresses.get(0).getAdminArea() + ", "
+ addresses.get(0).getCountryName(), Toast.LENGTH_SHORT).show();
return addresses.get(0).getLocality() + ", "
+ addresses.get(0).getAdminArea() + ", "
+ addresses.get(0).getCountryName();
}
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
@Override
public void onMapClick(LatLng latLng) {
try {
createMarker(latLng);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean onMarkerClick(Marker marker) {
marker.showInfoWindow();
return true;
}
Output:
Conclusion:
In this article you’ve learned how to create custom markers, how callbacks will work, as well as new ways for users to interact with the map.
https://developer.huawei.com/consumer/en/doc/development/HMS-References/hms-map-cameraupdate
Reference:

HMS Ads Kit Integration into Solar2D (Corona) Project

More information like this, you can visit HUAWEI Developer Forum​
In this article, I will mention about HMS Ads Kit Integration into Solar2D (Corona) project.
Corona provides a handy template to start. Copy \Native\Project Template\App from your Corona install directory and paste it somewhere writable. On Windows, Corona would usually be installed to \Program Files (x86)\Corona Labs\Corona.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
And rename App to your project name.
The contents of App folder are as follows. In App folder, we need only Android and Corona folders.
In Corona folder, there is a sample project. When you open main.lua file, you can see how to call methods from android side. For example : library.init()
You can delete all of files in Corona folder and you can put our own codes. But you need to import our android library into our own main.lua folder to call method from android.
Code:
local library = require "plugin.library"
Open android folder with Android studio.
Let’s make the configuration settings;
1- Add maven repository into build.gradle.
2- Change coronaMinSdkVersion to 19.
3- Add HMS Ads Kit SDK and change minSdkVersion to 19.
implementation ‘com.huawei.hms:ads-lite:13.4.32.300’
And we will use LuaLoader class and write code into LuaLoader class in plugin.
Now plugin side is ready to use HMS Ads Kit. In android project, we need to create wrapper for Ads Kit methods.
If you don`t have enough information about HMS Ads kit, i recommend to read this documentation
https://developer.huawei.com/consumer/en/hms/huawei-adskit
In this article i will show banner ad integration. So let’s start.
Before we begin, let’s define these variables in LuaLoader.class.
Code:
public AdParam adParam;
private BannerView bannerView;
private FrameLayout layout;
public String bannarAdId = "testw6vs28auh3";
For banner ad, we need to create a wrapper. (e.g BannerWrapper). And we need to add into invoke method.
Code:
@Override
public int invoke(LuaState L) {
// Register this plugin into Lua with the following functions.
NamedJavaFunction[] luaFunctions = new NamedJavaFunction[]{
new InitWrapper(),
new ShowWrapper(),
new BannerWrapper(),
// new InterstitialAdWrapper(),
};
String libName = L.toString(1);
L.register(libName, luaFunctions);
// Returning 1 indicates that the Lua require() function will return the above Lua library.
return 1;
}
And then let`s create BannerWrapper class.
Code:
@SuppressWarnings("unused")
private class BannerWrapper implements NamedJavaFunction {
@Override
public String getName() {
return "showBanner";
}
@Override
public int invoke(LuaState L) {
return showBanner(L);
}
}
Invoke method which in BannerWrapper class, returns a method (e.g showBanner()).
Let`s create showBanner() method.
Code:
@SuppressWarnings({"WeakerAccess"})
public int showBanner(LuaState L) {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return 0;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return;
}
HwAds.init(CoronaEnvironment.getApplicationContext());
adParam = new AdParam.Builder().build();
if (layout == null) {
layout = new FrameLayout(activity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
activity.getOverlayView().addView(layout, layoutParams);
}
if (bannerView == null) {
bannerView = new BannerView(CoronaEnvironment.getCoronaActivity());
bannerView.setAdId(bannarAdId);
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_320_50);
bannerView.loadAd(adParam);
layout.addView(bannerView);
}
}
});
return 0;
}
In this method firstly, we create an activity with using CoronaEnvironemnt.getCoronaAcitivty() method.
We call HyAds.init(context) method to initialize the HUAWEI Ads SDK and we initialize Param.Builder() to construct an ad request builder.
And then if layout is null, we initialize layout.
Lastly, If bannerView is null, we should initialize it. And we load this ads with loadAd() method, add this bannerView into layout.
That’s all.
When you call the showBanner() method on main.lua file, you see the banner ad.
Code:
local library = require "plugin.library"
library.showBanner()
When we run the android project, you should see the banner ads.
Let`s define AdListener to monitor the status of the ad.
Code:
private AdListener adListener = new AdListener() {
@Override
public void onAdLoaded() {
dispatchEvent("++Ad Loaded", false, "Loaded", "", "Banner");
}
@Override
public void onAdFailed(int errorCode) {
dispatchEvent(errorCode + "", true, "Loaded", "", "Banner");
}
@Override
public void onAdOpened() {
dispatchEvent("", false, "Openeed", "", "Banner");
}
@Override
public void onAdClicked() {
dispatchEvent("", false, "Clicked", "", "Banner");
}
@Override
public void onAdLeave() {
dispatchEvent("", false, "Leaved", "", "Banner");
}
@Override
public void onAdClosed() {
dispatchEvent("", false, "Closed", "", "Banner");
}
};
We use the dispatchEvent() method to send an information to the lua side. And the dispatchEvent() method takes only 1 parameter by default. I changed it to send more detailed information. I added some more parameters as follow.
Code:
public void dispatchEvent(final String data, final Boolean isError, final String phase, final String response, final String type) {
CoronaEnvironment.getCoronaActivity().getRuntimeTaskDispatcher().send(new CoronaRuntimeTask() {
@Override
public void executeUsing(CoronaRuntime runtime) {
LuaState L = runtime.getLuaState();
CoronaLua.newEvent(L, EVENT_NAME);
L.pushBoolean(isError);
L.setField(-2, "isError");
L.pushString(phase);
L.setField(-2, "phase");
L.pushString(response);
L.setField(-2, "response");
L.pushString(type);
L.setField(-2, "type");
L.pushString(data);
L.setField(-2, "message");
L.pushString("amazonAds");
L.setField(-2, "provider");
try {
CoronaLua.dispatchEvent(L, fListener, 0);
} catch (Exception ignored) {
}
}
});
}
And then we need to set listener into bannerView in showBanner method.
Code:
@SuppressWarnings({"WeakerAccess"})
public int showBanner(LuaState L) {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return 0;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return;
}
HwAds.init(CoronaEnvironment.getApplicationContext());
adParam = new AdParam.Builder().build();
if (layout == null) {
layout = new FrameLayout(activity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
activity.getOverlayView().addView(layout, layoutParams);
}
if (bannerView == null) {
bannerView = new BannerView(CoronaEnvironment.getCoronaActivity());
bannerView.setAdId(bannarAdId);
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_320_50);
bannerView.setAdListener(adListener);
bannerView.loadAd(adParam);
layout.addView(bannerView);
}
}
});
return 0;
}
Now, on android side everything is ready. We need to update lua part. We should import json lib because we send more than one value via dispatchEvent(). And in listener method, we use json.prettify(event) method.
Code:
local library = require "plugin.library"
local json = require("json")
local function listener( event )
print( "Received event from Library plugin " , json.prettify(event))
end
library.init( listener )
library.showBanner()
Let’s run it and see the logs.
As you can see, we integrated the HMS Ads Kit into the corona project and we can see the status of the advertisement.
You can add all the features of the HMS ads kit to your project in this way.
You can find the sample project from github. And Interstitial ad has been added in this sample project.
https://github.com/kayahanbaskeser/hms-ads-kit-integration-into-corona-project

Geofence Notification with Push Kit

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
Hello everyone, In this article, I will talk about how we can use together Geofence and Push Kit. When the device enters a set location, we will send a notification to the user using Push Kit.
Geofence : It is an important feature in the Location Kit. Geofence is actually used to draw a geographic virtual boundary.
Push Kit : Push kit is essentially a messaging service. There are two different message types. These are notification and data messages. We will use the notification messages in this article.
1- Huawei Core Integration
To use Geofence and Push kit services, you must first integrate the necessary kits into your project. You can use the document in the link to easily integrate the Location and Push kit into your project.
2- Add Permissions
After the HMS Core integration is finished, we need to add permissions to the AndroidManifest.xml file in order to access the user’s location and internet.
XML:
<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_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
3- Developing the Push Kit Part
To send a notification to the device using a push kit, firstly the device must receive a push token.
Java:
private void getPushToken() {
new Thread() {
@Override
public void run() {
super.run();
try {
String appId = AGConnectServicesConfig.fromContext(MainActivity.this).getString("client/app_id");
String token = HmsInstanceId.getInstance(MainActivity.this).getToken(appId, "HCM");
if (!TextUtils.isEmpty(token)) {
DataStore.pushToken = token;
}
} catch (ApiException e) {
Log.e("TokenFailed", "get token failed" + e);
}
}
}.start();
}
We have received a push token, now we need to reach the access token, and we will do this through the service. We will obtain access token through the service, you must also complete the Retrofit implementations. Add Retrofit libraries app level build.gradle
Code:
implementation "com.squareup.retrofit2:retrofit:2.3.0"
implementation "com.squareup.retrofit2:converter-gson:2.3.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
In order to send access token, first we should prepare our request. This request should have grant_type ,client_id ,client_secret and will return AccessToken. Then, we will use this AccessToken for out further requests.
Java:
public interface AccessTokenInterface {
@FormUrlEncoded
@POST("v2/token")
Call<AccessToken> GetAccessToken(
@Field("grant_type") String grantType,
@Field("client_id") int clientId,
@Field("client_secret") String clientSecret);
}
Now let’s handle the method by which we will obtain the access token. We need a Base URL to use in this method. The variable defined as OAUTH_BASE_URL represents our base URL. Do not forget to fill in client_credentials, YOUR_CLIENT_ID, YOUR_CLIENT_SECRET parts according to your project. This getAccessToken() was created using Synchronous Call. You can do this with Asynchronous Call according to the needs of your own project.
Java:
public void getAccessToken() {
String YOUR_CLIENT_SECRET =" ";
int YOUR_CLIENT_ID = ;
AccessInterface apiInterface = RetrofitClient.getClient(OAUTH_BASE_URL).create(AccessInterface.class);
Call<AccessToken> call = apiInterface.GetAccessToken("client_credentials",YOUR_CLIENT_ID , YOUR_CLIENT_SECRET);
try{
Response<AccessToken> response = call.execute();
accessToken = String.format("Bearer %s",response.body().getAccessToken());
}catch (IOException e){
e.printStackTrace();
}
}
After obtaining the access token, we create an interface to send a notification with the push kit. Do not forget to fill the {YOUR_APP_ID} part of your project app ID.
Java:
public interface NotificationInterface {
@Headers("Content-Type:application/json")
@POST("{YOUR_APP_ID}/messages:send")
Call<PushParameter> sendNotification(
@Header("Authorization") String authorization,
@Body NotificationMessage notificationMessage);
}
Java:
public void sendNotification(String accesstoken, String geofenceDetail) {
NotificationInterface notiInterface = RetrofitClient.getClient(PUSH_API_URL).create(NotificationInterface.class);
NotificationMessage notificationMessage = (new NotificationMessage
.Builder("Title of Notification", geofenceDetail, DataStore.pushToken, "1"))
.build();
Call<PushParameter> callNoti = notiInterface.sendNotification(accesstoken, notificationMessage);
callNoti.enqueue(new Callback<PushParameter>() {
@Override
public void onResponse(Call<PushParameter> call, Response<PushParameter> response) {
Log.i("SendNotification", response.body().getMsg());
}
@Override
public void onFailure(Call<PushParameter> call, Throwable t) {
Log.i("SendNotification Failure", t.toString());
}
});
}
4- Developing the Geofence Part
We have set up the push kit to send notifications, now let’s see how we will send these notifications for geofence. First we create a broadcast receiver for geofence.
Java:
public class GeofenceBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
GeofenceNotification.enqueueWork(context,intent);
}
}
When the Broadcast Receiver is triggered, our geofence notifications will be sent through this class. You can see the accessToken and sendNotification methods we use for push kit in this class.
Java:
public class GeofenceNotification extends JobIntentService {
public static final String PUSH_API_URL = "https://push-api.cloud.huawei.com/v1/";
public static final String OAUTH_BASE_URL = "https://login.cloud.huawei.com/oauth2/";
private String accessToken;
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, GeofenceNotification.class, 573, intent);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
GeofenceData geofenceData = GeofenceData.getDataFromIntent(intent);
if (geofenceData != null) {
int conversion = geofenceData.getConversion();
ArrayList<Geofence> geofenceTransition = (ArrayList<Geofence>) geofenceData.getConvertingGeofenceList();
String geofenceTransitionDetails = getGeofenceTransitionDetails(conversion,
geofenceTransition);
getAccessToken();
sendNotification(accessToken, geofenceTransitionDetails);
}
}
private String getGeofenceTransitionDetails(int conversion, ArrayList<Geofence> triggeringGeofences) {
String geofenceConversion = getConversionString(conversion);
ArrayList<String> triggeringGeofencesIdsList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getUniqueId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return String.format("%s: %s",geofenceConversion,triggeringGeofencesIdsString);
}
private String getConversionString(int conversionType) {
switch (conversionType) {
case Geofence.ENTER_GEOFENCE_CONVERSION:
return getString(R.string.geofence_transition_entered);
case Geofence.EXIT_GEOFENCE_CONVERSION:
return getString(R.string.geofence_transition_exited);
case Geofence.DWELL_GEOFENCE_CONVERSION:
return getString(R.string.geofence_transition_dwell);
default:
return getString(R.string.unknown_geofence_transition);
}
}
public void sendNotification(String accesstoken, String geofenceDetail) {
NotificationInterface notiInterface = RetrofitClient.getClient(PUSH_API_URL).create(NotificationInterface.class);
NotificationMessage notificationMessage = (new NotificationMessage.Builder("Title of Notification", geofenceDetail, DataClass.pushToken, "1")).build();
Call<PushParameter> callNoti = notiInterface.sendNotification(accesstoken, notificationMessage);
callNoti.enqueue(new Callback<PushParameter>() {
@Override
public void onResponse(Call<PushParameter> call, Response<PushParameter> response) {
Log.i("SendNotification", response.body().getMsg());
}
@Override
public void onFailure(Call<PushParameter> call, Throwable t) {
Log.i("SendNotification Failure", t.toString());
}
});
}
public void getAccessToken() {
String YOUR_CLIENT_SECRET =" ";
int YOUR_CLIENT_ID = ;
AccessInterface apiInterface = RetrofitClient.getClient(OAUTH_BASE_URL).create(AccessInterface.class);
Call<AccessToken> call = apiInterface.GetAccessToken("client_credentials",YOUR_CLIENT_ID , YOUR_CLIENT_SECRET);
try{
Response<AccessToken> response = call.execute();
accessToken = String.format("Bearer %s",response.body().getAccessToken());
}catch (IOException e){
e.printStackTrace();
}
}
}
Then we add the methods we use to create a geofence list. In this project, I have defined geofences as static. You can adjust these geofence information according to the needs of your application. For example, if your location information is kept in the database, you can use geofence locations from the database. When adding geofences in the completeGeofenceList method, pay attention to the unique id part. If you try to add geofences with the same ids, you will get an error.
Java:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String TAG = "MainActivity";
private FusedLocationProviderClient fusedLocationProviderClient;
private PendingIntent geofencePendingIntent;
private ArrayList<Geofence> geofenceList;
private GeofenceService geofenceService;
private SettingsClient settingsClient;
LocationCallback locationCallback;
LocationRequest locationRequest;
private String pushToken;
private Marker mMarker;
private MapView mapView;
private HuaweiMap hMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
permissionCheck();
mapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle("MapViewBundleKey");
}
mapView.onCreate(mapViewBundle);
mapView.getMapAsync(this);
geofenceService = LocationServices.getGeofenceService(getApplicationContext());
getPushToken();
completeGeofenceList();
createGeofence();
}
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1){
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed");
}
}
else if (requestCode == 2) {
if (grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed");
}
}
}
private void permissionCheck(){
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "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,
Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
}
private GeofenceRequest getGeofencingRequest() {
return new GeofenceRequest.Builder()
.setInitConversions(GeofenceRequest.ENTER_INIT_CONVERSION)
.createGeofenceList(geofenceList)
.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(MainActivity.this, GeofenceBroadcast.class);
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return geofencePendingIntent;
}
private void completeGeofenceList() {
Geofence.Builder geoBuild = new Geofence.Builder();
geofenceList = new ArrayList<>();
geofenceList.add(geoBuild.setUniqueId("Home").setRoundArea(39.617841289998736,27.429383486070098,200).setValidContinueTime(Geofence.GEOFENCE_NEVER_EXPIRE).setConversions(Geofence.ENTER_GEOFENCE_CONVERSION).setDwellDelayTime(1000).build());
geofenceList.add(geoBuild.setUniqueId("Office").setRoundArea(38.14893633264862,26.82832426954628,200).setValidContinueTime(Geofence.GEOFENCE_NEVER_EXPIRE).setConversions(Geofence.ENTER_GEOFENCE_CONVERSION).setDwellDelayTime(1000).build());
}
private void createGeofence() {
geofenceService.createGeofenceList(getGeofencingRequest(), getGeofencePendingIntent());
}
private void getPushToken() {
new Thread() {
@Override
public void run() {
super.run();
try {
String appId = AGConnectServicesConfig.fromContext(MainActivity.this).getString("client/app_id");
String token = HmsInstanceId.getInstance(MainActivity.this).getToken(appId, "HCM");
if (!TextUtils.isEmpty(token)) {
DataStore.pushToken1 = token;
}
} catch (ApiException e) {
Log.e("TokenFailed", "get token failed" + e);
}
}
}.start();
}
}
Sample application outputs for the use of push kit with geofence are as follows;
Conclusion
By using the push kit features, you can personalize your notifications according to the needs of your application. In this article I explained how to use the Push kit for Geofence notifications. I hope you will like it. Thank you for reading. If you have any questions, you can leave a comment.
References
Geofence Service
Push Kit

Real-time Locating Helps Users Get Around

Real-time locating is a core function for many apps, allowing them to quickly and accurately locate users' real time locations.
HUAWEI Location Kit enables apps to quickly obtain precise user locations and build up global locating capabilities, helping you implement personalized map display and interaction, as well as improve overall location-based service experience.
This article demonstrates how to use HUAWEI Location Kit and Map Kit to implement the real-time locating capability in an app.
Expectations​An app can obtain and display a user's real-time location on the map, especially when the app is launched for the first time. The map display changes in accordance to the user's actual location.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Involved Capabilities​Location Kit: basic locating
Map Kit: map display
Implementation Principle​An app uses Location Kit to obtain a user's real-time location and uses Map Kit to display the My Location button on the in-app map that the user can tap to determine their real-time location.
Preparations​Register as a developer and create a project in AppGallery Connect.
Click here to register as a developer.
Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of the app. For detailed instructions, please visit the official website of HUAWEI Developers.
Configure the Android Studio project.
Copy the agconnect-services.json file to the app directory of the project.
Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
Add build dependencies in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:maps:{version}'
implementation 'com.huawei.hms:location:{version}'
}
Add the following configuration to the file header.
Code:
apply plugin: 'com.huawei.agconnect'
Copy the signing certificate generated in Generating a Signing Certificate to the app directory of your project, and configure the signing certificate in android in the build.gradle file.
Code:
signingConfigs {
release {
// Signing certificate.
storeFile file("**.**")
// KeyStore password.
storePassword "******"
// Key alias.
keyAlias "******"
// Key password.
keyPassword "******"
v2SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
debug {
debuggable true
}
}
Key Code Implementation​(1) Compile a service to obtain a user's real-time location.
Java:
public class LocationService extends Service {
private final String TAG = this.getClass().getSimpleName();
List<ILocationChangedLister> locationChangedList = new ArrayList<>();
// Location
private FusedLocationProviderClient fusedLocationProviderClient;
private LocationRequest mLocationRequest;
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
locationResult.getLocations();
Log.d(TAG, "onLocationResult: " + locationResult);
Location location = locationResult.getLocations().get(0);
Log.w(TAG, "onLocationResult:Latitude " + location.getLatitude());
Log.w(TAG, "onLocationResult:Longitude " + location.getLongitude());
for (ILocationChangedLister locationChanged : locationChangedList) {
locationChanged.locationChanged(new LatLng(location.getLatitude(), location.getLongitude()));
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
Log.d(TAG, "onLocationAvailability: " + locationAvailability.toString());
}
};
private final MyBinder binder = new MyBinder();
private final Random generator = new Random();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
Log.i("DemoLog", "TestService -> onCreate, Thread: " + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("DemoLog",
"TestService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());
return START_NOT_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("DemoLog", "TestService -> onUnbind, from:" + intent.getStringExtra("from"));
return false;
}
@Override
public void onDestroy() {
Log.i("DemoLog", "TestService -> onDestroy, Thread: " + Thread.currentThread().getName());
super.onDestroy();
}
public int getRandomNumber() {
return generator.nextInt();
}
public void addLocationChangedlister(ILocationChangedLister iLocationChangedLister) {
locationChangedList.add(iLocationChangedLister);
}
public void getMyLoction() {
Log.d(TAG, "getMyLoction: ");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Location setting
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> Log.d(TAG, "onSuccess: " + aVoid)))
.addOnFailureListener(Throwable::printStackTrace);
}
public class MyBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
public interface ILocationChangedLister {
/**
* Update the location information
*
* @param latLng The new location information
*/
public void locationChanged(LatLng latLng);
}
}
(2) Add a map in the activity to monitor a user's real-time location.
Add a map using the XML layout file:
XML:
<com.huawei.hms.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Add a map in the activity:
XML:
mapView.onCreate(null);
mapView.getMapAsync(this);
Tap My Location button to display the current location on the map:
XML:
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
}
Bind Location Kit to listen to location changing events:
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBound = true;
if (binder instanceof LocationService.MyBinder) {
LocationService.MyBinder myBinder = (LocationService.MyBinder) binder;
locationService = myBinder.getService();
Log.i(TAG, "ActivityA onServiceConnected");
locationService.addLocationChangedlister(iLocationChangedLister);
locationService.getMyLoction();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
locationService = null;
Log.i(TAG, "ActivityA onServiceDisconnected");
}
};
Bind the activity to LocationService:
private void bindLocationService() {
Intent intent = new Intent(mActivity, LocationService.class);
intent.putExtra("from", "ActivityA");
Log.i(TAG, "-------------------------------------------------------------");
Log.i(TAG, "bindService to ActivityA");
mActivity.bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
Process the location changing events in the location changing listener:
LocationService.ILocationChangedLister iLocationChangedLister = new LocationService.ILocationChangedLister() {
@Override
public void locationChanged(LatLng latLng) {
Log.d(TAG, "locationChanged: " + latLng.latitude);
Log.d(TAG, "locationChanged: " + latLng.longitude);
updateLocation(latLng);
}
};
Update map view:
private void updateLocation(LatLng latLng) {
mLatLng = latLng;
hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 1));
}
Testing the App​You can use a mock location app to change your current location and see how the map view and My Location button alter accordingly.
To learn more, please visit:
HUAWEI Developers official website
Development Guide
Reddit to join developer discussions
GitHub or Gitee to download the demo and sample code
Stack Overflow to solve integration problems
Follow our official account for the latest HMS Core-related news and updates.
Original Source

How to Automatically Fill Addresses in Lifestyle Apps

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​
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
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.
Java:
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.
Java:
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:
Java:
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.
Java:
<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).
Java:
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
Java:
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.
Java:
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.
Java:
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.
Java:
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
>> Location Kit Development Guide
>> Reddit to join developer discussions
>> GitHub to download the sample code
>> Stack Overflow to solve integration problems

Categories

Resources