Related
Hi everybody!
I am developing an app that (for now) will scan bluetooth devices in the area and it display them on screen. Same thing has to do it with devices that are already associated with the terminal.
Problems:
1) If It start the application with bluetooth off, I get the mythical alert asking me if I want to activate the bluetooth. Confirmed the request, the alert for activate the bluetooth appears and then ... Black screen. Theoretically it should show a list of paired device (in this case, my laptop) but the screen is constantly black (for black i mean that the bar of the name of the app and the Android status bar are showed. The phone doesn't freeze)
2) However, if you start the application with bluetooth turned on, the app crashes and exits.
Any suggestion for solve these problems?
This is the Java Source Code:
Code:
public class Bluetooth extends Activity {
ArrayAdapter<String> mAA;
ListView lv;
private static final int REQUEST_ENABLE_BT = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.bluetooth);
lv = (ListView) findViewById(R.id.lv);
mAA = new ArrayAdapter<String>(this, R.id.lv);
BluetoothAdapter mBA = BluetoothAdapter.getDefaultAdapter();
if (!mBA.isEnabled()) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Set<BluetoothDevice> pairedDevices = mBA.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mAA.add(device.getName() + "\n" + device.getAddress());
lv.setAdapter(mAA);
}
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mAA.add(device.getName() + "\n" + device.getAddress());
}
}
};
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
mBA.cancelDiscovery();
lv.setAdapter(mAA);
}
}
Clarification:
- In the manifest i insert the string <uses-permission android:name="android.permission.BLUETOOTH" />
- Layout XML:
HTML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/ apk /res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" >
</ListView>
</LinearLayout>
Thank you in advance for all your help!
... And sorry for my English...
This article is originally from HUAWEI Developer Forum
Forum link: https://forums.developer.huawei.com/forumPortal/en/home
HiAi Image Super Resolution
Upscales an image or reduces image noise and improves image details without changing the resolution.
{
"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"
}
Upscales an image or reduces image noise and improves image details without changing the resolution.
Base on AI deep learning of CV (Computer Vision)
Utilize Huawei NPU (Neural Processing Unit), 50X faster than CPU
1X & 3X super-resolution furnish images with clearer effect, reducing JPEG compression noise
You can check the offical documentation about HiAi Image super resolution.
Huawei continuous investment on NPU technology
Huawei Phones support HiAI
Software: Huawei EMUI 9.0 & above
Hardware: CPU 970,810, 820,985,990
Codelab
https://developer.huawei.com/consumer/en/codelab/HiAIImageSuperresolution/index.html#0
You can also follow the codelab to implement the HiAi image resolution with the help DevEco IDE plugin in Android Studio.
Project: (HiAi Image Super Resolution)
In this article we are going to make project in which we can implement HiAi Image Super Resolution to improve low resolution image quality which is used in most of the application as a thumbnail images.
1. Implementation:
Download the vision-oversea-release.aar package in the Huawei AI Engine SDKs from the Huawei developer community.
Copy the downloaded vision-oversea-release.aar package to the app/libs directory of the project.
Add the following code to build.gradle in the APP directory of the project, and add vision-release.aar to the project. Dependency on the Gson library must be added, because the conversion of parameters and results between the JavaScript Object Notation (JSON) and Java classes inside vision-release.aar depends on the Gson library.
Code:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation(name: 'vision-oversea-release', ext: 'aar')
implementation 'com.google.code.gson:gson:2.8.6'
}
2. Assets:
In this section we adding some low resolution images in "assets/material/image_super_resolution" directory, to further fetch images for local direction for optimization.
3. Design ListView:
In this section we are design ListView in our layouts to show original images and optimized images.
activity_main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1pt"
android:layout_marginBottom="5pt"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Original Image"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Improved Image"
android:textSize="24sp" />
</LinearLayout>
<ListView
android:id="@+id/item_listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="3pt"
/>
</LinearLayout>
items.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/imgOriginal"
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/noimage"
android:layout_gravity="start"
android:layout_weight="1"
/>
<TextView
android:id="@+id/imgTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
android:layout_gravity="center_horizontal"
android:layout_weight="0"
android:textAlignment="center"
/>
<ImageView
android:id="@+id/imgConverted"
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/noimage"
android:layout_gravity="end"
android:layout_weight="1"
app:layout_constraintDimensionRatio="h,4:3"
/>
</LinearLayout>
4. Coding: (Adapter, HiAi Image Super Resolution )
Util Class:
We make a util class AssetsFileUtil, to get all the images from local assets directory, get single BitMap image.
Code:
public class AssetsFileUtil {
public static Bitmap getBitmapByFilePath(Context context, String filePath){
try{
AssetManager assetManager = context.getAssets();
InputStream is = assetManager.open(filePath);
Bitmap bitmap = BitmapFactory.decodeStream(is);
return bitmap;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
public static List<Bitmap> getBitmapListByDirPath(Context context, String dirPath){
List<Bitmap> list = new ArrayList<Bitmap>();
try{
AssetManager assetManager = context.getResources().getAssets();
String[] photos = assetManager.list(dirPath);
for(String photo : photos){
if(isFile(photo)){
Bitmap bitmap = getBitmapByFilePath(context,dirPath + "/" + photo);
list.add(bitmap);
}else {
List<Bitmap> childList = getBitmapListByDirPath(context,dirPath + "/" + photo);
list.addAll(childList);
}
}
}catch (Exception e){
e.printStackTrace();
}
return list;
}
public static List<String> getFileNameListByDirPath(Context context, String dirPath){
List<String> list = new ArrayList<String>();
try{
AssetManager assetManager = context.getResources().getAssets();
String[] photos = assetManager.list(dirPath);
for(String photo : photos){
if(isFile(photo)){
list.add(dirPath + "/" + photo);
}else {
List<String> childList = getFileNameListByDirPath(context,dirPath + "/" + photo);
list.addAll(childList);
}
}
}catch (Exception e){
e.printStackTrace();
}
return list;
}
public static boolean isFile(String fileName){
if(fileName.contains(".")){
return true;
}else {
return false;
}
}
}
MainActivity Class:
In this class we are getting local images and attaching images list to our Adapter
Code:
public class MainActivity extends AppCompatActivity {
private String mDirPath;
private ArrayList<Item> itemList;
private List<String> imageList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
itemList = new ArrayList<Item>();
getLocalImages();
// Setting Adapter and listview
ItemAdapter itemAdapter = new ItemAdapter(getApplicationContext(), R.layout.items, itemList);
ListView listView = findViewById(R.id.item_listView);
listView.setAdapter(itemAdapter);
}
public void getLocalImages(){
mDirPath ="material/image_super_resolution";
imageList = AssetsFileUtil.getFileNameListByDirPath(this,mDirPath);
for(int i=0; i<imageList.size();i++){
itemList.add(new Item(imageList.get(i), " ", imageList.get(i)));
}
}
}
Item Class:
Prepare item data class.
Code:
public class Item {
private String imgOriginal;
private String imgTitle;
private String imgConverted;
public Item(String imgOriginal, String imgTitle, String imgConverted) {
this.imgOriginal = imgOriginal;
this.imgTitle = imgTitle;
this.imgConverted = imgConverted;
}
public String getImgOriginal() {
return imgOriginal;
}
public void setImgOriginal(String imgOriginal) {
this.imgOriginal = imgOriginal;
}
public String getImgTitle() {
return imgTitle;
}
public void setImgTitle(String imgTitle) {
this.imgTitle = imgTitle;
}
public String getImgConverted() {
return imgConverted;
}
public void setImgConverted(String imgConverted) {
this.imgConverted = imgConverted;
}
}
ItemAdapter Class:
In this class we are binding our images array list with our layout ImageView and implement HiAi Image Resolution to optimize image resolution.
ItemAdapter class extends ArrayAdapter with the type of Item class.
Code:
public class ItemAdapter extends ArrayAdapter<Item>
Define some constants
Code:
private ArrayList<Item> itemList;
private final static int SUPERRESOLUTION_RESULT = 110;
private Bitmap bitmapOriginal;
private Bitmap bitmapConverted;
ImageView imgOriginal;
ImageView imgConverted;
private String TAG = "ItemAdapter";
Prepare constructor for the Adpater class
Code:
public ItemAdapter(@NonNull Context context, int resource, @NonNull ArrayList<Item> itemList) {
super(context, resource, itemList);
this.itemList = itemList;
}
Define initHiAi function to check service connected or disconnected
Code:
/**
* init HiAI interface
*/
private void initHiAI() {
/** Initialize with the VisionBase static class and asynchronously get the connection of the service */
VisionBase.init(getContext(), new ConnectionCallback() {
@Override
public void onServiceConnect() {
/** This callback method is invoked when the service connection is successful; you can do the initialization of the detector class, mark the service connection status, and so on */
}
@Override
public void onServiceDisconnect() {
/** When the service is disconnected, this callback method is called; you can choose to reconnect the service here, or to handle the exception*/
}
});
}
Define setHiAi function to perform HiAi operation on Original image and generate the optimized Bitmap.
Code:
/**
* Capability Interfaces
*
* @return
*/
private void setHiAi() {
/** Define class detector, the context of this project is the input parameter */
ImageSuperResolution superResolution = new ImageSuperResolution(getContext());
/** Define the frame, put the bitmap that needs to detect the image into the frame*/
Frame frame = new Frame();
/** BitmapFactory.decodeFile input resource file path*/
// Bitmap bitmap = BitmapFactory.decodeFile(null);
frame.setBitmap(bitmapOriginal);
/** Define and set super-resolution parameters*/
SuperResolutionConfiguration paras = new SuperResolutionConfiguration(
SuperResolutionConfiguration.SISR_SCALE_3X,
SuperResolutionConfiguration.SISR_QUALITY_HIGH);
superResolution.setSuperResolutionConfiguration(paras);
/** Run super-resolution and get result of processing */
ImageResult result = superResolution.doSuperResolution(frame, null);
/** After the results are processed to get bitmap*/
Bitmap bmp = result.getBitmap();
/** Note: The result and the Bitmap in the result must be NULL, but also to determine whether the returned error code is 0 (0 means no error)*/
this.bitmapConverted = bmp;
handler.sendEmptyMessage(SUPERRESOLUTION_RESULT);
}
Define Handler if the optimization completed attach the optimized Bitmap to image.
Code:
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SUPERRESOLUTION_RESULT:
if (bitmapConverted != null) {
imgConverted.setImageBitmap(bitmapConverted);
} else { // Set the original image
imgConverted.setImageBitmap(bitmapOriginal);
// toast("High Resolution image");
}
break;
}
}
};
Override the getView method attached orginial image to image view and process the original image to attached optimized image.
Code:
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
initHiAI();
int itemIndex = position;
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.items,parent, false);
}
imgOriginal = convertView.findViewById(R.id.imgOriginal);
TextView imgTitle = convertView.findViewById(R.id.imgTitle);
imgConverted = convertView.findViewById(R.id.imgConverted);
bitmapOriginal = AssetsFileUtil.getBitmapByFilePath(imgOriginal.getContext(), itemList.get(itemIndex).getImgConverted());
imgOriginal.setImageBitmap(bitmapOriginal);
bitmapConverted =AssetsFileUtil.getBitmapByFilePath(imgConverted.getContext(), itemList.get(itemIndex).getImgOriginal());
imgConverted.setImageBitmap(bitmapConverted);
int height = bitmapOriginal.getHeight();
int width = bitmapOriginal.getWidth();
Log.e(TAG, "width:" + width + ";height:" + height);
if (width <= 800 && height <= 600) {
new Thread() {
@Override
public void run() {
setHiAi();
}
}.start();
} else {
toast("Width and height of the image cannot exceed 800*600");
}
imgTitle.setText(itemList.get(itemIndex).getImgTitle());
return convertView;
}
public void toast(String text) {
Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show();
}
Coding section has been complete here, now run you project and check the output of the Image Optimization by using HiAi Image Super Resolution.
5. Result
In this article I will explain how to develop a basic messaging app by Huawei Push Kit. If you want to develop a messaging app or add messaging section into your application, I hope this article will be useful for you.
Before beginning, this application and article will be addition of my first ones. If you have not seen that article, you can see the link below. It also shows how to integrate Push Kit into your Xamarin.Android Application.
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201314061860830181&fid=0101187876626530001
Layout of activity_main
We will only add our messaging button to pass to messaging section. Final version of “activity_main.xml” will be like this.
Code:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:id="@+id/linearLayoutMain">
<Button
android:text="Get Token"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:layout_weight="15"
android:id="@+id/btnGetToken" />
<Button
android:text="Send Test Notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:layout_weight="15"
android:visibility="invisible"
android:id="@+id/btnNotification" />
<Button
android:text="Send Test Data Message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:layout_weight="15"
android:visibility="invisible"
android:id="@+id/btnDataMessage" />
<Button
android:text="Messaging"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:layout_weight="15"
android:visibility="invisible"
android:id="@+id/btnMessagingMain" />
</LinearLayout>
MainActivity Class
Firstly, we will inherit ViewAnimator.IOnClickListener interface to this class. Then, we will organize inside of OnCreate Method and implement OnClick method.
Code:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
//Identifying Buttons
btnGetToken = FindViewById<Button>(Resource.Id.btnGetToken);
btnNotification = FindViewById<Button>(Resource.Id.btnNotification);
btnDataMessage = FindViewById<Button>(Resource.Id.btnDataMessage);
btnMessagingMain = FindViewById<Button>(Resource.Id.btnMessagingMain);
//Set onClick listener to buttons
btnGetToken.SetOnClickListener(this);
btnNotification.SetOnClickListener(this);
btnDataMessage.SetOnClickListener(this);
btnMessagingMain.SetOnClickListener(this);
//Create instance of Broadcast Receiver for data message service
myReceiver = new MyBroadcastReceiver();
CheckPermission(new string[] { Android.Manifest.Permission.Internet,
Android.Manifest.Permission.AccessNetworkState,
Android.Manifest.Permission.WakeLock}, 100);
}
Secondly, we will arrange OnClick method so that we can call these events from one method.
Code:
public void OnClick(View v)
{
try
{
switch (v.Id)
{
case Resource.Id.btnGetToken:
GetToken();
break;
case Resource.Id.btnNotification:
HmsPushKit.SendNotification(tokenFromGetToken, "Title", "Body");
break;
case Resource.Id.btnDataMessage:
HmsPushKit.SendDataMessage(tokenFromGetToken, "{\"Type\":\"Test\",\"Message\":\"Welcome\"}");
break;
case Resource.Id.btnMessagingMain:
StartMessagingMain();
break;
default:
break;
}
}
catch (Exception e)
{
Log.Error("OnClickListener", e.ToString());
}
}
Thirdly, as you guess we will add StartMessagingMain method to call MessagingMainActivity class. Calling StartActivity method is adequate here. We don’t have to send any Intent.
Finally, we will move AccessToken, SendDataMessage and SendNotification method to new HmsPushKit class.
HmsPushKit.cs
We should be able to call these methods from any other class. Because of that, methods in this class should be static.
Code:
public static class HmsPushKit
{
static readonly string appID = "AppID"; //AppGallery Connect > Project Setting > App information > App ID
static readonly string appKey = "AppKey"; //AppGallery Connect > Project Setting > App information > App key
static readonly HttpClient client = new HttpClient();
public static async Task<string> GetAccessToken()
{
string uri = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
var values = new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", appID },
{ "client_secret", appKey }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync(uri, content);
var jsonResponse = JObject.Parse(await response.Content.ReadAsStringAsync()); //Install-Package Newtonsoft.Json
string accessToken = jsonResponse["access_token"].ToString(); //It is valid for 3600 seconds
return accessToken;
}
/// <summary>
/// Send notification by Huawei Push Kit.
/// </summary>
/// <param name="tokenUSendTo">This token get by GetToken function</param>
/// <param name="notTitle">Notification Title</param>
/// <param name="notBody">Notification Body</param>
public static async void SendNotification(string tokenUSendTo,string notTitle,string notBody)
{
string uriNot = "https://push-api.cloud.huawei.com/v1/" + appID + "/messages:send";
var jObject = new
{
message = new
{
notification = new
{
title = notTitle,
body = notBody
},
android = new
{
notification = new
{
click_action = new
{
type = 3
}
}
},
token = new[] { tokenUSendTo }
}
};
string myJson = JsonConvert.SerializeObject(jObject, Formatting.Indented);
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", await GetAccessToken());
var responseData = await client.PostAsync(uriNot, new StringContent(myJson, Encoding.UTF8, "application/json"));
}
/// <summary>
/// Send data message by Huawei Push Kit.
/// </summary>
/// <param name="tokenUSendTo">This token get by GetToken function</param>
/// <param name="serializedObject">Use JsonConvert.SerializeObject function</param>
public static async void SendDataMessage(string tokenUSendTo, string serializedObject)
{
string uriNot = "https://push-api.cloud.huawei.com/v1/" + appID + "/messages:send";
var jObject = new
{
message = new
{
data = serializedObject,
token = new[] { tokenUSendTo }
}
};
string myJson = JsonConvert.SerializeObject(jObject, Formatting.Indented);
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", await GetAccessToken());
var responseData = await client.PostAsync(uriNot, new StringContent(myJson, Encoding.UTF8, "application/json"));
}
}
DataBase
Actually, database is not essential for a sample application but I want to make it pretty. I will use sqlite-net-pcl by SQLite-net.
{
"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"
}
This application will need two essential database tables(Model) Person and Message. We will also use UniqueData table for minor data.
Code:
public class Person
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public string Token { get; set; }
public Person(string Code,string Name)
{
this.Code = Code;
this.Name = Name;
Random rnd = new Random();
Icon = "icon" + rnd.Next(1, 4);
}
public Person()
{
}
}
public class Message
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string CodeFrom { get; set; }
public string CodeTo { get; set; }
public string Text { get; set; }
}
public class UniqueData
{
public string Key { get; set; }
public string Value { get; set; }
}
And the Database class that I use is below. The most part is easy to understand. If you want to use another Model you should add this into CreateDataBase method. Moreover, you don’t have to check if there is a database. If database does not exist, it will create otherwise it will not.
Code:
public class DataBase
{
readonly string dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "DB.db");
readonly string _SQLite = "SQLite";
public DataBase()
{
CreateDataBase();
}
public bool CreateDataBase()
{
try
{
using (var connection = new SQLiteConnection(dbPath))
{
connection.CreateTable<Person>();
connection.CreateTable<Message>();
connection.CreateTable<UniqueDatas>();
return true;
}
}
catch (SQLiteException e)
{
Log.Error(_SQLite, e.Message);
return false;
}
}
public bool InsertIntoTable<T>(T row)
{
try
{
using (var connection = new SQLiteConnection(dbPath))
{
connection.Insert(row);
return true;
}
}
catch (SQLiteException e)
{
Log.Error(_SQLite, e.Message);
return false;
}
}
public List<T> SelectTable<T>() where T:new()
{
try
{
using (var connection = new SQLiteConnection(dbPath))
{
return connection.Table<T>().ToList();
}
}
catch (SQLiteException e)
{
Log.Error(_SQLite, e.Message);
return null;
}
}
public bool DeleteFromTable<T>(T row)
{
try
{
using (var connection = new SQLiteConnection(dbPath))
{
connection.Delete(row);
return true;
}
}
catch (SQLiteException e)
{
Log.Error(_SQLite, e.Message);
return false;
}
}
}
Layout of activity_main_messaging
I will share with you a simple screen for the list of people.
My xml file will not contain the rows. We will add them from MessagingMainActivity class. Xml code for this layout below.
Code:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@color/material_grey_300"
android:weightSum="4"
android:paddingHorizontal="2dp">
<Button
android:text="Del"
android:gravity="center_horizontal"
android:textSize="24dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/btnDel"/>
<TextView
android:text="Chats"
android:gravity="center"
android:textStyle="bold"
android:textColor="@android:color/black"
android:textSize="24dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="4"
android:id="@+id/textView1"
/>
<Button
android:gravity="center_horizontal"
android:text="New"
android:textSize="24dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/btnNew"/>
</LinearLayout>
<ScrollView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:scrollbars="vertical"
android:paddingHorizontal="20dp"
android:id="@+id/scrollView">
<LinearLayout
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/linearLayout"
android:divider="#B6B6B6"
android:dividerHeight="5px">
</LinearLayout>
</ScrollView>
</LinearLayout>
MessagingMainActivity Class
Things we will do in this class are bringing people from database, adding new person, deleting person and starting messaging. So let’s start with identifing Delete Button, New button and LinearLayout which is in the ScrollView.
After, we will set ClickListener on two buttons therefore, we will inherit ViewAnimator.IOnClickListener to this activity as well.
Later, we need to take instance of our DataBase class then add people into our LinearLayout. Furthermore, I will also add sample data.
At last, we will fill OnClick method.
Code:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main_messaging);
linearLayout = FindViewById<LinearLayout>(Resource.Id.linearLayout);
btnNew = FindViewById<Button>(Resource.Id.btnNew);
btnDel = FindViewById<Button>(Resource.Id.btnDel);
btnNew.SetOnClickListener(this);
btnDel.SetOnClickListener(this);
db = new DataBase();
if (db.SelectTable<Person>().Count == 0)
{
db.InsertIntoTable(new Person { Code = "0", Name = "Enes Durmus", Icon = "icon1" });
db.InsertIntoTable(new Person { Code = "1", Name = "Ahmet Ercek", Icon = "icon2" });
db.InsertIntoTable(new Person { Code = "2", Name = "Gokberk Bardakci", Icon = "icon3" });
}
foreach (Person person in db.SelectTable<Person>())
{
linearLayout.AddView(OneRowLL(this, person));
Log.Info("SQLite", person.ToString());
linearLayout.AddView(GetLine(this, Resources.DisplayMetrics.WidthPixels / 3));// This is just decorative
}
}
public void OnClick(View v)
{
try
{
switch (v.Id)
{
case Resource.Id.btnNew:
AddPerson();
break;
case Resource.Id.btnDel:
IsDelete = true;
break;
default:
break;
}
}
catch (Exception e)
{
Log.Error("OnClickListener", e.ToString());
}
}
As you see there is OneRowLL method. It returns a linearlayout which contains CircleImageView from Refractored.Controls.CircleImage nuget and linearlayout contains two textviews.
Code:
LinearLayout OneRowLL(Context context, Person person)
{
LinearLayout result = new LinearLayout(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent);
result.LayoutParameters = layoutParams;
result.Orientation = Orientation.Horizontal;
result.TransitionName = person.Code;
result.WeightSum = 1;
ViewGroup.LayoutParams vgLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.MatchParent);
CircleImageView imageView = new CircleImageView(context); // Nuget: Refractored.Controls.CircleImageView
LinearLayout.LayoutParams iLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WrapContent, LinearLayout.LayoutParams.MatchParent) { Weight = 0.6f };
imageView.LayoutParameters = iLayoutParams;
int id = Resources.GetIdentifier("com.companyname.pushdemoforarticle:drawable/" + person.Icon, null, null);
imageView.SetImageResource(id);
imageView.BorderWidth = 6;
imageView.BorderColor = -16777216;
result.AddView(imageView);
LinearLayout subLinearLayout = new LinearLayout(context);
layoutParams.Weight = 1;
subLinearLayout.LayoutParameters = layoutParams;
subLinearLayout.Orientation = Orientation.Vertical;
subLinearLayout.SetPadding(20, 0, 0, 0);
ViewGroup.LayoutParams txtViewLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
subLinearLayout.AddView(new TextView(context)
{
Text = person.Name,
TextSize = 24,
LayoutParameters = txtViewLayoutParams,
Gravity = GravityFlags.Start
});
string _lastMessage = string.Empty;
List<Message> messages = db.SelectTable<Message>().Where(x => x.CodeFrom == person.Code || x.CodeTo == person.Code).ToList();
if (messages.Count != 0)
{
Message lastMessage = messages.TakeLast(1).First();
_lastMessage = lastMessage.CodeFrom == self ? "You: "+lastMessage.Text : lastMessage.Text;
}
subLinearLayout.AddView(new TextView(context)
{
Text = _lastMessage,
LayoutParameters = txtViewLayoutParams,
});
result.AddView(subLinearLayout);
result.Click += LinearLayoutClick;
return result;
}
Afterwards, we will create AddPerson method for btnNew. We will use LayoutInflater so I also create a xml file as well. We need user’s code to get his token and a name to display it.
Code:
private void AddPerson()
{
AlertDialog dialog = InitDialog();
dialog.Show();
}
public AlertDialog InitDialog()
{
//Setting xml from layouts
LayoutInflater layoutInflater = LayoutInflater.From(this);
View view = layoutInflater.Inflate(Resource.Layout.input_box, null);
AlertDialog.Builder alertbuilder = new AlertDialog.Builder(this);
alertbuilder.SetView(view);
//Identifing EditTexts
var userCode = view.FindViewById<EditText>(Resource.Id.txtUserCode);
var userName = view.FindViewById<EditText>(Resource.Id.txtUserName);
//Setting Positive and Negative Buttons
alertbuilder.SetCancelable(false)
.SetPositiveButton("OK", delegate
{
Person person = new Person(userCode.Text.Trim(), userName.Text);
if (db.InsertIntoTable(person))
linearLayout.AddView(OneRowLL(this, person));
}).SetNegativeButton("Cancel", delegate { });
AlertDialog dialog = alertbuilder.Create();
return dialog;
}
Code:
<?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">
<TextView
android:id="@+id/dialogTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Your Friend"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/txtUserCode"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Your Friend's Code" />
<EditText
android:id="@+id/txtUserName"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Your Friend's Name" />
</LinearLayout>
Next step is btnDel. Delete button will be simple. Click delete then click person afterwards person is gone. That’s adequate for now but you can improve it by adding invisible red delete button to each row and ask for approve.
Finally, LinearLayoutClick for pass to messaging. We will send their code by Intent.
Code:
public void LinearLayoutClick(object sender, EventArgs e)
{
LinearLayout row = sender as LinearLayout;
if (!IsDelete)
{
Intent intent = new Intent(this, typeof(MessagingActivity));
intent.PutExtra("code", row.TransitionName);
StartActivity(intent);
}
else
{
linearLayout.RemoveView(row);
IsDelete = false;
}
}
Layout of activity_messaging.xml
There will be 3 sections. First one is the LinearLayout which shows who we message. Second one is ScrollView for messages. And the last one is EditText for typing and sending. Xml file below.
Code:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:id="@+id/linearLayoutMain">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="100"
android:id="@+id/ll0"
android:transitionName="0"
android:paddingLeft="@dimen/abc_select_dialog_padding_start_material">
<refractored.controls.CircleImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="60"
app:civ_border_width="2dp"
app:civ_border_color="#000000"
android:id="@+id/imageIcon"/>
<LinearLayout
android:paddingLeft="10dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="100">
<TextView
android:textSize="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:id="@+id/txtName"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtStatus"/>
</LinearLayout>
</LinearLayout>
<ScrollView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="100"
android:gravity="bottom"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:scrollbars="vertical"
android:paddingHorizontal="20dp"
android:id="@+id/scrollView">
<LinearLayout
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/linearLayout" />
</ScrollView>
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="20"
android:id="@+id/textInput"
android:hint="Type here!"
android:layout_marginBottom="4dp"/>
</LinearLayout>
For more information, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202327073597950015&fid=0101187876626530001
Introduction
Huawei offer a range of ad formats so you can choose whichever that suits your app best. Currently, you can integrate Banner, Native, Rewarded, Interstitial, Splash, and Roll ads, and we will be launching even more formats in the future.
Use the HUAWEI Ads SDK to quickly integrate HUAWEI Ads into your app.
Native Ads
Native ads fit seamlessly into the surrounding content to match your app design. Such ads can be customized as needed.
{
"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"
}
In this article we can learn about how to integrate Native image and video Ads in between RecyclerView items.
Check the below activity_main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rl_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<RelativeLayout
android:id="@+id/rl_tool"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Music Player"
android:textColor="#fff"
android:textSize="16sp" />
</RelativeLayout>
<TextView
android:id="@+id/txt_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/rl_tool"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="Playlist"
android:textColor="#fff"
android:textSize="16sp" />
<com.yarolegovich.discretescrollview.DiscreteScrollView
android:id="@+id/discrete_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/hw_banner_view"
android:layout_below="@id/txt_category"
app:dsv_orientation="vertical" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="false"
android:indeterminateDrawable="@drawable/circular_progress"
android:visibility="invisible" />
<com.huawei.hms.ads.banner.BannerView
android:id="@+id/hw_banner_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
After that check below MainActivity for how to get API response data by using Volley library
Code:
public class MainActivity extends AppCompatActivity {
private DiscreteScrollView discreteScrollView;
public static String BASE_URL = "https://beatsapi.media.jio.com/v2_1/beats-api/jio/src/response/home/";
private String BASE_IMAGE_URL;
private ArrayList<PlaylistModel> playlist = new ArrayList();
private boolean isConnected = false;
private HomeAdapterNew homeAdapter;
private SharedPreferences preferences;
private SharedPreferences.Editor editor;
private ProgressBar progressBar;
private BannerView bannerView;
private RelativeLayout rlRoot;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
addBannerAd();
initHomeAdapter();
if (NetworkUtil.isNetworkConnected(this))
callHomeResponseApiVolley();
else {
String homeResponse = preferences.getString("HomeResponse", "");
filterResponse(homeResponse);
}
}
private void init() {
preferences = this.getSharedPreferences("MyPref", Context.MODE_PRIVATE);
discreteScrollView = findViewById(R.id.discrete_scroll_view);
progressBar = findViewById(R.id.progress_bar);
bannerView = findViewById(R.id.hw_banner_view);
rlRoot = findViewById(R.id.rl_root);
}
private void initHomeAdapter() {
homeAdapter = new HomeAdapterNew(this);
discreteScrollView.setAdapter(homeAdapter);
discreteScrollView.setSlideOnFling(true);
discreteScrollView.setItemTransformer(new ScaleTransformer.Builder()
.setMaxScale(1.05f)
.setMinScale(0.8f)
.setPivotX(Pivot.X.CENTER)
.setPivotY(Pivot.Y.CENTER)
.build());
discreteScrollView.addScrollStateChangeListener(new DiscreteScrollView.ScrollStateChangeListener<RecyclerView.ViewHolder>() {
@Override
public void onScrollStart(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
}
@Override
public void onScrollEnd(@NonNull RecyclerView.ViewHolder viewHolder, int adapterPosition) {
}
@Override
public void onScroll(float v, int i, int i1, @Nullable RecyclerView.ViewHolder viewHolder, @Nullable RecyclerView.ViewHolder t1) {
}
});
}
private void addBannerAd() {
bannerView.setAdId("testw6vs28auh3");
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_360_57);
AdParam adParam = new AdParam.Builder().build();
bannerView.loadAd(adParam);
}
private void callHomeResponseApiVolley() {
progressBar.setVisibility(View.VISIBLE);
StringRequest request = new StringRequest(Request.Method.GET, BASE_URL + "Telugu", new com.android.volley.Response.Listener<String>() {
@Override
public void onResponse(String response) {
progressBar.setVisibility(View.INVISIBLE);
if (response != null) {
editor = preferences.edit();
editor.putString("HomeResponse", response);
editor.apply();
filterResponse(response);
}
}
}, new com.android.volley.Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
progressBar.setVisibility(View.INVISIBLE);
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(request);
}
void filterResponse(String response) {
try {
JSONObject object = new JSONObject(response);
JSONObject resultObject = object.getJSONObject("result");
JSONArray jsonDataArray = resultObject.getJSONArray("data");
BASE_IMAGE_URL = resultObject.getString("imageurl");
Log.e("BASE_URL_IMAGE", BASE_IMAGE_URL);
for (int i = 0; i < jsonDataArray.length(); i++) {
String type = jsonDataArray.getJSONObject(i).getString("type");
JSONArray songsListArray = jsonDataArray.getJSONObject(i).getJSONArray("list");
if (type.equalsIgnoreCase("playlist")) {
getSongsFromArray(songsListArray);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private void getSongsFromArray(JSONArray songsListArray) throws JSONException {
for (int i = 0; i < songsListArray.length(); i++) {
JSONObject jsonObject = songsListArray.getJSONObject(i);
String title = jsonObject.getString("title");
String imageUrl = jsonObject.getString("image");
Log.e("ImageUrl", imageUrl);
String playlistID = jsonObject.getString("playlistid");
playlist.add(new PlaylistModel(title, playlistID, BASE_IMAGE_URL + imageUrl));
}
ArrayList<AdsListModel> adsList = new ArrayList<>();
adsList.add(new AdsListModel(getString(R.string.ad_id_native_image)));
adsList.add(new AdsListModel(getString(R.string.ad_id_native_video)));
homeAdapter.addList(playlist, adsList);
}
}
Banner Ads
Banner ads are rectangular images that occupy a spot at the top, middle, or bottom within an app layout. Banner ads refresh automatically at regular intervals. When a user clicks a banner ad, the user is usually redirected to the advertiser page.
Here in addBannerAd method bannerView taken from xml. We can integrate programatically. Check the below code
Code:
BannerView bannerView = new BannerView(this);
bannerView.setAdId("testw6vs28auh3");
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_SMART);
AdParam adParam = new AdParam.Builder().build();
bannerView.loadAd(adParam);
RelativeLayout.LayoutParams rLParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
rLParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1);
rlRoot.addView(bannerView, rLParams);
Standard Banner Ad Sizes
The following table lists the standard banner ad sizes.
NOTE :
In the Chinese mainland, only BANNER_SIZE_360_57 and BANNER_SIZE_360_144 are supported.
In the above getSongsFromArray method, We are passing both playlist data and ads data to RecyclerView adapter
with the help of addList method in HomeAdapter
Check below for Native Ad slot id
Code:
<string name="ad_id_native_image">testu7m3hc4gvm</string>
<string name="ad_id_native_video">testy63txaom86</string>
Check the below PlaylistModel class for playlist data
Code:
public class PlaylistModel extends BaseListModel implements Serializable {
String playlistTitle;
String playlistID;
String playlistImage;
public PlaylistModel(String title, String playlistID, String playlistImage) {
this.playlistID = playlistID;
this.playlistImage = playlistImage;
this.playlistTitle = title;
}
public String getPlaylistID() {
return playlistID;
}
public String getPlaylistImage() {
return playlistImage;
}
public String getPlaylistTitle() {
return playlistTitle;
}
}
Check the below code for AdsListModel
Code:
public class AdsListModel extends BaseListModel {
private String adID;
AdsListModel(String ID) {
this.adID = ID;
}
public String getAdID() {
return adID;
}
}
Check the below code for BaseListModel
Code:
public class BaseListModel {
}
After that for showing content item and ad item, Need to create two different layouts. One for actual content and another for ad.
Check the below inflate_home_item.xml for showing actual content
Code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="300dp"
android:layout_height="350dp"
android:layout_margin="10dp"
app:cardBackgroundColor="#000"
app:cardCornerRadius="5dp"
app:cardElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txt_playlist_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="20dp"
android:singleLine="true"
android:text="Prabhas Playlist"
android:textColor="#fff"
android:textSize="16sp" />
<ImageView
android:id="@+id/img_home"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_below="@id/txt_playlist_name"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"
android:transitionName="PlaylistImage" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
More details, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0204417759943370014
Very useful.
Really interesting. Thanks.
Quite helpful.
Quite interesting.
How ad layout behaves when device orientation is changed?
Overview
This application helps us for getting the direction from current location to the selected place. This app uses Huawei Site Kit, Location Kit, Map kit and Huawei Direction API for showing the direction. Let us see the uses of all kits in this application.
Site Kit: This kit is used for getting the places and near-by places on keyword search.
Location Kit: This kit is used for getting the current location of the user.
Map Kit: This kit is used for showing the map, adding a marker and drawing polyline on the Huawei Map.
Direction API: This API is used for getting the path, steps and polyline between two places.
Let us start with the project configuration part:
Step 1: Create an app on App Gallery Connect.
Step 2: Enable the Site Kit, Location Lit and Map Kit in Manage APIs menu.
{
"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"
}
Step 3: Create an Android Project with the same package name as App Gallery project package name.
Step 4: Enter the below maven url inside the repositories of buildscript and allprojects (project build.gradle file).
Java:
maven { url ‘http://developer.huawei.com/repo/’ }
Step 5: Add classpath to project’s build.gradle file.
Java:
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
Step 6: Apply plugin in App’s build.gradle file at top after application plugin.
Java:
apply plugin: 'com.huawei.agconnect'
Step 7: Add below dependencies to app’s build.gradle file.
Java:
implementation 'com.huawei.hms:site:5.0.2.300'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation "androidx.cardview:cardview:1.0.0"
implementation 'com.huawei.hms:maps:4.0.0.302'
implementation 'com.huawei.hms:location:4.0.1.300'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.google.code.gson:gson:2.6.1'
Step 8: Add the app ID generated when the creating the app on HUAWEI Developers to manifest file.
Java:
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=your app id" />
Step 9: Add the below permissions to manifest file.
Java:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
<!-- Allow the app to obtain the coarse longitude and latitude of a user through the Wi-Fi network or base station. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- Allow the app to receive location information from satellites through the GPS chip. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Step 10: Generate SHA 256 key and add to App Gallery Connect Project.
Step 11: download the agconnect-services.json from App Information Section. Copy and paste the Json file in the app folder of the android project.
Step 12: Sync the project.
Let us start with the implementation part:
Part 1: Site Kit Integration
Using the Site Kit, we will search for place and get the latitude and longitude.
Step 1: Get the API_KEY from App Gallery and define the same in your MainActivity.Java.
Java:
public static final String MY_API_KEY = "Your API_KEY will come here";
Step 2: Declare a SearchService object and use SearchServiceFactory to initialize the object.
Java:
// Declare SearchService object
private SearchService searchService;
// Initialize the SearchService object
searchService = SearchServiceFactory.create(this, URLEncoder.encode(MY_API_KEY, "utf-8"));
Step 3: create the layout for search a place.
Java:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="bottom"
android:gravity="center"
android:paddingLeft="5dp"
android:text="Find your place"
android:textSize="18sp"
android:textStyle="bold"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Query: "
android:visibility="gone" />
<EditText
android:id="@+id/edit_text_text_search_query"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:autofillHints=""
android:background="@drawable/search_bg"
android:hint="Search here "
android:imeOptions="actionGo"
android:inputType="text"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp"
android:visibility="visible"/>
</LinearLayout>
<Button
android:id="@+id/button_text_search"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:background="@drawable/search_btn_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="Search"
android:textAllCaps="false"
android:textColor="@color/upsdk_white" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="center"
android:paddingLeft="5dp"
android:text="Note: Get site Id suing Keyword/Nearby/Place suggestion search"
android:textSize="18sp"
android:textStyle="bold"
android:visibility="gone"
android:padding="10dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="bottom"
android:background="#D3D3D3"
android:gravity="center_vertical"
android:paddingLeft="5dp"
android:text="Result"
android:textSize="16sp"
android:visibility="gone" />
<TextView
android:id="@+id/response_text_search"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textIsSelectable="true"
android:padding="10dp"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/searchResultList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:visibility="visible"/>
</LinearLayout>
</LinearLayout>
Step 4: Create the ListAdapter for showing the data.
Java:
public class SearchListAdapter extends RecyclerView.Adapter<SearchListAdapter.SearchViewHolder> {
List<SearchModel> searchModelList;
Context context;
public SearchListAdapter(List<SearchModel> searchModelList, Context context) {
this.searchModelList = searchModelList;
this.context = context;
}
@NonNull
@Override
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new SearchViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.search_result_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull SearchViewHolder holder, final int position) {
final SearchModel searchModel = searchModelList.get(position);
holder.nameTv.setText(searchModel.getName());
holder.formattedAddress.setText(searchModel.getFormattedAddress());
holder.countryCodeTv.setText(searchModel.getCountryCode());
holder.countryTv.setText(searchModel.getCountry());
// Click listener for Row view
holder.btnGetDirection.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context,"Position is "+position,Toast.LENGTH_SHORT ).show();
Intent intent = new Intent(context, DirectionActivity.class);
intent.putExtra("latitude",searchModel.getLatitude());
intent.putExtra("longitude",searchModel.getLongitude());
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return searchModelList.size();
}
class SearchViewHolder extends RecyclerView.ViewHolder {
TextView nameTv;
TextView formattedAddress;
TextView countryTv;
TextView countryCodeTv;
LinearLayout row_layout;
Button btnGetDirection;
public SearchViewHolder(@NonNull View itemView) {
super(itemView);
nameTv = itemView.findViewById(R.id.name);
formattedAddress = itemView.findViewById(R.id.formattedAddress);
countryTv = itemView.findViewById(R.id.country);
countryCodeTv = itemView.findViewById(R.id.countryCode);
row_layout = itemView.findViewById(R.id.row_layout);
btnGetDirection = itemView.findViewById(R.id.get_direction);
}
}
}
Step 5: Create row_layout.xml inside layout folder.
Java:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
app:cardElevation="5dp"
android:layout_marginBottom="3dp">
<LinearLayout
android:id="@+id/row_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Name: "
android:textStyle="bold"
android:layout_weight="0.3"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:paddingLeft="5dp"
android:id="@+id/name"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Address: "
android:textStyle="bold"
android:layout_weight="0.3"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:id="@+id/formattedAddress"
android:layout_weight="0.7"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Country: "
android:textStyle="bold"
android:layout_weight="0.3"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:id="@+id/country"
android:layout_weight="0.7"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Country code: "
android:textStyle="bold"
android:layout_weight="0.3"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/countryCode"
android:paddingLeft="5dp"
android:layout_weight="0.3"/>
<Button
android:id="@+id/get_direction"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_gravity="center"
android:background="@drawable/search_btn_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="Get Direction"
android:textAllCaps="false"
android:textColor="@color/upsdk_white" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
Step 6: Initialize the Recycler view to MainActivity.Java.
Java:
private RecyclerView searchResultList;
searchResultList.setLayoutManager(new LinearLayoutManager(this));
Step 7: On Search button click, search places and set it to ListAdapter.
Java:
mSearchBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
searchModelList = new ArrayList<>();
search();
}
});
Java:
public void search() {
TextSearchRequest textSearchRequest = new TextSearchRequest();
textSearchRequest.setQuery(queryInput.getText().toString());
textSearchRequest.setHwPoiType(HwLocationType.ADDRESS);
textSearchRequest.setHwPoiType(HwLocationType.ENTERTAINMENT_PLACE);
textSearchRequest.setHwPoiType(HwLocationType.INDIAN_RESTAURANT);
textSearchRequest.setHwPoiType(HwLocationType.CITIES);
textSearchRequest.setHwPoiType(HwLocationType.REGIONS);
searchService.textSearch(textSearchRequest, new SearchResultListener<TextSearchResponse>() {
@Override
public void onSearchResult(TextSearchResponse textSearchResponse) {
List<Site> sites = textSearchResponse.getSites();
if (sites == null || sites == null || sites.size() <= 0) {
return;
}
AddressDetail addressDetail;
if (sites != null && sites.size() > 0) {
for (Site site : sites) {
searchModel = new SearchModel();
addressDetail = site.getAddress();
searchModel.setName(site.getName());
searchModel.setFormattedAddress(site.getFormatAddress());
searchModel.setCountry(addressDetail.getCountry());
searchModel.setCountryCode(addressDetail.getCountryCode());
searchModel.setLatitude(site.getLocation().getLat());
searchModel.setLongitude(site.getLocation().getLng());
searchModelList.add(searchModel);
}
SearchListAdapter searchListAdapter = new SearchListAdapter(searchModelList, MainActivity.this);
searchResultList.setAdapter(searchListAdapter);
}
}
Now getting the list of places completed.
Result:
Part 2: Map Kit Implementation
This Kit is being used for showing the Huawei map. After clicking on Get Direction button in searched places, its navigates to DirectionActivity.Java which loads the Huawei map using Map Kit and getting the current location using Huawei Location Kit.
Step 1: Create the xml layout which contains the MapView.
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.huawei.hms.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:mapType="normal"
map:uiCompass="true"/>
</LinearLayout>
Step 2: To use the MapView, implement OnMapReadyCallbackAPI and override the onMapReady(HuaweiMap huaweiMap).
Java:
public class DirectionActivity extends AppCompatActivity implements OnMapReadyCallback{
}
Step 3: Add runtime permissions.
Java:
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
};
if (!hasPermissions(this, RUNTIME_PERMISSIONS)) {
ActivityCompat.requestPermissions(this, RUNTIME_PERMISSIONS, REQUEST_CODE);
}
Java:
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;
}
Step 4: Load MapView inside onCreate() method of DirectionActivity.Java and call getMapAsync() to register the callback.
Java:
private HuaweiMap hMap;
private MapView mMapView;mMapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAP_BUNDLE_KEY);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
Step 5: Inside onMapReady() callback, get the Huawei Map object and set the current location enabled.
Java:
public void onMapReady(HuaweiMap huaweiMap) {
Log.d(TAG, "onMapReady: ");
hMap = huaweiMap;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return;
}
hMap.setMyLocationEnabled(true);
CameraPosition build = new CameraPosition.Builder().target(new LatLng(20.5937, 78.9629)).zoom(4).build();
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(build);
hMap.animateCamera(cameraUpdate);
}
Step 6: Override the onStart(), onStop(),onDestroy(),onPause(), onResume() and onLowMemory() in the DirectionActivity.Java.
Java:
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
Now integration of map done.
Result:
Part 3: Location Kit Integration
This kit is being used for getting the current location of the user.
Step 1: Initialize the current location instances.
Java:
private LocationCallback mLocationCallback;
private LocationRequest mLocationRequest;
private FusedLocationProviderClient fusedLocationProviderClient;
private SettingsClient settingsClient;private double latitude;
private double longitude;
Step 2: call getCurrentLocation() inside onCreate() method of DirectionActivity.Java and save it.
Java:
private void getCurrentLocation(){
//create a fusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
//create a settingsClient
settingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// set the interval for location updates, in milliseconds.
mLocationRequest.setInterval(10000);
// set the priority of the request
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
Location loc = locations.get(0);
latitude = loc.getLatitude();
longitude = loc.getLongitude();
if(count == 0){
count = count + 1;
getRoutes();
}
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Toast.makeText(DirectionActivity.this, "isLocationAvailable:"+flag, Toast.LENGTH_SHORT).show();
}
}
};
}
}
Step 3: call requestLocationUpdatesWithCallback() method after getCurrentLocation()insideonCreate().
Java:
private void requestLocationUpdatesWithCallback() {
try {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// check devices settings before request location updates.
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>()
{
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
// request location updates
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(DirectionActivity.this,"requestLocationUpdatesWithCallback onFailure:",Toast.LENGTH_SHORT).show();
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e)
{
Toast.makeText(DirectionActivity.this,"checkLocationSetting onFailure:",Toast.LENGTH_SHORT).show();
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(DirectionActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Now getting current location part completed.
Part 4: Direction API Implementation
This API is getting used for getting the routes between source and destination location.
Step 1: Get the destination location from place info and save it inside onCreate()method of DirectionActivity.java.
Java:
// Destination location data
private double destLatitude;
private double destLongitude;destLatitude = getIntent().getDoubleExtra("latitude",0.0);
destLongitude = getIntent().getDoubleExtra("longitude",0.0);
Step 2: Create DirectionService.java for getting the routes between source and destination location.
Java:
public class DirectionService {
public static final String ROOT_URL = "https://mapapi.cloud.huawei.com/mapApi/v1/routeService/";
public static final String conection = "?key=";
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
final MutableLiveData<JsonData> jsonData = new MutableLiveData<>();
private String jsonResponse;
public RouteInfo info;
private static DirectionService directionService;
public static DirectionService getInstance(){
if (directionService == null)
directionService = new DirectionService();
return directionService;
}
public void setRouteInfo(RouteInfo info)
{
this.info = info;
}
public void driving(String serviceName, String apiKey, Route route) throws UnsupportedEncodingException {
JSONObject json = new JSONObject();
JSONObject origin = new JSONObject();
JSONObject destination = new JSONObject();
try {
origin.put("lng",route.getOrigin().getLng());
origin.put("lat", route.getOrigin().getLat());
destination.put("lng", route.getDestination().getLng());
destination.put("lat", route.getDestination().getLat());
json.put("origin", origin);
json.put("destination", destination);
} catch (JSONException e) {
Log.e("error", e.getMessage());
}
RequestBody body = RequestBody.create(JSON, String.valueOf(json));
OkHttpClient client = new OkHttpClient();
Request request =
new Request.Builder().url(ROOT_URL + serviceName + conection + URLEncoder.encode(apiKey, "UTF-8"))
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("driving", e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// Log.d("driving", response.body().string());
info.routeInfo(response.body().string());
}
});
}
}
Step 3: Call the getRoute() method inside getCurrentLocation() of DirectionActivity.Java.
Java:
private void getRoutes()
{
// get the routes
Origin origin = new Origin();
origin.setLat(latitude);
origin.setLng(longitude);
Destination dest = new Destination();
dest.setLat(destLatitude);
dest.setLng(destLongitude);
Route route = new Route();
route.setOrigin(origin);
route.setDestination(dest);
try {
DirectionService.getInstance().setRouteInfo(this);
DirectionService.getInstance().driving("driving",MainActivity.MY_API_KEY,route);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Step 4: Create an Interface RouteInfo.
Java:
public interface RouteInfo {
void routeInfo(String info);
}
Step 5: DirectionActivity.Java will implement RouteInfo interface.
Java:
public class DirectionActivity extends AppCompatActivity implements OnMapReadyCallback,RouteInfo{
}
Step 6: Override routeInfo() method and convert string response to Json object using gson library.
Java:
@Override
public void routeInfo(String info) {
Gson gson = new Gson();
JsonData obj = gson.fromJson(info,JsonData.class);
addPolyline(obj);
addMarker();
animateCameraToCurrentLocation();
}
Step 7: Add polyline from the routes info.
Java:
private void addPolyline(JsonData obj) {
if(hMap == null){
return;
}
if (null != mPolyline) {
mPolyline.remove();
mPolyline = null;
}
PolylineOptions options = new PolylineOptions();
if(obj != null){
ArrayList<Routes> routes = obj.getRoutes();
if(routes != null && routes.size() > 0){
ArrayList<Path> paths = routes.get(0).getPaths();
if(paths != null && paths.size() > 0){
ArrayList<Step> steps = paths.get(0).getSteps();
if(steps != null && steps.size() > 0)
{
for(Step step : steps) {
ArrayList<com.huawei.sitekitsampleapp.model.Polyline> polylines = step.getPolyline();
if(polylines != null && polylines.size() > 0){
for(com.huawei.sitekitsampleapp.model.Polyline polyline : polylines){
// Add lat lng to options
options.add(new LatLng(polyline.getLat(),polyline.getLng()));
}
}
}
}
}
}
}
options.color(Color.GREEN).width(3);
mPolyline = hMap.addPolyline(options);
}
Step 8: Add a Marker at destination location.
Java:
private void addMarker() {
if (null != mMarker) {
mMarker.remove();
}
MarkerOptions options = new MarkerOptions()
.position(new LatLng(destLatitude, destLongitude)).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker));
mMarker = hMap.addMarker(options);
}
Step 9: Add marker.xml to drawable folder.
XML:
<vector android:height="24dp" android:tint="#FF1730"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
</vector>
Step 10: Animate camera to current location.
Java:
private void animateCameraToCurrentLocation()
{
CameraPosition build = new CameraPosition.Builder().target(new LatLng(latitude, longitude)).zoom(13).build();
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(build);
hMap.animateCamera(cameraUpdate);
}
Now showing the direction between two place done.
Result:
Tips and Tricks:
Set input properly for origin and Destination for getting the routes.
Conclusion:
This application can help to show the direction between your current location to your favorite place. You can get the restaurants, schools and places and navigate to the same.
Reference:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-References-V5/directions-walking-0000001050161494-V5#EN-US_TOPIC_0000001050161494__section12176172981317
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-sdk-keyword-search-0000001050156630
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-sdk-map-instance-creation-0000001062881706
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/location-develop-steps-0000001050746143