diff --git a/build.gradle b/build.gradle index b98c6f41..f7b7f89c 100644 --- a/build.gradle +++ b/build.gradle @@ -22,16 +22,7 @@ ext { mm_compileSdkVersion = 33 mm_targetSdkVersion = 33 mm_buildToolsVersion = "33.0.0" - mm_androidSdkVersion = "7.3.1" -} - -allprojects { - repositories { - google() - mavenCentral() - // huawei maven - maven { url 'https://developer.huawei.com/repo/' } - } + mm_androidSdkVersion = "7.4.2" } //It's required to be applied here, to have `subprojects.publish` task available @@ -62,6 +53,7 @@ task build {} build.dependsOn tasks.getByPath('infobip-mobile-messaging-huawei-chat-sdk:build') //build.dependsOn tasks.getByPath('infobip-mobile-messaging-huawei-geo-sdk:build') +build.dependsOn tasks.getByPath('infobip-mobile-messaging-huawei-inbox-sdk:build') build.dependsOn tasks.getByPath('infobip-mobile-messaging-huawei-cryptor-migration:build') build.dependsOn tasks.getByPath(':infobip-mobile-messaging-huawei-sdk:build') diff --git a/infobip-mobile-messaging-huawei-chat-sdk/build.gradle b/infobip-mobile-messaging-huawei-chat-sdk/build.gradle index 47952dc4..95d2f870 100644 --- a/infobip-mobile-messaging-huawei-chat-sdk/build.gradle +++ b/infobip-mobile-messaging-huawei-chat-sdk/build.gradle @@ -1,7 +1,7 @@ buildscript { repositories { - mavenCentral() google() + mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:7.2.2' diff --git a/infobip-mobile-messaging-huawei-demo/build.gradle b/infobip-mobile-messaging-huawei-demo/build.gradle index 222a96a1..e7954acc 100644 --- a/infobip-mobile-messaging-huawei-demo/build.gradle +++ b/infobip-mobile-messaging-huawei-demo/build.gradle @@ -96,6 +96,10 @@ android { // geofencing { // dimension "default" // } + inbox { + dimension "default" + } + } } @@ -104,14 +108,15 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.3' implementation project(':infobip-mobile-messaging-huawei-chat-sdk') - // current version of SDK doesn't support geo // implementation project(':infobip-mobile-messaging-huawei-geo-sdk') - implementation ("com.infobip:infobip-mobile-messaging-android-resources:${mm_androidSdkVersion}@aar") implementation project(':infobip-mobile-messaging-huawei-sdk') + implementation project(':infobip-mobile-messaging-huawei-inbox-sdk') implementation "com.infobip:infobip-mobile-messaging-api-java:${mm_androidSdkVersion}" + implementation ("com.infobip:infobip-mobile-messaging-android-resources:${mm_androidSdkVersion}@aar") + // push kit implementation 'com.huawei.hms:push:6.3.0.302' implementation 'androidx.appcompat:appcompat:1.3.1' diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/AndroidManifest.xml b/infobip-mobile-messaging-huawei-demo/src/inbox/AndroidManifest.xml new file mode 100644 index 00000000..7da5d862 --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/Constants.java b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/Constants.java new file mode 100644 index 00000000..28f1670e --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/Constants.java @@ -0,0 +1,8 @@ +package org.infobip.mobile.messaging.demo; + +public class Constants { + public static final String BUNDLE_KEY_DEMO_INBOX = "DEMO_INBOX"; + public static final String BUNDLE_KEY_EXTERNAL_USER_ID = "DEMO_EXTERNAL_USER_ID"; + public static final String SHARED_PREF_KEY = "InfobipDemoPrefs"; + public static final String SHARED_PREF_INBOX_VALUE = "INFOBIP_DEMO_INBOX_VALUE"; +} diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/CustomAdapter.java b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/CustomAdapter.java new file mode 100644 index 00000000..b22098b3 --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/CustomAdapter.java @@ -0,0 +1,83 @@ +package org.infobip.mobile.messaging.demo; + +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.infobip.mobile.messaging.inbox.InboxMessage; + +import java.util.List; + +public class CustomAdapter extends RecyclerView.Adapter { + private List messageTexts; + private OnMessageListener onMessageListener; + + public CustomAdapter(List inboxMessages, OnMessageListener onMessageListener) { + this.messageTexts = inboxMessages; + this.onMessageListener = onMessageListener; + } + + public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final TextView messageText; + private final TextView messageTopic; + + OnMessageListener onMessageListener; + + public ViewHolder(View view, OnMessageListener onMessageListener) { + super(view); + this.onMessageListener = onMessageListener; + view.setOnClickListener(this); + + messageText = view.findViewById(R.id.tv_message_details); + messageTopic = view.findViewById(R.id.tv_message_topic); + } + + @Override + public void onClick(View view) { + onMessageListener.onMessageClick(getAdapterPosition()); + } + + public TextView getMessageTextView() { + return messageText; + } + + public TextView getMessageTopicView() { + return messageTopic; + } + } + + @Override + @NonNull + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.message_details, parent, false); + + return new ViewHolder(v, onMessageListener); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + InboxMessage message = messageTexts.get(position); + String text = "Text: " + message.getBody(); + String topic = "Topic: " + message.getTopic(); + + holder.getMessageTextView().setText(text); + holder.getMessageTopicView().setText(topic); + holder.getMessageTextView() + .setTypeface(null, message.isSeen() ? Typeface.NORMAL : Typeface.BOLD); + } + + @Override + public int getItemCount() { + return messageTexts.size(); + } + + public interface OnMessageListener { + void onMessageClick(int position); + } +} \ No newline at end of file diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/InboxActivity.java b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/InboxActivity.java new file mode 100644 index 00000000..ff64f0ae --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/InboxActivity.java @@ -0,0 +1,198 @@ +package org.infobip.mobile.messaging.demo; + +import android.annotation.SuppressLint; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.google.android.material.tabs.TabLayout; + +import org.infobip.mobile.messaging.MobileMessaging; +import org.infobip.mobile.messaging.inbox.Inbox; +import org.infobip.mobile.messaging.inbox.InboxBundleMapper; +import org.infobip.mobile.messaging.inbox.InboxMessage; +import org.infobip.mobile.messaging.inbox.MobileInbox; +import org.infobip.mobile.messaging.inbox.MobileInboxFilterOptions; +import org.infobip.mobile.messaging.mobileapi.MobileMessagingError; +import org.infobip.mobile.messaging.mobileapi.Result; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InboxActivity extends AppCompatActivity implements CustomAdapter.OnMessageListener { + + private SwipeRefreshLayout swipeLayout; + private TextView counts; + private Button btnBack; + protected RecyclerView mRecyclerView; + protected RecyclerView.LayoutManager mLayoutManager; + protected CustomAdapter mAdapter; + + private Inbox inbox; + private List inboxMessages; + private MobileInbox mobileInbox; + private String externalUserId; + private String topic; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_inbox); + + mRecyclerView = findViewById(R.id.recyclerView); + counts = findViewById(R.id.tv_counts); + swipeLayout = findViewById(R.id.swipeContainer); + swipeLayout.setOnRefreshListener(fetchInboxOnSwipeListener()); + + btnBack = findViewById(R.id.button_second); + btnBack.setOnClickListener(onBackPressedListener()); + + TabLayout tabs = findViewById(R.id.tabs); + + mobileInbox = MobileInbox.getInstance(this); + topic = null; + + Intent intent = getIntent(); + if (intent != null) { + externalUserId = intent.getStringExtra(Constants.BUNDLE_KEY_EXTERNAL_USER_ID); + inbox = Inbox.createFrom(intent.getBundleExtra(Constants.BUNDLE_KEY_DEMO_INBOX)); + } + + inboxMessages = new ArrayList<>(); + if (inbox != null && inbox.getCountTotal() > 0) { + inboxMessages.addAll(inbox.getMessages()); + updateCounterText(); + } else { + counts.setText(R.string.inbox_empty); + } + + mAdapter = new CustomAdapter(inboxMessages, this); + + mLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setAdapter(mAdapter); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.scrollToPosition(0); + + tabs.addTab(tabs.newTab().setText(R.string.tb_all)); + tabs.addTab(tabs.newTab().setText(R.string.tb_promo)); + tabs.addTab(tabs.newTab().setText(R.string.tb_notifications)); + tabs.addOnTabSelectedListener(tabSelectedListener()); + } + + @Override + public void onMessageClick(int i) { + String messageId = inboxMessages.get(i).getMessageId(); + if (inboxMessages.get(i).isSeen()) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setMessage(R.string.mark_as_seen) + .setPositiveButton("YES", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + inboxMessages.get(i).setSeen(); + mobileInbox.setSeen(externalUserId, new String[]{messageId}, new MobileMessaging.ResultListener() { + @SuppressLint("NotifyDataSetChanged") + @Override + public void onResult(Result result) { + if (result.isSuccess()) { + updateCounterText(); + mAdapter.notifyDataSetChanged(); + } + } + }); + } + }).setNegativeButton("NO", (dialog, which) -> {}); + builder.show(); + } + + private void updateCounterText() { + String countsText = String.format("%s messages, %s unread", inbox.getCountTotal(), inbox.getCountUnread()); + counts.setText(countsText); + } + + private TabLayout.OnTabSelectedListener tabSelectedListener() { + return new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + Map topicNameMap = new HashMap<>(); + topicNameMap.put(0, null); + topicNameMap.put(1, "promo"); + topicNameMap.put(2, "notifications"); + + if (inbox != null && inbox.getCountTotal() > 0) { + topic = topicNameMap.get(tab.getPosition()); + updateInboxList(); + } + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + + } + }; + } + + @SuppressLint("NotifyDataSetChanged") + private void updateInboxList() { + inboxMessages.clear(); + for (InboxMessage message : inbox.getMessages()) { + if (topic == null || message.getTopic().equalsIgnoreCase(topic)) { + inboxMessages.add(message); + } + } + mAdapter.notifyDataSetChanged(); + } + + private SwipeRefreshLayout.OnRefreshListener fetchInboxOnSwipeListener() { + MobileInboxFilterOptions filterOptions = new MobileInboxFilterOptions(null, null, topic, null); + return () -> mobileInbox.fetchInbox(externalUserId, filterOptions, new MobileMessaging.ResultListener() { + @Override + public void onResult(Result result) { + if (result.isSuccess()) { + inbox = result.getData(); + if (inbox.getCountTotal() > 0) { + updateInboxList(); + updateCounterText(); + } else { + Toast.makeText(InboxActivity.this, R.string.inbox_empty, Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(InboxActivity.this, R.string.cannot_update_inbox, Toast.LENGTH_SHORT).show(); + } + swipeLayout.setRefreshing(false); + } + }); + } + + private View.OnClickListener onBackPressedListener() { + return new View.OnClickListener() { + @Override + public void onClick(View view) { + Bundle arguments = new Bundle(); + arguments.putBundle(Constants.BUNDLE_KEY_DEMO_INBOX, InboxBundleMapper.inboxToBundle(inbox)); + + Intent intent = new Intent(InboxActivity.this, MainActivity.class); + intent.putExtras(arguments); + InboxActivity.this.startActivity(intent); + } + }; + } +} \ No newline at end of file diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/MainActivity.java b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/MainActivity.java new file mode 100644 index 00000000..e930f095 --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/java/org/infobip/mobile/messaging/demo/MainActivity.java @@ -0,0 +1,254 @@ +package org.infobip.mobile.messaging.demo; + +import static org.infobip.mobile.messaging.util.StringUtils.isBlank; +import static org.infobip.mobile.messaging.util.StringUtils.isNotBlank; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import com.google.android.material.badge.BadgeDrawable; +import com.google.android.material.badge.BadgeUtils; + +import org.infobip.mobile.messaging.Event; +import org.infobip.mobile.messaging.MobileMessaging; +import org.infobip.mobile.messaging.SuccessPending; +import org.infobip.mobile.messaging.User; +import org.infobip.mobile.messaging.UserIdentity; +import org.infobip.mobile.messaging.inbox.Inbox; +import org.infobip.mobile.messaging.inbox.InboxBundleMapper; +import org.infobip.mobile.messaging.inbox.MobileInbox; +import org.infobip.mobile.messaging.inbox.MobileInboxEvent; +import org.infobip.mobile.messaging.mobileapi.MobileMessagingError; +import org.infobip.mobile.messaging.mobileapi.Result; + +public class MainActivity extends AppCompatActivity { + + private EditText etExtUsrId; + private Button btnPersonalize; + private Button btnDepersonalize; + private BadgeDrawable badgeDrawable; + private Button btnToInbox; + + private MobileMessaging mobileMessaging; + private SharedPreferences sharedPref; + private String externalUserId; + private Inbox inbox; + private Boolean receiversRegistered = false; + + private final BroadcastReceiver sdkBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateControls(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + setSupportActionBar(this.findViewById(R.id.toolbar)); + + btnToInbox = findViewById(R.id.btn_to_inbox); + etExtUsrId = findViewById(R.id.etExtUserId); + btnPersonalize = findViewById(R.id.btn_personalize); + btnDepersonalize = findViewById(R.id.btn_depersonalize); + + registerReceivers(); + mobileMessaging = MobileMessaging.getInstance(this); + + // Setting onClick listeners for buttons + btnPersonalize.setOnClickListener(this::onPersonalizeButtonPressed); + btnDepersonalize.setOnClickListener(this::onDepersonalizeButtonPressed); + btnToInbox.setOnClickListener(onToInboxButtonPressed()); + + // Setting the badge + badgeDrawable = BadgeDrawable.create(this); + btnToInbox.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @SuppressLint({"UnsafeOptInUsageError", "UnsafeExperimentalUsageError"}) + @Override + public void onGlobalLayout() { + badgeDrawable.setNumber((inbox == null) ? 0 : inbox.getCountUnread()); + badgeDrawable.setHorizontalOffset(30); + badgeDrawable.setVerticalOffset(20); + BadgeUtils.attachBadgeDrawable(badgeDrawable, btnToInbox, null); + btnToInbox.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + + sharedPref = getSharedPreferences(Constants.SHARED_PREF_KEY, Context.MODE_PRIVATE); + + // Checking if there is inbox in passed arguments from second activity + Intent intent = getIntent(); + if (intent != null) { + Bundle inboxValue = intent.getBundleExtra(Constants.BUNDLE_KEY_DEMO_INBOX); + if (inboxValue != null) { + inbox = Inbox.createFrom(inboxValue); + saveInboxToSharedPref(); + } else { + // Checking if there is a saved inbox in preferences + getInboxFromSharedPref(); + } + } + + // Populating text field with external user id if present + if (isUserPersonalizedWithExternalUserId()) { + externalUserId = mobileMessaging.getUser().getExternalUserId(); + etExtUsrId.setText(externalUserId); + } else { + etExtUsrId.setHint(R.string.extuserid_hint); + } + + updateControls(); + } + + private void getInboxFromSharedPref() { + if (isUserPersonalizedWithExternalUserId()) { + String sharedPrefString = sharedPref.getString(Constants.SHARED_PREF_INBOX_VALUE, ""); + if (isNotBlank(sharedPrefString)) { + inbox = new Inbox().fromString(sharedPrefString); + } + } + } + + private void saveInboxToSharedPref() { + SharedPreferences.Editor sharedPrefEditor = sharedPref.edit() + .putString(Constants.SHARED_PREF_INBOX_VALUE, inbox.toString()); + sharedPrefEditor.commit(); + } + + // Personalizing by external user id provided, then fetching inbox + private void onPersonalizeButtonPressed(View view) { + UserIdentity userIdentity = new UserIdentity(); + String extUserId = etExtUsrId.getText().toString(); + if (isBlank(extUserId)) { + Toast.makeText(MainActivity.this, R.string.cannot_personalize, Toast.LENGTH_SHORT).show(); + return; + } + userIdentity.setExternalUserId(extUserId); + mobileMessaging.personalize(userIdentity, null, new MobileMessaging.ResultListener() { + @Override + public void onResult(Result result) { + externalUserId = extUserId; + Toast.makeText(MainActivity.this, R.string.personalized_success, Toast.LENGTH_SHORT).show(); + prepareInbox(); + } + }); + } + + public void onDepersonalizeButtonPressed(View view) { + //Cleaning up inbox because new user might log in + inbox = new Inbox(); + externalUserId = null; + saveInboxToSharedPref(); + mobileMessaging.depersonalize(new MobileMessaging.ResultListener() { + @Override + public void onResult(Result result) { + Toast.makeText(MainActivity.this, R.string.depersonalized_success, Toast.LENGTH_SHORT).show(); + } + }); + } + + private View.OnClickListener onToInboxButtonPressed() { + return view -> { + // Passing external user id and inbox as arguments to the second activity + Bundle arguments = new Bundle(); + arguments.putString(Constants.BUNDLE_KEY_EXTERNAL_USER_ID, externalUserId); + arguments.putBundle(Constants.BUNDLE_KEY_DEMO_INBOX, InboxBundleMapper.inboxToBundle(inbox)); + + Intent intent = new Intent(MainActivity.this, InboxActivity.class); + intent.putExtras(arguments); + MainActivity.this.startActivity(intent); + }; + } + + private boolean isUserPersonalizedWithExternalUserId() { + if (mobileMessaging.getUser() != null) + return isNotBlank(mobileMessaging.getUser().getExternalUserId()); + return false; + } + + private boolean isPushRegistrationAvailable() { + return mobileMessaging.getInstallation() != null; + } + + private void prepareInbox() { + MobileInbox.getInstance(this).fetchInbox(mobileMessaging.getUser().getExternalUserId(), null, new MobileMessaging.ResultListener() { + @Override + public void onResult(Result result) { + if (result.isSuccess()) { + inbox = result.getData(); + saveInboxToSharedPref(); + updateBadge(); + } + } + }); + } + + // Changing buttons & text field availability + private void updateControls() { + updateBadge(); + etExtUsrId.setEnabled(isPushRegistrationAvailable() && !isUserPersonalizedWithExternalUserId()); + btnPersonalize.setEnabled(!isUserPersonalizedWithExternalUserId()); + btnDepersonalize.setEnabled(isUserPersonalizedWithExternalUserId()); + btnToInbox.setEnabled(isUserPersonalizedWithExternalUserId()); + } + + // Showing count of unread inbox messages + private void updateBadge() { + badgeDrawable.setNumber((inbox == null) ? 0 : inbox.getCountUnread()); + } + + @Override + public void onDestroy() { + unregisterReceivers(); + super.onDestroy(); + } + + @Override + public void onPause() { + unregisterReceivers(); + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + registerReceivers(); + } + + private void registerReceivers() { + if (!receiversRegistered) { + LocalBroadcastManager + .getInstance(this) + .registerReceiver(sdkBroadcastReceiver, new IntentFilter() {{ + addAction(Event.PERSONALIZED.getKey()); + addAction(Event.DEPERSONALIZED.getKey()); + addAction(MobileInboxEvent.INBOX_MESSAGES_FETCHED.getKey()); + }}); + } + this.receiversRegistered = true; + } + + private void unregisterReceivers() { + if (receiversRegistered) { + LocalBroadcastManager + .getInstance(this) + .unregisterReceiver(sdkBroadcastReceiver); + } + this.receiversRegistered = false; + } +} diff --git a/infobip-mobile-messaging-huawei-demo/src/inbox/res/layout/activity_inbox.xml b/infobip-mobile-messaging-huawei-demo/src/inbox/res/layout/activity_inbox.xml new file mode 100644 index 00000000..997788bc --- /dev/null +++ b/infobip-mobile-messaging-huawei-demo/src/inbox/res/layout/activity_inbox.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + +