diff --git a/android/sample/ai-agent-sample/.gitignore b/android/sample/ai-agent-sample/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/android/sample/ai-agent-sample/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/sample/ai-agent-sample/build.gradle.kts b/android/sample/ai-agent-sample/build.gradle.kts new file mode 100644 index 0000000..9e18339 --- /dev/null +++ b/android/sample/ai-agent-sample/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.jetbrains.kotlin.android) + id("com.google.gms.google-services") +} + +val MESSENGER_VERSION: String by project +android { + namespace = "com.sendbird.sdk.aiagent.sample" + compileSdk = 35 + version = MESSENGER_VERSION + + defaultConfig { + applicationId = "com.sendbird.sdk.aiagent.sample" + minSdk = 21 + targetSdk = 35 + versionCode = 1 + versionName = MESSENGER_VERSION + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + signingConfigs { + create("releaseWithSignedKey") { + storeFile = file("../aiagent-sample-keystore") + storePassword = System.getenv("signedKeyPassword") + keyAlias = "sample" + keyPassword = System.getenv("signedKeyPassword") + } + } + + buildTypes { + release { + isMinifyEnabled = true + isShrinkResources = true + signingConfig = signingConfigs.getByName("releaseWithSignedKey") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + buildFeatures { + viewBinding = true + buildConfig = true + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + + api(project(":ai-agent-messenger")) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.activity) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.lifecycle.runtime.ktx) +// implementation(libs.androidx.ui) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + implementation(platform("com.google.firebase:firebase-bom:33.8.0")) +} diff --git a/android/sample/ai-agent-sample/google-services.json b/android/sample/ai-agent-sample/google-services.json new file mode 100644 index 0000000..13215cc --- /dev/null +++ b/android/sample/ai-agent-sample/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "1096745601007", + "project_id": "sb-ai-agent-android", + "storage_bucket": "sb-ai-agent-android.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1096745601007:android:1d288a6178057e6984581a", + "android_client_info": { + "package_name": "com.sendbird.sdk.aiagent.sample" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyCsMqYa0pxUcKf73hjTLLGJ20zWVGZZGKU" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/sample/ai-agent-sample/proguard-rules.pro b/android/sample/ai-agent-sample/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/android/sample/ai-agent-sample/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/android/sample/ai-agent-sample/src/androidTest/java/com/sendbird/sdk/aiagent/sample/ExampleInstrumentedTest.kt b/android/sample/ai-agent-sample/src/androidTest/java/com/sendbird/sdk/aiagent/sample/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..65ed7a2 --- /dev/null +++ b/android/sample/ai-agent-sample/src/androidTest/java/com/sendbird/sdk/aiagent/sample/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.sendbird.sdk.aiagent.sample + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.sendbird.sdk.aiagent.sample", appContext.packageName) + } +} diff --git a/android/sample/ai-agent-sample/src/main/AndroidManifest.xml b/android/sample/ai-agent-sample/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5b4b1e2 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/sample/ai-agent-sample/src/main/ic_launcher-playstore.png b/android/sample/ai-agent-sample/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..a6cc84c Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/ic_launcher-playstore.png differ diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/AgentApplication.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/AgentApplication.kt new file mode 100644 index 0000000..668c2cc --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/AgentApplication.kt @@ -0,0 +1,66 @@ +package com.sendbird.sdk.aiagent.sample + +import android.app.Application +import android.content.res.Configuration +import com.sendbird.android.exception.SendbirdException +import com.sendbird.sdk.aiagent.messenger.AIAgentMessenger +import com.sendbird.sdk.aiagent.messenger.consts.MessengerThemeMode +import com.sendbird.sdk.aiagent.messenger.interfaces.MessengerInitResultHandler +import com.sendbird.sdk.aiagent.messenger.model.MessengerInitParams +import com.sendbird.sdk.aiagent.messenger.model.UserSessionInfo +import com.sendbird.sdk.aiagent.sample.consts.InitState +import com.sendbird.sdk.aiagent.sample.model.SampleAppInfo +import com.sendbird.sdk.aiagent.sample.model.us3 +import com.sendbird.sdk.aiagent.sample.utils.AbstractSessionHandler +import com.sendbird.sdk.aiagent.sample.utils.PreferenceUtils +import com.sendbird.sdk.aiagent.sample.utils.apiHost +import com.sendbird.sdk.aiagent.sample.utils.getCurrentTheme +import com.sendbird.sdk.aiagent.sample.utils.wsHost +import kotlinx.coroutines.flow.MutableStateFlow + +class AgentApplication : Application(), MessengerInitResultHandler { + override fun onCreate() { + super.onCreate() + + PreferenceUtils.init(applicationContext) + val appInfo: SampleAppInfo = PreferenceUtils.sampleAppInfo ?: us3 + AIAgentMessenger.initialize(MessengerInitParams( + context = applicationContext, + appId = appInfo.appId, + theme = applicationContext.getCurrentTheme(), + initResultHandler = this, + apiHost = appInfo.region.apiHost(), + wsHost = appInfo.region.wsHost(), + )) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + + if (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) { + AIAgentMessenger.setThemeMode(MessengerThemeMode.Dark) + } else if (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_NO) { + AIAgentMessenger.setThemeMode(MessengerThemeMode.Light) + } + } + + override fun onInitSuccess() { + PreferenceUtils.manualUserInfo?.let { + val userSessionInfo = UserSessionInfo(it.userId, it.authToken, AbstractSessionHandler()) + AIAgentMessenger.updateSessionInfo(userSessionInfo) + } + initState.value = InitState.SUCCEED + } + + override fun onInitFailure(e: SendbirdException) { + initState.value = InitState.FAILED + } + + override fun onMigrationStarted() { + initState.value = InitState.MIGRATING + } + + companion object { + internal val initState = MutableStateFlow(InitState.NONE) + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/BaseSampleActivity.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/BaseSampleActivity.kt new file mode 100644 index 0000000..6c100b2 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/BaseSampleActivity.kt @@ -0,0 +1,18 @@ +package com.sendbird.sdk.aiagent.sample.activities + +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import com.sendbird.sdk.aiagent.common.extensions.applyAppLocale +import com.sendbird.sdk.aiagent.common.utils.Logger +import java.util.Locale + +open class BaseSampleActivity : AppCompatActivity() { + override fun attachBaseContext(newBase: Context) { + val languageTag = Locale.getDefault().toLanguageTag() + Logger.i("attachBaseContext: languageTag=$languageTag") + if (languageTag.isNotEmpty()) { + val localizedContext = newBase.applyAppLocale(languageTag) + super.attachBaseContext(localizedContext) + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/LoginActivity.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/LoginActivity.kt new file mode 100644 index 0000000..b32f66f --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/LoginActivity.kt @@ -0,0 +1,97 @@ +package com.sendbird.sdk.aiagent.sample.activities + +import android.os.Bundle +import android.widget.Toast +import androidx.lifecycle.lifecycleScope +import com.sendbird.android.SendbirdChat +import com.sendbird.sdk.aiagent.messenger.AIAgentMessenger +import com.sendbird.sdk.aiagent.messenger.model.UserSessionInfo +import com.sendbird.sdk.aiagent.sample.consts.Region +import com.sendbird.sdk.aiagent.sample.databinding.SampleLayoutLoginBinding +import com.sendbird.sdk.aiagent.sample.model.ManualUserInfo +import com.sendbird.sdk.aiagent.sample.model.SampleAppInfo +import com.sendbird.sdk.aiagent.sample.model.us3 +import com.sendbird.sdk.aiagent.sample.model.userNo1 +import com.sendbird.sdk.aiagent.sample.model.userNo2 +import com.sendbird.sdk.aiagent.sample.model.userNo3 +import com.sendbird.sdk.aiagent.sample.model.userNo4 +import com.sendbird.sdk.aiagent.sample.model.userNo5 +import com.sendbird.sdk.aiagent.sample.model.userNo6 +import com.sendbird.sdk.aiagent.sample.model.userUs3 +import com.sendbird.sdk.aiagent.sample.utils.AbstractSessionHandler +import com.sendbird.sdk.aiagent.sample.utils.PreferenceUtils +import com.sendbird.sdk.aiagent.sample.utils.apiHost +import com.sendbird.sdk.aiagent.sample.utils.wsHost +import kotlinx.coroutines.launch + + +class LoginActivity : BaseSampleActivity() { + private val binding by lazy { SampleLayoutLoginBinding.inflate(layoutInflater) } + private val appInfo: SampleAppInfo by lazy { PreferenceUtils.sampleAppInfo ?: us3 } + private val manualUserInfo: ManualUserInfo by lazy { getDefaultAppInfo(appInfo.region) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + with(binding) { + setContentView(root) + setDefaultInformation(this@with, manualUserInfo) + btnSignIn.setOnClickListener { + lifecycleScope.launch { + val userId = etUserId.text.toString() + val authToken = etAuthToken.text.toString() + val context = this@LoginActivity + runCatching { + authenticate(userId, authToken) + }.onFailure { + Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() + } + } + } + } + } + + private fun authenticate(userId: String, authToken: String) { + val userInfo = PreferenceUtils.sampleAppInfo ?: us3 + val apiHost = userInfo.region.apiHost() + val wsHost = userInfo.region.wsHost() + SendbirdChat.connect(userId, authToken, apiHost, wsHost) { _, e -> + if (e != null) { + // Handle error + Toast.makeText(this@LoginActivity, "Error: ${e.message}", Toast.LENGTH_SHORT).show() + return@connect + } else { + PreferenceUtils.manualUserInfo = ManualUserInfo( + userId = userId, + authToken = authToken + ) + AIAgentMessenger.updateSessionInfo(UserSessionInfo( + userId = userId, + sessionToken = authToken, + sessionHandler = AbstractSessionHandler() + )) + finish() + } + } + } + + private fun setDefaultInformation(binding: SampleLayoutLoginBinding, manualUserInfo: ManualUserInfo) { + with(binding) { + with(manualUserInfo) { + etUserId.setText(userId) + etAuthToken.setText(authToken) + } + } + } + + private fun getDefaultAppInfo(region: Region): ManualUserInfo { + return when (region) { + Region.PRODUCTION -> userUs3 + Region.NO1 -> userNo1 + Region.NO2 -> userNo2 + Region.NO3 -> userNo3 + Region.NO4 -> userNo4 + Region.NO5 -> userNo5 + Region.NO6 -> userNo6 + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SelectAppInfoActivity.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SelectAppInfoActivity.kt new file mode 100644 index 0000000..4ca9a70 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SelectAppInfoActivity.kt @@ -0,0 +1,99 @@ +package com.sendbird.sdk.aiagent.sample.activities + +import android.os.Bundle +import android.view.View +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope +import com.sendbird.sdk.aiagent.sample.R +import com.sendbird.sdk.aiagent.sample.consts.Region +import com.sendbird.sdk.aiagent.sample.databinding.SampleLayoutSelectAppInfoBinding +import com.sendbird.sdk.aiagent.sample.model.SampleAppInfo +import com.sendbird.sdk.aiagent.sample.model.no1 +import com.sendbird.sdk.aiagent.sample.model.no2 +import com.sendbird.sdk.aiagent.sample.model.no3 +import com.sendbird.sdk.aiagent.sample.model.no4 +import com.sendbird.sdk.aiagent.sample.model.no5 +import com.sendbird.sdk.aiagent.sample.model.no6 +import com.sendbird.sdk.aiagent.sample.model.us3 +import com.sendbird.sdk.aiagent.sample.utils.PreferenceUtils +import com.sendbird.sdk.aiagent.sample.utils.apiHost +import com.sendbird.sdk.aiagent.sample.utils.awaitInitializeMessenger +import com.sendbird.sdk.aiagent.sample.utils.toRegion +import com.sendbird.sdk.aiagent.sample.utils.wsHost +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SelectAppInfoActivity : BaseSampleActivity() { + private lateinit var appInfo: SampleAppInfo + private val binding by lazy { SampleLayoutSelectAppInfoBinding.inflate(layoutInflater) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + with(binding) { + setContentView(root) + val spinnerItems = resources.getStringArray(R.array.sb_regions) + val myAdapter = ArrayAdapter(this@SelectAppInfoActivity, R.layout.support_simple_spinner_dropdown_item, spinnerItems) + sRegion.adapter = myAdapter + sRegion.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { + (view as TextView).setTextColor(ContextCompat.getColor(this@SelectAppInfoActivity, R.color.black)) + appInfo = getDefaultAppInfo(spinnerItems[position].toRegion(this@SelectAppInfoActivity)) + setDefaultInformation(this@with, appInfo) + } + + override fun onNothingSelected(parent: AdapterView<*>) {} + } + btnSave.setOnClickListener { + val aiAgentId = etAIAgentId.text.toString() + val appId = etAppId.text.toString() + val context = this@SelectAppInfoActivity + val apiHost = appInfo.region.apiHost() + val wsHost = appInfo.region.wsHost() + + lifecycleScope.launch(Dispatchers.Default) { + runCatching { + context.awaitInitializeMessenger(appId, apiHost, wsHost) + + // save local storage + PreferenceUtils.sampleAppInfo = appInfo.copy( + aiAgentId = aiAgentId, + appId = appId + ) + withContext(Dispatchers.Main) { + startActivity(ViewMainActivity.newIntent(this@SelectAppInfoActivity, aiAgentId)) + finish() + } + }.onFailure { + Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() + } + } + } + } + } + + private fun setDefaultInformation(binding: SampleLayoutSelectAppInfoBinding, appInfo: SampleAppInfo) { + with(binding) { + with(appInfo) { + etAppId.setText(appId) + etAIAgentId.setText(aiAgentId) + } + } + } + + private fun getDefaultAppInfo(region: Region): SampleAppInfo { + return when (region) { + Region.PRODUCTION -> us3 + Region.NO1 -> no1 + Region.NO2 -> no2 + Region.NO3 -> no3 + Region.NO4 -> no4 + Region.NO5 -> no5 + Region.NO6 -> no6 + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SplashActivity.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SplashActivity.kt new file mode 100644 index 0000000..5b8e77d --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/SplashActivity.kt @@ -0,0 +1,44 @@ +package com.sendbird.sdk.aiagent.sample.activities + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Bundle +import androidx.lifecycle.lifecycleScope +import com.sendbird.sdk.aiagent.common.utils.Logger +import com.sendbird.sdk.aiagent.messenger.ui.widget.WaitingDialog +import com.sendbird.sdk.aiagent.sample.AgentApplication +import com.sendbird.sdk.aiagent.sample.consts.InitState +import com.sendbird.sdk.aiagent.sample.databinding.SampleLayoutSplashBinding +import com.sendbird.sdk.aiagent.sample.utils.PreferenceUtils +import kotlinx.coroutines.launch + +@SuppressLint("CustomSplashScreen") +class SplashActivity : BaseSampleActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + SampleLayoutSplashBinding.inflate(layoutInflater).apply { + setContentView(root) + } + + lifecycleScope.launch { + AgentApplication.initState.collect { + Logger.i(">> collected, initState: $it") + when (it) { + InitState.NONE -> {} + InitState.MIGRATING -> WaitingDialog.show(this@SplashActivity) + InitState.FAILED, InitState.SUCCEED -> { + WaitingDialog.dismiss() + val appInfo = PreferenceUtils.sampleAppInfo + val intent = if (appInfo == null) { + Intent(this@SplashActivity, SelectAppInfoActivity::class.java) + } else { + ViewMainActivity.newIntent(this@SplashActivity, aiAgentId = appInfo.aiAgentId) + } + startActivity(intent) + finish() + } + } + } + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/ViewMainActivity.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/ViewMainActivity.kt new file mode 100644 index 0000000..9b4dbbe --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/activities/ViewMainActivity.kt @@ -0,0 +1,131 @@ +package com.sendbird.sdk.aiagent.sample.activities + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.View.GONE +import android.view.View.VISIBLE +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.core.view.WindowCompat +import androidx.lifecycle.lifecycleScope +import com.sendbird.sdk.aiagent.common.extensions.addRipple +import com.sendbird.sdk.aiagent.common.extensions.aiAgentId +import com.sendbird.sdk.aiagent.messenger.AIAgentMessenger +import com.sendbird.sdk.aiagent.messenger.BuildConfig +import com.sendbird.sdk.aiagent.messenger.consts.LaunchMode +import com.sendbird.sdk.aiagent.messenger.consts.MessengerEntryPoint +import com.sendbird.sdk.aiagent.messenger.model.LauncherLayoutParams +import com.sendbird.sdk.aiagent.messenger.model.LauncherLocation +import com.sendbird.sdk.aiagent.messenger.model.LauncherMargin +import com.sendbird.sdk.aiagent.messenger.model.LauncherSettingsParams +import com.sendbird.sdk.aiagent.messenger.ui.MessengerLauncher +import com.sendbird.sdk.aiagent.messenger.ui.activity.MessengerActivity +import com.sendbird.sdk.aiagent.sample.R +import com.sendbird.sdk.aiagent.sample.databinding.ActivityViewMainBinding +import com.sendbird.sdk.aiagent.sample.model.us3 +import com.sendbird.sdk.aiagent.sample.utils.PreferenceUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class ViewMainActivity : BaseSampleActivity() { + private lateinit var binding: ActivityViewMainBinding + + private val aiAgentId: String? by lazy { intent.extras.aiAgentId } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityViewMainBinding.inflate(layoutInflater) + setContentView(binding.root) + initMessengerLauncher() + setButtonForFullScreenAiAgent() + initView() + } + + override fun onResume() { + super.onResume() + initManualUserProfile() + drawFingerPrint() + } + + private fun initManualUserProfile() { + with(binding.ivProfile) { + visibility = if (PreferenceUtils.manualUserInfo == null) { + setImageResource(R.drawable.sample_profile_icon) + setOnClickListener { + startActivity(Intent(this@ViewMainActivity, LoginActivity::class.java)) + } + VISIBLE + } else { + GONE + } + addRipple() + } + } + + private fun initMessengerLauncher() { + aiAgentId?.let { + val params = LauncherLayoutParams( + LaunchMode.ANCHORED, + LauncherMargin(12, 12, 12, 12), + LauncherLocation.BOTTOM_END + ) + MessengerLauncher(this, it, LauncherSettingsParams(layoutParams = params)).attach() + } ?: run { + Toast.makeText(this, R.string.aa_text_error_not_found_aiagent_id, Toast.LENGTH_SHORT).show() + finishAffinity() + } + } + + private fun setButtonForFullScreenAiAgent() { + binding.btnViewDemo.setOnClickListener { + aiAgentId?.let { + startActivity(MessengerActivity.newIntentForConversation(this, it)) + } + } + } + + private fun initView() { + lifecycleScope.launch { + window.statusBarColor = ContextCompat.getColor(this@ViewMainActivity, R.color.black_500) + WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = false + binding.btnLogout.setOnClickListener { + lifecycleScope.launch(Dispatchers.IO) { + PreferenceUtils.clearAll() + AIAgentMessenger.deauthenticate() + withContext(Dispatchers.Main) { + finishAffinity() + startActivity(Intent(this@ViewMainActivity, SelectAppInfoActivity::class.java)) + } + } + } + } + } + + private fun drawFingerPrint() { + lifecycleScope.launch { + val fingerPrint = withContext(Dispatchers.IO) { + val region = (PreferenceUtils.sampleAppInfo ?: us3).region.name + val fingerPrint = "${BuildConfig.VERSION_NAME} - [$region]" + + PreferenceUtils.manualUserInfo?.let { + "${fingerPrint}\n${it.userId}" + } ?: fingerPrint + } + + withContext(Dispatchers.Main) { + binding.tvInformation.text = fingerPrint + } + } + } + + companion object { + private const val KEY_AI_AGENT_ID = "KEY_AI_AGENT_ID" + internal fun newIntent(context: Context, aiAgentId: String): Intent { + return Intent(context, ViewMainActivity::class.java).apply { + putExtra(KEY_AI_AGENT_ID, aiAgentId) + } + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/InitState.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/InitState.kt new file mode 100644 index 0000000..13b154a --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/InitState.kt @@ -0,0 +1,26 @@ +package com.sendbird.sdk.aiagent.sample.consts + +/** + * Used with Sendbird AIAgent Messenger initialization. + */ +enum class InitState { + /** + * Indicates the migrating state. + */ + MIGRATING, + + /** + * Indicates the failed state. + */ + FAILED, + + /** + * Indicates the succeeded state. + */ + SUCCEED, + + /** + * Indicates nothing is set. + */ + NONE, +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/KeySet.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/KeySet.kt new file mode 100644 index 0000000..f838900 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/KeySet.kt @@ -0,0 +1,9 @@ +package com.sendbird.sdk.aiagent.sample.consts + +internal object KeySet { + const val region = "region" + const val userId = "userId" + const val authToken = "authToken" + const val appId = "appId" + const val aiAgentId = "aiAgentId" +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/Region.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/Region.kt new file mode 100644 index 0000000..e3dd17b --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/consts/Region.kt @@ -0,0 +1,29 @@ +package com.sendbird.sdk.aiagent.sample.consts + +import com.sendbird.sdk.aiagent.sample.R + +enum class Region(val value: Int) { + PRODUCTION(R.string.sample_region_production), + NO1(R.string.sample_region_no1), + NO2(R.string.sample_region_no2), + NO3(R.string.sample_region_no3), + NO4(R.string.sample_region_no4), + NO5(R.string.sample_region_no5), + NO6(R.string.sample_region_no6) + ; + + companion object { + fun fromValue(value: Int): Region { + return when (value) { + R.string.sample_region_production -> PRODUCTION + R.string.sample_region_no1 -> NO1 + R.string.sample_region_no2 -> NO2 + R.string.sample_region_no3 -> NO3 + R.string.sample_region_no4 -> NO4 + R.string.sample_region_no5 -> NO5 + R.string.sample_region_no6 -> NO6 + else -> PRODUCTION + } + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/ManualUserInfo.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/ManualUserInfo.kt new file mode 100644 index 0000000..2865d1c --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/ManualUserInfo.kt @@ -0,0 +1,68 @@ +package com.sendbird.sdk.aiagent.sample.model + +import com.sendbird.sdk.aiagent.sample.consts.KeySet +import org.json.JSONObject + +internal data class ManualUserInfo( + val userId: String, + val authToken: String, +) { + constructor(json: JSONObject): this( + userId = json.getString(KeySet.userId), + authToken = json.getString(KeySet.authToken), + ) + + constructor(jsonString: String): this(JSONObject(jsonString)) + + fun toJson(): JSONObject { + return JSONObject().apply { + put(KeySet.userId, userId) + put(KeySet.authToken, authToken) + } + } +} + +// dummy +internal val userNo1 = ManualUserInfo( + userId = "", + authToken = "", +) + +// AMT warroom +internal val userNo2 = ManualUserInfo( + userId = "client-user", + authToken = "20670e9154f2828cc864d31df247f41282d2cc62", +) + +// dummy +internal val userNo3 = ManualUserInfo( + userId = "", + authToken = "", +) + +// dummy +internal val userNo4 = ManualUserInfo( + userId = "and-client-user", + authToken = "1c249166d9c177a51b7ea88455c12c09c02d4786", +) + +internal val userNo5 = ManualUserInfo( + userId = "aiagent-test-user", + authToken = "d1d4002af98c4e8654f96efa60c1561cf9162784", +) + +internal val userUs3 = ManualUserInfo( + userId = "client_user", + authToken = "deb776838a0dca710fffd9c38b06ed133e2d088f", +) + +internal val userNo6 = ManualUserInfo( + userId = "chase", + authToken = "e5ac05124214f9b19fce67b0b54051adadca2bc5", +) + +// netflix demo +//internal val userNo6 = ManualUserInfo( +// userId = "tester-user-9e0125dc684c39cbe74463317e0c4e42", +// authToken = "64a73c7fc181f2d89534722c45ef1e5372deb7a2", +//) diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/SampleAppInfo.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/SampleAppInfo.kt new file mode 100644 index 0000000..dba4b7a --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/model/SampleAppInfo.kt @@ -0,0 +1,85 @@ +package com.sendbird.sdk.aiagent.sample.model + +import com.sendbird.sdk.aiagent.sample.consts.KeySet +import com.sendbird.sdk.aiagent.sample.consts.Region +import org.json.JSONObject + +internal data class SampleAppInfo( + val region: Region, + val appId: String, + val aiAgentId: String +) { + constructor(json: JSONObject): this( + region = Region.fromValue(json.getInt(KeySet.region)), + appId = json.getString(KeySet.appId), + aiAgentId = json.getString(KeySet.aiAgentId) + ) + + constructor(jsonString: String): this(JSONObject(jsonString)) + + fun toJson(): JSONObject { + return JSONObject().apply { + put(KeySet.region, region.value) + put(KeySet.appId, appId) + put(KeySet.aiAgentId, aiAgentId) + } + } +} + +// dummy +internal val no1 = SampleAppInfo( + region = Region.NO1, + appId = "", + aiAgentId = "" +) + +// AMT warroom +//internal val no2 = SampleAppInfo( +// region = Region.NO2, +// appId = "D5628A7E-1AA9-4A84-990C-01FD4AF56082", +// aiAgentId = "12010c7c-b1f8-4b3e-91b8-4b688ebe4be7" +//) +internal val no2 = SampleAppInfo( + region = Region.NO2, + appId = "2FE6BC0F-C3E7-4A27-8549-1A49AE6E3406", + aiAgentId = "4uYl0g4Cj3Q51u7vlIPdM" +) + +// dummy +internal val no3 = SampleAppInfo( + region = Region.NO3, + appId = "", + aiAgentId = "" +) + +// dummy +internal val no4 = SampleAppInfo( + region = Region.NO4, + appId = "F347B1F0-18EC-43A6-A12A-9EE38957295F", + aiAgentId = "0aaac811-e891-4a20-acee-d3ad3d4356db" +) + +internal val no5 = SampleAppInfo( + region = Region.NO5, + appId = "5B306480-5E40-40BA-A702-EA0935B4898D", + aiAgentId = "4131e150-1845-417a-976f-15d262c66ad1" +) + +internal val us3 = SampleAppInfo( + region = Region.PRODUCTION, + appId = "10306808-B7F3-436F-9F5C-29F431B47B73", + aiAgentId = "e4c57465-4773-432e-9740-f0284a951494" +) + +internal val no6 = SampleAppInfo( + region = Region.NO6, + appId = "6FBE91A6-32D0-4001-99A1-853971DD180B", + aiAgentId = "7e74ecf7-d544-4582-8375-efd333b86611" +) + +// netflix demo +//internal val no6 = SampleAppInfo( +// region = Region.NO6, +// appId = "D238FFB1-35D3-4749-A0B1-E1B3202501EB", +// aiAgentId = "1ee0c3b3-59b5-48eb-94fe-a17eaa47d145" +//) diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/persists/Preference.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/persists/Preference.kt new file mode 100644 index 0000000..c0e509e --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/persists/Preference.kt @@ -0,0 +1,26 @@ +package com.sendbird.sdk.aiagent.sample.persists + +import android.content.Context +import android.content.SharedPreferences + +internal class Preference(context: Context, fileName: String) { + + fun getString(key: String, defaultValue: String? = null): String? = + pref.getString(key, defaultValue) ?: defaultValue + + fun putString(key: String, value: String) = pref.edit().putString(key, value).apply() + fun getInt(key: String, defaultValue: Int = 0): Int = pref.getInt(key, defaultValue) + fun putInt(key: String, value: Int) = pref.edit().putInt(key, value).apply() + fun getBoolean(key: String, defaultValue: Boolean = false): Boolean = pref.getBoolean(key, defaultValue) + fun putBoolean(key: String, value: Boolean) = pref.edit().putBoolean(key, value).apply() + fun clear() = pref.edit().clear().apply() + fun remove(key: String) = pref.edit().remove(key).apply() + fun contains(key: String): Boolean = pref.contains(key) + + private val pref: SharedPreferences by lazy { + context.getSharedPreferences( + fileName, + Context.MODE_PRIVATE + ) + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/AbstractSessionHandler.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/AbstractSessionHandler.kt new file mode 100644 index 0000000..a5e8f9c --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/AbstractSessionHandler.kt @@ -0,0 +1,15 @@ +package com.sendbird.sdk.aiagent.sample.utils + +import com.sendbird.android.handler.SessionTokenRequester +import com.sendbird.sdk.aiagent.messenger.interfaces.AIAgentSessionHandler +import com.sendbird.sdk.aiagent.common.utils.Logger + +class AbstractSessionHandler : AIAgentSessionHandler() { + override fun onSessionClosed() { + Logger.w("Session closed") + } + + override fun onSessionTokenRequired(sessionTokenRequester: SessionTokenRequester) { + Logger.w("Session token required") + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/Extensions.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/Extensions.kt new file mode 100644 index 0000000..38a0866 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/Extensions.kt @@ -0,0 +1,47 @@ +package com.sendbird.sdk.aiagent.sample.utils + +import android.content.Context +import android.content.res.Configuration +import com.sendbird.android.exception.SendbirdException +import com.sendbird.sdk.aiagent.messenger.AIAgentMessenger +import com.sendbird.sdk.aiagent.messenger.consts.MessengerThemeMode +import com.sendbird.sdk.aiagent.messenger.interfaces.MessengerInitResultHandler +import com.sendbird.sdk.aiagent.messenger.model.MessengerInitParams +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +fun Context.isDarkTheme(): Boolean { + val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + return currentNightMode == Configuration.UI_MODE_NIGHT_YES +} + +fun Context.getCurrentTheme(): MessengerThemeMode { + return if (applicationContext.isDarkTheme()) { + MessengerThemeMode.Dark + } else { + MessengerThemeMode.Light + } +} + +suspend fun Context.awaitInitializeMessenger(appId: String, apiHost: String?, wsHost: String?) = suspendCoroutine { cont -> + AIAgentMessenger.initialize( + MessengerInitParams( + context = this, + appId = appId, + theme = getCurrentTheme(), + initResultHandler = object : MessengerInitResultHandler { + override fun onInitSuccess() { + cont.resume(Unit) + } + + override fun onInitFailure(e: SendbirdException) { + cont.resumeWithException(e) + } + override fun onMigrationStarted() {} + }, + apiHost = apiHost, + wsHost = wsHost + ) + ) +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/PreferenceUtils.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/PreferenceUtils.kt new file mode 100644 index 0000000..30bc33f --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/PreferenceUtils.kt @@ -0,0 +1,29 @@ +package com.sendbird.sdk.aiagent.sample.utils + +import android.content.Context +import com.sendbird.sdk.aiagent.sample.model.SampleAppInfo +import com.sendbird.sdk.aiagent.sample.model.ManualUserInfo +import com.sendbird.sdk.aiagent.sample.persists.Preference + +internal object PreferenceUtils { + private const val PREFERENCE_KEY_MANUAL_USER_INFO = "PREFERENCE_KEY_MANUAL_USER_INFO" + private const val PREFERENCE_KEY_SAMPLE_APP_INFO = "PREFERENCE_KEY_SAMPLE_APP_INFO" + + private lateinit var pref: Preference + + fun init(context: Context) { + pref = Preference(context, "sendbird-ai-agent-sample") + } + + var manualUserInfo: ManualUserInfo? + get() = pref.getString(PREFERENCE_KEY_MANUAL_USER_INFO)?.let { ManualUserInfo(it) } + set(value) = if (value == null) pref.remove(PREFERENCE_KEY_MANUAL_USER_INFO) else pref.putString(PREFERENCE_KEY_MANUAL_USER_INFO, value.toJson().toString()) + + var sampleAppInfo: SampleAppInfo? + get() = pref.getString(PREFERENCE_KEY_SAMPLE_APP_INFO)?.let { SampleAppInfo(it) } + set(value) = if (value == null) pref.remove(PREFERENCE_KEY_SAMPLE_APP_INFO) else pref.putString(PREFERENCE_KEY_SAMPLE_APP_INFO, value.toJson().toString()) + + fun clearAll() { + pref.clear() + } +} diff --git a/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/RegionExtensions.kt b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/RegionExtensions.kt new file mode 100644 index 0000000..762f796 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/java/com/sendbird/sdk/aiagent/sample/utils/RegionExtensions.kt @@ -0,0 +1,44 @@ +package com.sendbird.sdk.aiagent.sample.utils + +import android.content.Context +import com.sendbird.sdk.aiagent.sample.R +import com.sendbird.sdk.aiagent.sample.consts.Region + +fun Region.apiHost(): String? { + return when (this) { + Region.NO1 -> "https://api-no1.sendbirdtest.com" + Region.NO2 -> "https://api-no2.sendbirdtest.com" + Region.NO3 -> "https://api-no3.sendbirdtest.com" + Region.NO4 -> "https://api-no4.sendbirdtest.com" + Region.NO5 -> "https://api-no5.sendbirdtest.com" + Region.NO6 -> "https://api-no6.sendbirdtest.com" + else -> null + } +} + +fun Region.wsHost(): String? { + return when (this) { + Region.NO1 -> "wss://ws-no1.sendbirdtest.com" + Region.NO2 -> "wss://ws-no2.sendbirdtest.com" + Region.NO3 -> "wss://ws-no3.sendbirdtest.com" + Region.NO4 -> "wss://ws-no4.sendbirdtest.com" + Region.NO5 -> "wss://ws-no5.sendbirdtest.com" + Region.NO6 -> "wss://ws-no6.sendbirdtest.com" + else -> null + } +} + +fun String.toRegion(context: Context): Region { + context.let { + return when (this) { + context.getString(R.string.sample_region_production) -> Region.PRODUCTION + context.getString(R.string.sample_region_no1) -> Region.NO1 + context.getString(R.string.sample_region_no2) -> Region.NO2 + context.getString(R.string.sample_region_no3) -> Region.NO3 + context.getString(R.string.sample_region_no4) -> Region.NO4 + context.getString(R.string.sample_region_no5) -> Region.NO5 + context.getString(R.string.sample_region_no6) -> Region.NO6 + else -> Region.PRODUCTION + } + } +} diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_chat.xml b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_chat.xml new file mode 100644 index 0000000..4f3d7e5 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_chat.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_close.xml b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_close.xml new file mode 100644 index 0000000..ed06cd4 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_close.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_logout.xml b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_logout.xml new file mode 100644 index 0000000..dc9a9ba --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_logout.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_menu.xml b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_menu.xml new file mode 100644 index 0000000..4f3d7e5 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable-anydpi/ic_action_menu.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_chat.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_chat.png new file mode 100644 index 0000000..416b210 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_chat.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_close.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_close.png new file mode 100644 index 0000000..ae4927a Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_close.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_logout.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_logout.png new file mode 100644 index 0000000..455dd60 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_logout.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_menu.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_menu.png new file mode 100644 index 0000000..416b210 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/ic_action_menu.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/logo.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/logo.png new file mode 100644 index 0000000..c04c40a Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/logo.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/main_background.png b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/main_background.png new file mode 100644 index 0000000..80ed791 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-hdpi/main_background.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_chat.png b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_chat.png new file mode 100644 index 0000000..7183a82 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_chat.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_close.png b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_close.png new file mode 100644 index 0000000..bb1ffb1 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_close.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_logout.png b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_logout.png new file mode 100644 index 0000000..016dd66 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_logout.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_menu.png b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_menu.png new file mode 100644 index 0000000..7183a82 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-mdpi/ic_action_menu.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/sample/ai-agent-sample/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..7706ab9 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_chat.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_chat.png new file mode 100644 index 0000000..33a29fa Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_chat.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_close.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_close.png new file mode 100644 index 0000000..ed37335 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_close.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_logout.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_logout.png new file mode 100644 index 0000000..16698a2 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_logout.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_menu.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_menu.png new file mode 100644 index 0000000..33a29fa Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/ic_action_menu.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/logo.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/logo.png new file mode 100644 index 0000000..c04c40a Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/logo.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/main_background.png b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/main_background.png new file mode 100644 index 0000000..80ed791 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xhdpi/main_background.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_chat.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_chat.png new file mode 100644 index 0000000..a7e0f0f Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_chat.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_close.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_close.png new file mode 100644 index 0000000..46db467 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_close.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_logout.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_logout.png new file mode 100644 index 0000000..3ef8e1d Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_logout.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_menu.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_menu.png new file mode 100644 index 0000000..a7e0f0f Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/ic_action_menu.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/logo.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/logo.png new file mode 100644 index 0000000..c04c40a Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/logo.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/main_background.png b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/main_background.png new file mode 100644 index 0000000..80ed791 Binary files /dev/null and b/android/sample/ai-agent-sample/src/main/res/drawable-xxhdpi/main_background.png differ diff --git a/android/sample/ai-agent-sample/src/main/res/drawable/ic_launcher_background.xml b/android/sample/ai-agent-sample/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable/sample_profile_icon.xml b/android/sample/ai-agent-sample/src/main/res/drawable/sample_profile_icon.xml new file mode 100644 index 0000000..1e24cf3 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable/sample_profile_icon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/sample/ai-agent-sample/src/main/res/drawable/sample_selector_sign_in_with_user_id_button.xml b/android/sample/ai-agent-sample/src/main/res/drawable/sample_selector_sign_in_with_user_id_button.xml new file mode 100644 index 0000000..d839204 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable/sample_selector_sign_in_with_user_id_button.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_demo_sign_in_edittext_background.xml b/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_demo_sign_in_edittext_background.xml new file mode 100644 index 0000000..77c045c --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_demo_sign_in_edittext_background.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_main_demo_button.xml b/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_main_demo_button.xml new file mode 100644 index 0000000..ebb4ccf --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/drawable/sample_shape_main_demo_button.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/sample/ai-agent-sample/src/main/res/layout/activity_view_main.xml b/android/sample/ai-agent-sample/src/main/res/layout/activity_view_main.xml new file mode 100644 index 0000000..3f08fe1 --- /dev/null +++ b/android/sample/ai-agent-sample/src/main/res/layout/activity_view_main.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + +