Developing a Serverless architecture requires the backend service tools. AppGallery Connect provides these tools such as Cloud Storage, Cloud DB, Cloud Function, and with these common tools we can build up a chat app by enabling our Pay-as-you-go in AppGallery Connect.
Chat app will give you an insight about the Serverless components from Huawei Ecosystem such as Auth Service, Cloud Storage, Cloud DB, and Cloud Functions. Apart from that you will also get an idea about Location Kit, Map Kit, and Site Kit that can be used to the share the location, which is an important feature, on the app. The registration process involves the sign-in with the phone number and the OTP, and the save user profile on the database.
In this codelab we are implementing the following features with HMS kits.
|
Features |
HMS Kits |
Sign in with phone number |
Auth Serivce |
|
Chat with two different people |
Cloud DB |
Share the image |
Cloud Storage and Cloud DB |
|
Push notifications to the user |
Push Kit |
|
Share the current location or nearby landmark. |
Map Kit, Location Kit, and Site Kit |
In this codelab, you will create a chat app demo project, use the APIs of some Huawei services such as Push Kit, Location Kit, Map Kit, Site Kit, Cloud storage, Cloud DB, and learn the MVVM concept. The message and files that can be shared between two different people are stored in the Cloud DB.





Once the site, location, or image is updated, the chat window will
be like this.
A notification is pushed to the person once the message is shared,
as shown in the following screenshot.
Note: To maintain user privacy, we have blurred the portion of the screenshots wherever the user personal information is exposed throughout this document

In this codelab, you will learn how to:
Enable HUAWEI Service(s) in AppGallery Connect:
To integrate HMS Core kits, you must complete the following
preparations:
For details, please refer to
Preparations for Integrating HUAWEI HMS Core.
Go to Project Setting >
Manage APIs, and enable the API permission for the
following kits.
Auth service provides multiple modes of sign-in such as mobile number,
Facebook, and Google. Here we will enable mobile number sign-in mode
so that we can receive the OTP.
Add the following dependancy:
implementation 'com.huawei.agconnect:agconnect-auth:<auth_service_version>'
A verification code is required for mobile number–based registration. The verification code will be sent to the users mobile number to ensure that the mobile number belongs to this user. Call VerifyCodeSettings.Builder to set the verification code, and call AGConnectAuth.requestVerifyCode to request a verification code.
Import required classes for Auth Service.
import com.huawei.agconnect.auth.AGConnectAuth;
import com.huawei.agconnect.auth.PhoneUser;
import com.huawei.agconnect.auth.VerifyCodeResult;
import com.huawei.agconnect.auth.VerifyCodeSettings;
AuthServiceViewModel.java
public void getOTP(String countryCodeStr, String phoneNumberStr) {
VerifyCodeSettings settings = new VerifyCodeSettings.Builder()
.action(VerifyCodeSettings.ACTION_REGISTER_LOGIN)
.sendInterval(30)
.locale(Locale.getDefault())
.build();
Task task = AGConnectAuth.getInstance().requestVerifyCode(countryCodeStr, phoneNumberStr, settings);
task.addOnSuccessListener(TaskExecutors.immediate(), verifyCodeResult -> {
if (null != verifyCodeResult) {
verifyCodeResultMutableLiveData.postValue(verifyCodeResult);
}
});
task.addOnFailureListener(e ->
AppLog.logE(TAG, "onFailure: " + e.getCause()));
}
LoginFragment. Java
Use the following snippnet for the sign-in button.
Util.showProgressBar(getActivity());
bundle.putString(Constants.PHONE_NUMBER, etPhoneNumber.getText().toString());
bundle.putString(Constants.COUNTRY_CODE, "+91");
authServiceViewModel.getOTP("+91", etPhoneNumber.getText().toString());
authServiceViewModel.verifyCodeResultMutableLiveData.observe(requireActivity(), verifyCodeResult -> {
loginPhoneFragmentListener.setLoginPhoneFragmentListener(bundle);
Util.stopProgressBar();
});
} else {
Toast.makeText(requireContext(), "Please enter number", Toast.LENGTH_SHORT).show();
}
AuthServiceViewModel.java
public void verifyContactDetails(String countryCodeStr, String phoneNumberStr, String code) {
PhoneUser = new PhoneUser.Builder()
.setCountryCode(countryCodeStr)
.setPhoneNumber(phoneNumberStr)
.setVerifyCode(code)
.build();
AGConnectAuth.getInstance().createUser(phoneUser)
.addOnSuccessListener(signInResult -> {
if (signInResult != null) {
User user = new User();
user.setUsername(signInResult.getUser().getDisplayName());
user.setPhoneNumber(phoneNumberStr);
userMutableLiveData.postValue(user);
}
})
.addOnFailureListener(e -> {
AppLog.logE(TAG, "verifyContactDetails: " + e.getStackTrace());
User user = new User();
user.setPhoneNumber(phoneNumberStr);
userMutableLiveData.setValue(user);
});
}
LoginWithOTPFragment.java
Util.showProgressBar(getActivity());
Bundle bundle = new Bundle();
bundle.putString(Constants.COUNTRY_CODE, strCountryCode);
bundle.putString(Constants.PHONE_NUMBER, strPhone);
if (otpEditText.length() == 6) {
authServiceViewModel.verifyContactDetails(strCountryCode, strPhone, otpEditText.getText().toString());
authServiceViewModel.userMutableLiveData.observe(requireActivity(), user -> {
if (user != null) {
loginWithOTPFragmentListener.setLoginWithOTPFragmentListener(bundle);
}
Util.stopProgressBar();
});
}
});
If the number is correct:
@Override
public void setLoginWithOTPFragmentListener(Bundle bundle) {
String number = bundle.getString(Constants.PHONE_NUMBER);
Intent intent = new Intent(LoginActivity.this, UserProfileActivity.class);
intent.putExtra(Constants.PHONE_NUMBER, number);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
ActivityCompat.finishAffinity(LoginActivity.this);
}
The app page will be navigated to user profile screen where the user will enter all the details such as name, mobile number and status.
dependencies {
implementation 'com.huawei.agconnect:agconnectdatabase:<cloud_DB_zone>'
}
apply plugin: 'com.huawei.agconnect'
In Java
Create a User class to communicate the user details with Cloud DB.
package com.huawei.chitchatapp.dbcloud;
import com.huawei.agconnect.cloud.database.CloudDBZoneObject;
import com.huawei.agconnect.cloud.database.Text;
import com.huawei.agconnect.cloud.database.annotations.DefaultValue;
import com.huawei.agconnect.cloud.database.annotations.NotNull;
import com.huawei.agconnect.cloud.database.annotations.Indexes;
import com.huawei.agconnect.cloud.database.annotations.PrimaryKeys;
@PrimaryKeys({"user_phone"})
@Indexes({"user_id:user_id", "user_phone_id:user_phone,user_id"})
public final class User extends CloudDBZoneObject {
private Integer user_id;
private String user_phone;
private String user_name;
private String user_status;
private String user_login_status;
private String user_push_token;
private String user_profile_url;
public User() {
super(User.class);
}
public void setUserId(Integer user_id) {
this.user_id = user_id;
}
public Integer getUserId() {
return user_id;
}
public void setUserPhone(String user_phone) {
this.user_phone = user_phone;
}
public String getUserPhone() {
return user_phone;
}
public void setUserName(String user_name) {
this.user_name = user_name;
}
public String getUserName() {
return user_name;
}
public void setUserStatus(String user_status) {
this.user_status = user_status;
}
public String getUserStatus() {
return user_status;
}
public void setUserLoginStatus(String user_login_status) {
this.user_login_status = user_login_status;
}
public String getUserLoginStatus() {
return user_login_status;
}
public void setUserPushToken(String user_push_token) {
this.user_push_token = user_push_token;
}
public String getUserPushToken() {
return user_push_token;
}
public void setUserProfileUrl(String user_profile_url) {
this.user_profile_url = user_profile_url;
}
public String getUserProfileUrl() {
return user_profile_url;
}
}
CloudDBHelper.java
import android.content.Context;
import com.huawei.agconnect.cloud.database.AGConnectCloudDB;
import com.huawei.agconnect.cloud.database.CloudDBZone;
import com.huawei.agconnect.cloud.database.CloudDBZoneConfig;
import com.huawei.agconnect.cloud.database.exceptions.AGConnectCloudDBException;
import com.huawei.chitchatapp.dbcloud.ObjectTypeInfoHelper;
import com.huawei.chitchatapp.utils.AppLog;
import com.huawei.chitchatapp.utils.Constants;
import com.huawei.chitchatapp.utils.OnDBZoneOpen;
import com.huawei.hmf.tasks.Task;
private AGConnectCloudDB agConnectCloudDB;
private CloudDBZone cloudDBZone;
private static final String TAG = CloudDBHelper.class.getSimpleName();
private static CloudDBHelper cloudDBHelper;
public static CloudDBHelper getInstance() {
if (cloudDBHelper == null) {
cloudDBHelper = new CloudDBHelper();
}
return cloudDBHelper;
}
public void init(Context context) {
AGConnectCloudDB.initialize(context);
try {
agConnectCloudDB = AGConnectCloudDB.getInstance();
agConnectCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo());
} catch (AGConnectCloudDBException e) {
e.printStackTrace();
}
}
public void openDb(OnDBZoneOpen onDBZoneOpen) {
CloudDBZoneConfig mConfig = new CloudDBZoneConfig(Constants.DB_ZONE_NAME,
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
mConfig.setPersistenceEnabled(true);
Task openDBZoneTask = agConnectCloudDB.openCloudDBZone2(mConfig, true);
openDBZoneTask.addOnSuccessListener(cloudDBZone -> {
AppLog.logI(TAG, "cloudDBZOne Open");
this.cloudDBZone = cloudDBZone;
onDBZoneOpen.isDBZoneOpen(true, this.cloudDBZone);
}).addOnFailureListener(e -> {
AppLog.logW(TAG, "open cloudDBZone failed for " + e.getMessage());
onDBZoneOpen.isDBZoneOpen(false, null);
});
}
public void closeDb(Context context) {
try {
agConnectCloudDB.closeCloudDBZone(cloudDBZone);
} catch (AGConnectCloudDBException e) {
AppLog.logW(TAG,"close the DBZone "+e.getMessage());
}
}
private void updateProfileData(String name, String status, Uri profileUri) {
ChitChatSharedPref.initializeInstance(UserProfileActivity.this);
User user = new User();
user.setUserId(userId);
user.setUserPushToken(pushToken);
user.setUserPhone(phoneNumber);
user.setUserName(name);
user.setUserLoginStatus(Constants.STATUS_ONLINE);
user.setUserStatus(status);
user.setUserProfileUrl(String.valueOf(profileUri));
userProfile.saveUser(user, UserProfileActivity.this);
userProfile.userMutableLiveData.observe(UserProfileActivity.this, aBoolean -> {
if (aBoolean) {
ChitChatSharedPref.initializeInstance(getApplicationContext());
ChitChatSharedPref.getInstance().putString(Constants.PHONE_NUMBER, phoneNumber);
ChitChatSharedPref.getInstance().putString(Constants.USER_NAME, name);
ChitChatSharedPref.getInstance().putString(Constants.ALREADY_LOGIN, "1");
Toast.makeText(UserProfileActivity.this, getString(R.string.showMessageSuccess), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(UserProfileActivity.this, MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(UserProfileActivity.this, getString(R.string.showMessageFailed), Toast.LENGTH_SHORT).show();
}
});
}
public void saveUser(User user, Context context) {
CloudDBHelper.getInstance().openDb((isConnected, cloudDBZone) -> {
if (isConnected && cloudDBZone != null) {
if (cloudDBZone == null) {
return;
} else {
Task insertTask = cloudDBZone.executeUpsert(user);
insertTask.addOnSuccessListener(integer -> {
userMutableLiveData.setValue(true);
CloudDBHelper.getInstance().closeDb(context);
}).addOnFailureListener(e -> {
userMutableLiveData.setValue(false);
CloudDBHelper.getInstance().closeDb(context);
});
}
}
});
}
Adding the following dependency:
dependencies{
implementation "com.huawei.agconnect:agconnect-storage:"
}
final StorageReference storageReference = ChitChatApplication.getStorageManagement().getStorageReference(fileName + name);
public class ChitChatStorageViewModel extends ViewModel {
private static final String TAG = "ChitChatStorageViewModel";
private MutableLiveData<Uri> uploadFileLiveData;
private OnApiError onApiError;
public LiveData<Uri> uploadFileLiveData() {
if (uploadFileLiveData == null) {
uploadFileLiveData = new MutableLiveData<>();
}
return uploadFileLiveData;
}
public void uploadFile(StorageReference reference, String fileName, File filePath, OnApiError onApiError) {
this.onApiError = onApiError;
UploadTask task = reference.putFile(filePath);
task.addOnSuccessListener(uploadSuccessListener)
.addOnFailureListener(uploadFailureListener);
}
OnSuccessListener<UploadTask.UploadResult> uploadSuccessListener = new OnSuccessListener<UploadTask.UploadResult>() {
@Override
public void onSuccess(UploadTask.UploadResult uploadResult) {
uploadResult.getStorage().getDownloadUrl().addOnSuccessListener(downloadLink)
.addOnFailureListener(downloadUriFailureListener);
}
};
OnSuccessListener<Uri> downloadLink = new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
uploadFileLiveData.postValue(uri);
}
};
OnFailureListener uploadFailureListener = new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (onApiError != null) {
onApiError.onError("Error in uploading file to server", e);
}
}
};
OnFailureListener downloadUriFailureListener = new OnFailureListener() {
@Override
public void onFailure(Exception e) {
onApiError.onError("Failed in getting uri", e);
}
};
}
The following code is the place where we need to upload the file.
public void uploadImage(File path) {
userProfileImage.uploadFileLiveData().observe(UserProfileActivity.this, uri -> {
updateProfileData(mName.getText().toString(), mStatus.getText().toString(), uri);
});
final String name = phoneNumber + ".png";
final StorageReference storageReference = ChitChatApplication.getStorageManagement().getStorageReference("chitchatapp/profile_pic/" + name);
userProfileImage.uploadFile(storageReference,
phoneNumber + ".png", path,
(errorMessage, e) -> AppLog.logE("ProfileFragment", "filePAth--->Error" + e));
}
Push Kit is a messaging service provided for you. It establishes a
messaging channel from the cloud to devices. By integrating Push Kit,
you can send messages to your apps on users' devices in real time.
This helps you maintain closer ties with users and increases user
awareness of and engagement with your apps. The basic process of push
kit is as show in the below image.
Add the following dependency:
dependencies {
implementation 'com.huawei.hms:push:<lastest_push_kit_version>'
}
You need to register service in application in the
AndroidManifest.xml file to receive data messages or
obtain tokens. Service extends the
HmsMessageService class and overrides the methods in
the class. The following uses the service with the class named
DemoHmsMessageService class as an example. You can
customize the class name as needed.
In Android 11, the way for an
app to query other apps on the user device and interact with them is
changed. If targetSdkVersion is 30 or later for your
app, add the queries element in the
manifest element in
AndroidManifest.xml to allow your app to access HMS
Core (APK).
<meta-data
android:name="push_kit_auto_init_enabled"
android:value="true"
/>
The ChitChatPushService class extends the
HmsMessageService class. In ChitChatPushService, the
onNewToken(String token, Bundle bundle) method is
overridden to obtain a token.
If the version of the Push SDK you
integrated is earlier than 5.0.4.302, override the
onNewToken(String token) method.
public class ChitChatPushService extends HmsMessageService {
private static final String TAG = ChitChatPushService.class.getSimpleName();
private static final String CHANNEL1 = "Push_Channel_01";
private Data data = null;
private Bitmap mBitmap;
@Override
public void onNewToken(String s) {
super.onNewToken(s);
}
}
You can use the following code base, which can also be used to retrieve token on android 10 and above. The asynctask can be called in an activity.
public class GetToken extends AsyncTask {
private static final String TAG = GetToken.class.getSimpleName();
@SuppressLint("StaticFieldLeak")
private Context context;
private String appId;
private GetTokenListener getTokenListener;
public GetToken(String appId, Context context) {
this.appId = appId;
this.context = context;
}
public void setGetTokenListener(GetTokenListener getTokenListener) {
this.getTokenListener = getTokenListener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(Void... voids) {
try {
String pushToken = HmsInstanceId.getInstance(context).getToken(appId, HmsMessaging.DEFAULT_TOKEN_SCOPE);
AppLog.logD(TAG, pushToken);
getTokenListener.getToken(pushToken);
return pushToken;
} catch (ApiException e) {
AppLog.logE(TAG,e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
Once the token is retrieved you can implement the following code which will process the notification for message and image notification.
public class ChitChatPushService extends HmsMessageService {
private static final String TAG = ChitChatPushService.class.getSimpleName();
private static final String CHANNEL1 = "Push_Channel_01";
private Data data = null;
private Bitmap mBitmap;
@Override
public void onNewToken(String s) {
super.onNewToken(s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
AppLog.logE(TAG, remoteMessage.getData());
try {
JSONObject jsonObject = new JSONObject(remoteMessage.getData());
data = new Gson().fromJson(jsonObject.toString(), Data.class);
} catch (JSONException e) {
AppLog.logE(TAG,e.getMessage());
}
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(
CHANNEL1, CHANNEL1, importance);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(mChannel);
if (Objects.requireNonNull(remoteMessage.getDataOfMap().get("message")).equalsIgnoreCase(Constants.MESSAGE_TYPE_TEXT)) {
Intent notificationIntent = new Intent(getApplicationContext(), MessageActivity.class);
notificationIntent.putExtra("roomId", remoteMessage.getDataOfMap().get("roomId"));
notificationIntent.putExtra("name",remoteMessage.getDataOfMap().get("sender_name"));
notificationIntent.putExtra("phone",remoteMessage.getDataOfMap().get("sender_phone"));
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0,
notificationIntent, 0);
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL1)
.setSmallIcon(R.drawable.profile)
.setContentTitle(remoteMessage.getDataOfMap().get("sender_name"))
.setContentText(remoteMessage.getDataOfMap().get("message_data"));
mBuilder.setContentIntent(intent);
mBuilder.setAutoCancel(true);
mNotificationManager.notify(0, mBuilder.build());
} else if (Objects.requireNonNull(remoteMessage.getDataOfMap().get("message")).equalsIgnoreCase(Constants.MESSAGE_TYPE_IMAGE)) {
new GeneratePictureStyleNotification(this, data).execute();
} else if (Objects.requireNonNull(remoteMessage.getDataOfMap().get("message")).equalsIgnoreCase(Constants.MESSAGE_TYPE_MAP)) {
Intent notificationIntent = new Intent(getApplicationContext(), MessageActivity.class);
Bundle passBundle = new Bundle();
passBundle.putString("roomId", remoteMessage.getDataOfMap().get("roomId"));
PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0,
notificationIntent, 0);
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL1)
.setSmallIcon(R.drawable.profile)
.setContentTitle(remoteMessage.getDataOfMap().get("sender_name"))
.setContentText(Constants.LOCATION_DATA);
mBuilder.setContentIntent(intent);
mBuilder.setAutoCancel(true);
mNotificationManager.notify(0, mBuilder.build());
}
}
}
}
private class GeneratePictureStyleNotification extends AsyncTask<String, Void, Bitmap< {
Context mContext;
private Data data;
public GeneratePictureStyleNotification(Context context, Data data) {
super();
this.mContext = context;
this.data = data;
}
@Override
protected Bitmap doInBackground(String... params) {
Glide.with(mContext)
.asBitmap()
.load(data.messageData)
.into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition super Bitmap> transition) {
mBitmap = resource;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
showNotification(data);
}
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
}
}
private void showNotification(Data data) {
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
int notificationId = 1;
// String channelName = CHANNEL1;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(
CHANNEL1, CHANNEL1, importance);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(mChannel);
Intent notificationIntent = new Intent(getApplicationContext(), MessageActivity.class);
Bundle passValue = new Bundle();
passValue.putString("roomId", data.getRoomId());
notificationIntent.setAction("android.intent.action.MAIN");
notificationIntent.addCategory("android.intent.category.LAUNCHER");
notificationIntent.putExtras(passValue);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder;
if (mBitmap != null) {
NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle()
.bigPicture(mBitmap);
mBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL1)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getResources().getString(R.string.app_name))
.setLargeIcon(mBitmap)
.setStyle(style)
.setContentText(data.getMessageData());
} else {
mBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL1)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getResources().getString(R.string.app_name))
.setContentText(data.getMessageData());
}
mBuilder.setContentIntent(intent);
mBuilder.setAutoCancel(true);
mNotificationManager.notify(notificationId, mBuilder.build());
}
} else {
Intent notificationIntent = new Intent(getApplicationContext(), MessageActivity.class);
Bundle passValue = new Bundle();
passValue.putString("roomId", data.getRoomId());
notificationIntent.setAction("android.intent.action.MAIN");
notificationIntent.addCategory("android.intent.category.LAUNCHER");
notificationIntent.putExtras(passValue);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (mBitmap != null) {
NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle()
.bigPicture(mBitmap);
mBuilder.setSmallIcon(R.mipmap.ic_launcher).setContentTitle(getString(R.string.app_name))
.setStyle(style)
.setLargeIcon(mBitmap).setAutoCancel(true).setSound(soundUri);
} else {
mBuilder.setSmallIcon(R.mipmap.ic_launcher).setContentTitle(getString(R.string.app_name))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(data.message)).setContentText(data.getMessage()).setAutoCancel(true).setSound(soundUri);
}
mBuilder.setAutoCancel(true);
NotificationCompat.InboxStyle inBoxStyle = new NotificationCompat.InboxStyle();
inBoxStyle.setBigContentTitle(getString(R.string.app_name));
mBuilder.setContentIntent(intent);
mBuilder.setStyle(inBoxStyle);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(notificationId, notification);
}
}
}
The below code will help you to send push notification to others.
public class PushApis {
private Context context;
private static final String TAG = PushApis.class.getSimpleName();
public PushApis(Context context) {
this.context = context;
}
public void sendPushNotification(String chatId, String message, String appId, String messageData, String userPushTokens) {
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String response = "";
URL url = new URL(Constants.TOKEN_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("POST", "/oauth2/v3/token HTTP/1.1");
connection.setRequestProperty("Host", "oauth-login.cloud.huawei.com");
HashMap<String, String> params = new HashMap<>();
params.put("grant_type", "client_credentials");
params.put("client_secret", Constants.CLIENT_SECRET);
params.put("client_id", Constants.CLIENT_ID);
String postDataLength = getDataString(params);
OutputStream os = connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(postDataLength);
writer.flush();
writer.close();
os.close();
int responseCode = connection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = br.readLine()) != null) {
response += line;
}
} else {
response = "";
}
AppLog.logE("Response", response);
Gson gson = new Gson();
BearerRequest bearerRequest = gson.fromJson(response, BearerRequest.class);
triggerPush(bearerRequest.getAccessToken(), appId, chatId, message, messageData, userPushTokens);
} catch (Exception e) {
AppLog.logE(TAG, e.getMessage());
}
}
private String getDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first) {
first = false;
} else {
result.append("&");
}
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return result.toString();
}
private void triggerPush(String bearer, String appId, String chatId, String messageType, String messageData, String userPushTokens) {
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String response = null;
URL url = new URL("https://push-api.cloud.huawei.com/v1/" + appId + "/messages:send");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Authorization", "Bearer " + bearer);
connection.setRequestProperty("Host", "oauth-login.cloud.huawei.com");
connection.setRequestProperty("POST", "/oauth2/v2/token HTTP/1.1");
OutputStream os = connection.getOutputStream();
Data data = new Data();
data.message = messageType;
data.roomId = chatId;
data.messageData = messageData;
data.sender_name = "xxxx xxxx";
data.sender_phone = "xxxxxxxx";
data.title = context.getResources().getString(R.string.app_name);
ArrayList<String> token = new ArrayList<>();
token.add(userPushTokens);
Message message = new Message();
message.tokens = token;
message.data = data.toString();
PushMessageRequest pushMessageRequest = new PushMessageRequest();
pushMessageRequest.message = message;
pushMessageRequest.validate_only = false;
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
Gson gson = new Gson();
JSONObject jsonObject = new JSONObject(gson.toJson(pushMessageRequest, PushMessageRequest.class));
writer.write(jsonObject.toString());
writer.flush();
writer.close();
os.close();
int responseCode = connection.getResponseCode();
String line = null;
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = br.readLine()) != null) {
response += line;
}
AppLog.logE(TAG, response);
} catch (Exception e) {
AppLog.logE(TAG, e.getMessage());
}
}
}
Add the following dependency for Location Kit:
dependencies {
implementation "com.huawei.hms:location:"
}
Add the following permissions to the Manifest file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />;
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Add the runtime permission.
if (checkLocationPermission()) {
Intent intent = new Intent(MessageActivity.this, LocationActivity.class);
launcherForLocation.launch(intent);
} else {
requestPermissionForLocation();
}
Add the check permission for checkLocationPermission() and request premission for requestPermissionforLocation().
checkLocationPermission():
private boolean checkLocationPermission() {
int locationPermission = ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
int coursePermission = ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION);
return locationPermission == PackageManager.PERMISSION_GRANTED && coursePermission == PackageManager.PERMISSION_GRANTED;
}
requestPermissionForLocation():
private void requestPermissionForLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, Constants.LOCATION_PERMISSION);
}
}
Handle the permission.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case Constants.LOCATION_PERMISSION:
if (grantResults.length > 0) {
boolean fineLoc = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean coarseLoc = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (fineLoc && coarseLoc) {
Intent intent = new Intent(MessageActivity.this, LocationActivity.class);
launcherForLocation.launch(intent);
} else {
Toast.makeText(this, getResources().getString(R.string.allow_location_permission), Toast.LENGTH_SHORT).show();
}
}
}
}
public void getCurrentLocation(Context context) {
public void getCurrentLocation(Context context) {
FusedLocationProviderClient mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
SettingsClient mSettingsClient = LocationServices.getSettingsClient(context);
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mFusedLocationProviderClient.getLastLocation().addOnSuccessListener(location -> {
AppLog.logD(TAG,
"Lat long--->Fushed" + location.getLongitude()
+ "," + location.getLatitude() + "," + location.getAccuracy());
if (location != null) {
locationMutableLiveData.postValue(location);
}
}).addOnFailureListener(e -> {
AppLog.logE(TAG, "error" + e.getMessage());
});
}
The blue marker on the map indicatesthe current location.
The Map SDK for Android provides a set of APIs for map development in Android. The map data covers most countries and regions outside the Chinese mainland, and supports multiple languages. Map Kit uses the WGS 84 GPS coordinate system, which can meet most map development requirements outside the Chinese mainland. You can easily add map-related functions in your Android app
1. Sign in to
AppGallery Connect
and click My projects.
2. Find
your project from the project list and click the app for which you
need to enable Map Kit on the project card.
3.
Go to Project settings > Manage APIs and enable Map Kit.
Add the following dependency:
dependencies {
implementation "com.huawei.hms:maps:"
}
<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"/>
<com.huawei.hms.maps.MapView xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
stMapView(savedInstanceState);
}
private void stMapView(Bundle savedInstanceState) {
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(Constants.MAP_VIEW_BUNDLE_KEY);
}
MapsInitializer.setApiKey(Constants.MAP_VIEW_API_KEY);
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
hMap.getUiSettings().setMyLocationButtonEnabled(true);
}
The Site SDK provides place search services that allow your users to use location-based services more conveniently, helping you quickly acquire users. Site Kit provides the following core capabilities for you to quickly build apps with which your users can explore the world around them:
Here we are going to use nearby place search.
Add the following dependency for Site Kit:
dependencies {
implementation "com.huawei.hms:site:<site_kit_lastest_code>'
}
Create a search object.
private SearchService searchService;
try {
searchService = SearchServiceFactory.create(this, URLEncoder.encode(Constants.MAP_VIEW_API_KEY, "utf-8"));
} catch (UnsupportedEncodingException e) {
AppLog.logE(TAG, "encode apikey error");
}
Create the function to access all the nearby areas.
public void getNearbyData(double latitude, double longitude, SearchService searchService, String locationType) {
NearbySearchRequest request = new NearbySearchRequest();
Coordinate location = new Coordinate(latitude, longitude);
request.setLocation(location);
request.setQuery(locationType);
request.setRadius(5);
request.setHwPoiType(HwLocationType.ADDRESS);
request.setLanguage("en");
request.setPageIndex(1);
request.setPageSize(10);
request.setStrictBounds(false);
SearchResultListener<NearbySearchResponse> resultListener = new SearchResultListener<NearbySearchResponse>() {
@Override
public void onSearchResult(NearbySearchResponse results) {
arrayListMutableLiveData.postValue(new ArrayList<>(results.getSites()));
}
@Override
public void onSearchError(SearchStatus status) {
AppLog.logE("TAG", "Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
searchService.nearbySearch(request, resultListener);
}
}
Access the LiveData in the activity after getting the location from the site Kit.
private void updateDetails(Location location) {
float zoom = 14.0f;
LatLng latLng1 = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng1, zoom);
hMap.animateCamera(cameraUpdate);
currentLocationAccuracy.setText(String.format("Accurate to %s meters", location.getAccuracy()));
Util.stopProgressBar();
}
Well done. You have successfully built a Chat app and learned how to:
For more details, please refer to the following official documentations.
Disclaimer: "This codelab is a reference to implement combination of multiple HMS kits in a single project. The developer should verify and ensure the legal and security compliance of the relevant open source code".
You can download the source code here.