From a3313ac8268a0da0eb6af739f23a7ca7f069d6ae Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 3 Aug 2022 13:32:47 +0900 Subject: [PATCH] Added 2.2.6 --- CHANGELOG.md | 6 ++ README.md | 10 +- build.gradle | 8 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 6 +- uikit-custom-sample/build.gradle | 34 ++---- .../src/main/AndroidManifest.xml | 3 +- .../uikit/customsample/HomeActivity.java | 48 +++++++++ .../uikit/customsample/SettingsFragment.java | 89 ++++++++------- .../fcm/MyFirebaseMessagingService.java | 35 +++--- .../openchannel/OpenChannelListFragment.java | 1 + .../community/CreateCommunityActivity.java | 81 +++++++------- .../src/main/res/values-ko-rKR/strings.xml | 21 ++++ .../src/main/res/values/strings.xml | 4 +- uikit-sample/build.gradle | 25 ++--- uikit-sample/src/main/AndroidManifest.xml | 4 +- .../uikit_messaging_android/HomeActivity.java | 48 +++++++++ .../SettingsFragment.java | 90 +++++++++------- .../fcm/MyFirebaseMessagingService.java | 63 ++++------- .../community/CreateCommunityActivity.java | 82 +++++++------- uikit-sample/src/main/res/values/strings.xml | 1 + uikit/build.gradle | 31 +++--- uikit/src/main/AndroidManifest.xml | 8 +- .../adapter/MessageDiffCallback.java | 8 ++ .../uikit/fragments/ChannelFragment.java | 24 +---- .../fragments/ChannelSettingsFragment.java | 12 +-- .../uikit/fragments/ModerationFragment.java | 1 + .../uikit/fragments/OpenChannelFragment.java | 24 +---- .../OpenChannelSettingsFragment.java | 12 +-- .../uikit/fragments/PermissionFragment.java | 101 ++++++++++-------- .../com/sendbird/uikit/utils/IntentUtils.java | 39 +++++-- .../sendbird/uikit/utils/PermissionUtils.java | 41 +++++++ .../com/sendbird/uikit/utils/UserUtils.java | 9 +- .../sendbird/uikit/vm/ChannelViewModel.java | 2 +- .../uikit/vm/OpenChannelViewModel.java | 1 + .../uikit/vm/UserTypeListViewModel.java | 26 +++-- .../uikit/widgets/MyQuotedMessageView.java | 2 +- .../uikit/widgets/OtherQuotedMessageView.java | 4 +- .../sb_view_my_file_message_component.xml | 2 +- 39 files changed, 593 insertions(+), 415 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c2c2a88..e911f4f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +### v2.2.6 (Aug 3, 2022) with Core SDK `v3.1.18` +* Support Android 13 + * Set the `maxSdkVersion` of `android.permission.READ_EXTERNAL_STORAGE` to `32` +* Removed `android.permission.REQUEST_INSTALL_PACKAGES` permission +* Improved stability. + ### v2.2.5 (Mar 29, 2022) with Core SDK `v3.1.9` * Improved stability. diff --git a/README.md b/README.md index fc6badaa..84ecced6 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,10 @@ ## Introduction -The new version of the Sendbird UIKit is now available as the beta. Compared to UIKit v2, UIKit v3 beta features a new modular architecture with more granular components that give you enhanced flexibility to customize your web and mobile apps. Check out our [migration guides](https://github.com/sendbird/sendbird-uikit-android/blob/v3-beta/changelogs/MIGRATIONGUIDE_V3.md) and go visit the [v3 branch](https://github.com/sendbird/sendbird-uikit-android/tree/v3-beta) here. - Sendbird UIKit for Android is a development kit with an user interface that enables an easy and fast integration of standard chat features into new or existing client apps. This repository houses the UIKit source code in addition to two samples as explained below. -- **uikit** is where you can find the open source code. Check out [UIKit Open Source Guidelines](https://github.com/sendbird/sendbird-uikit-android-sources/blob/main/OPENSOURCE_GUIDELINES.md) for more information regarding our stance on open source. -- **uikit-sample** is a chat app with UIKit’s core core features in which you can see items such as push notifications, total unread message count and auto sign-in are demonstrated. When you sign in to the sample app, you will only see a list of channels rendered by the [ChannelListActivity](https://sendbird.com/docs/uikit/v1/android/guides/group-channel#2-list-channels) on the screen. +- **uikit** is where you can find the open source code. Check out [UIKit Open Source Guidelines](https://github.com/sendbird/sendbird-uikit-android-sources/blob/main-v2/OPENSOURCE_GUIDELINES.md) for more information regarding our stance on open source. +- **uikit-sample** is a chat app with UIKit’s core core features in which you can see items such as push notifications, total unread message count and auto sign-in are demonstrated. When you sign in to the sample app, you will only see a list of channels rendered by the [ChannelListActivity](https://sendbird.com/docs/uikit/v1/android/guides/group-channel#2-list-channels) on the screen. - **uikit-custom-sample** is a chat app which contains customizable sample code for the following: * An example of how you can create your own custom message type, for example, a demonstration of sending a message in highlight. * MessageListParams provides various options for retrieving a list of messages with `MessageListParams` @@ -39,7 +37,7 @@ The minimum requirements for UIKit for Android are: ### Try the sample app using your data -If you would like to try the sample app specifically fit to your usage, you can do so by replacing the default sample app ID with yours, which you can obtain by [creating your Sendbird application from the dashboard](https://docs.sendbird.com/android/quick_start#3_install_and_configure_the_chat_sdk_4_step_1_create_a_sendbird_application_from_your_dashboard). Furthermore, you could also add data of your choice on the dashboard to test. This will allow you to experience the sample app with data from your Sendbird application. +If you would like to try the sample app specifically fit to your usage, you can do so by replacing the default sample app ID with yours, which you can obtain by [creating your Sendbird application from the dashboard](https://sendbird.com/docs/chat/v3/android/quickstart/send-first-message#2-before-you-start). Furthermore, you could also add data of your choice on the dashboard to test. This will allow you to experience the sample app with data from your Sendbird application.
@@ -129,4 +127,4 @@ Here is an overview of a list of key components that can be customized on UIKit. |CreateChannel|A component that shows all the users in your client app so you can create a channel. Users can be selected from this component to begin chatting.| |InviteChannel|A component that shows all the users of your client app from the current channel so you can invite other users to join. | |ChannelSettings|A component that changes the channel information.| -|MemberList|A component that shows the list of members who have joined the current channel.| +|MemberList|A component that shows the list of members who have joined the current channel.| \ No newline at end of file diff --git a/build.gradle b/build.gradle index 4be7359b..59695703 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,10 @@ buildscript { repositories { google() - jcenter() - + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.android.tools.build:gradle:7.1.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -17,9 +16,8 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() maven { url "https://jitpack.io" } maven { url "https://repo.sendbird.com/public/maven" } } } - diff --git a/gradle.properties b/gradle.properties index a38f273d..88d6afc4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,6 +17,6 @@ org.gradle.jvmargs=-Xmx1536m android.useAndroidX=true android.enablerD8=true -UIKIT_VERSION = 2.2.5 +UIKIT_VERSION = 2.2.6 UIKIT_VERSION_CODE = 1 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 651ef0e8..c6deadaa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Jan 02 16:41:55 KST 2020 +#Tue Jul 19 13:26:03 KST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/uikit-custom-sample/build.gradle b/uikit-custom-sample/build.gradle index 9071dd3a..d84e2959 100644 --- a/uikit-custom-sample/build.gradle +++ b/uikit-custom-sample/build.gradle @@ -2,25 +2,16 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' android { - compileSdkVersion 30 - buildToolsVersion "29.0.3" + compileSdkVersion 33 defaultConfig { applicationId "com.sendbird.uikit.customsample" minSdkVersion 16 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName "1.0" multiDexEnabled true - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } + buildConfigField "String", "VERSION_NAME", "\"$UIKIT_VERSION\"" } compileOptions { @@ -35,23 +26,16 @@ android { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) -// implementation project(":uikit") - implementation "com.sendbird.sdk:uikit:2.2.5" + implementation project(":uikit") +// implementation "com.sendbird.sdk:uikit:$UIKIT_VERSION" implementation "androidx.multidex:multidex:2.0.1" implementation 'com.google.firebase:firebase-messaging:21.0.0' - - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'com.google.android.material:material:1.2.1' - implementation 'com.github.bumptech.glide:glide:4.11.0' - annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' - - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.github.bumptech.glide:glide:4.13.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0' } \ No newline at end of file diff --git a/uikit-custom-sample/src/main/AndroidManifest.xml b/uikit-custom-sample/src/main/AndroidManifest.xml index a9c447e8..6c05ad46 100644 --- a/uikit-custom-sample/src/main/AndroidManifest.xml +++ b/uikit-custom-sample/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" package="com.sendbird.uikit.customsample"> + - + diff --git a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/HomeActivity.java b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/HomeActivity.java index 550d9ca5..7f15f680 100644 --- a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/HomeActivity.java +++ b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/HomeActivity.java @@ -1,13 +1,24 @@ package com.sendbird.uikit.customsample; +import android.Manifest; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.view.View; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.PermissionChecker; import androidx.databinding.DataBindingUtil; import com.sendbird.android.GroupChannelTotalUnreadMessageCountParams; @@ -22,9 +33,11 @@ import com.sendbird.uikit.customsample.openchannel.OpenChannelMainActivity; import com.sendbird.uikit.customsample.utils.PreferenceUtils; import com.sendbird.uikit.customsample.utils.PushUtils; +import com.sendbird.uikit.utils.ContextUtils; import com.sendbird.uikit.widgets.WaitingDialog; import java.util.List; +import java.util.Locale; import java.util.Map; @@ -32,6 +45,11 @@ public class HomeActivity extends AppCompatActivity { private ActivityHomeBinding binding; private static final String USER_EVENT_HANDLER_KEY = "USER_EVENT_HANDLER_KEY" + System.currentTimeMillis(); + @NonNull + private final ActivityResultLauncher requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}); + @NonNull + private final ActivityResultLauncher appSettingLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), intent -> {}); + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -45,6 +63,18 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { binding.tvUnreadCount.setTextAppearance(this, R.style.SendbirdCaption3OnDark01); binding.tvUnreadCount.setBackgroundResource(R.drawable.shape_badge_background); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + final String permission = Manifest.permission.POST_NOTIFICATIONS; + if (ContextCompat.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED) { + return; + } + if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { + showPermissionRationalePopup(); + return; + } + requestPermissionLauncher.launch(permission); + } } @Override @@ -120,4 +150,22 @@ public void onError(SendBirdException e) { } }); } + + private void showPermissionRationalePopup() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(String.format(Locale.US, getString(R.string.sb_text_need_to_allow_permission_notification), ContextUtils.getApplicationName(this))); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + appSettingLauncher.launch(intent); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); + } } \ No newline at end of file diff --git a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/SettingsFragment.java b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/SettingsFragment.java index e8ee14c0..c7b3f4b3 100644 --- a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/SettingsFragment.java +++ b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/SettingsFragment.java @@ -1,11 +1,12 @@ package com.sendbird.uikit.customsample; +import static android.app.Activity.RESULT_OK; + import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.view.LayoutInflater; @@ -46,10 +47,8 @@ import java.util.Locale; import java.util.TimeZone; -import static android.app.Activity.RESULT_OK; - public class SettingsFragment extends Fragment { - private String[] REQUIRED_PERMISSIONS; + private final String[] REQUIRED_PERMISSIONS = PermissionUtils.CAMERA_PERMISSION; private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 1001; private static final int PERMISSION_SETTINGS_REQUEST_ID = 2000; @@ -61,6 +60,12 @@ public class SettingsFragment extends Fragment { private SwitchCompat disturbSwitch; private Uri mediaUri; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + SendBirdUIKit.connect(null); + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -154,26 +159,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis if (isAllGranted) { showMediaSelectDialog(); - } else { - String[] notGranted = PermissionUtils.getNotGrantedPermissions(getContext(), permissions); - List deniedList = PermissionUtils.getShowRequestPermissionRationale(getActivity(), permissions); - if (deniedList.size() == 0 && getActivity() != null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(getActivity().getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); - builder.setMessage(getPermissionGuildeMessage(getActivity(), notGranted[0])); - builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + getActivity().getPackageName())); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getContext(), com.sendbird.uikit.R.color.secondary_300)); - } } } } @@ -183,15 +168,6 @@ private void initPage(@NonNull View view) { return; } - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } else { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - boolean useDoNotDisturb = true; if (getArguments() != null) { useDoNotDisturb = getArguments().getBoolean(StringSet.SETTINGS_USE_DO_NOT_DISTURB, true); @@ -268,7 +244,7 @@ private void showEditProfileDialog() { return; } - requestPermissions(REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + requestPermission(REQUIRED_PERMISSIONS); } }).showSingle(getFragmentManager()); } @@ -330,7 +306,7 @@ private void showMediaSelectDialog() { if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_camera) { takeCamera(); } else if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_gallery) { - pickImage(); + takePhoto(); } } catch (Exception e) { Logger.e(e); @@ -350,12 +326,12 @@ private void takeCamera() { } } - private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + private void takePhoto() { + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_ACTIVITY_REQUEST_CODE); } - private static String getPermissionGuildeMessage(@NonNull Context context, @NonNull String permission) { + private static String getPermissionGuideMessage(@NonNull Context context, @NonNull String permission) { int textResId; if (Manifest.permission.CAMERA.equals(permission)) { textResId = com.sendbird.uikit.R.string.sb_text_need_to_allow_permission_camera; @@ -364,4 +340,41 @@ private static String getPermissionGuildeMessage(@NonNull Context context, @NonN } return String.format(Locale.US, context.getString(textResId), ContextUtils.getApplicationName(context)); } + + private void requestPermission(@NonNull String[] permissions) { + if (getContext() == null || getActivity() == null) return; + // 1. check permission + final boolean hasPermission = PermissionUtils.hasPermissions(getContext(), permissions); + if (hasPermission) { + showMediaSelectDialog(); + return; + } + + // 2. determine whether rationale popup should show + final List deniedList = PermissionUtils.getExplicitDeniedPermissionList(getActivity(), permissions); + if (!deniedList.isEmpty()) { + showPermissionRationalePopup(deniedList.get(0)); + return; + } + // 3. request permission + requestPermissions(REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + } + + private void showPermissionRationalePopup(@NonNull String permission) { + AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(getPermissionGuideMessage(requireContext(), permission)); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + requireContext().getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), com.sendbird.uikit.R.color.secondary_300)); + } } diff --git a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/fcm/MyFirebaseMessagingService.java b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/fcm/MyFirebaseMessagingService.java index 269bf30a..db0c2cfd 100644 --- a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/fcm/MyFirebaseMessagingService.java +++ b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/fcm/MyFirebaseMessagingService.java @@ -1,21 +1,22 @@ -/** - * Copyright 2016 Google Inc. All Rights Reserved. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + Copyright 2016 Google Inc. All Rights Reserved. +

+ Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

+ http://www.apache.org/licenses/LICENSE-2.0 +

+ Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ package com.sendbird.uikit.customsample.fcm; +import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -82,6 +83,7 @@ public void onMessageReceived(Context context, RemoteMessage remoteMessage) { if (remoteMessage.getData().containsKey(StringSet.sendbird)) { String jsonStr = remoteMessage.getData().get(StringSet.sendbird); SendBird.markAsDelivered(remoteMessage.getData()); + if (jsonStr == null) return; sendNotification(context, new JSONObject(jsonStr)); } } catch (JSONException e) { @@ -115,7 +117,10 @@ public static void sendNotification(@NonNull Context context, @NonNull JSONObjec Intent intent = GroupChannelMainActivity.newRedirectToChannelIntent(context, channelUrl); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent pendingIntent = PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, 0); + @SuppressLint("UnspecifiedImmutableFlag") + PendingIntent pendingIntent = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ? + PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, PendingIntent.FLAG_IMMUTABLE) : + PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, 0); Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID) diff --git a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/OpenChannelListFragment.java b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/OpenChannelListFragment.java index 738daecc..fbadb4de 100644 --- a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/OpenChannelListFragment.java +++ b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/OpenChannelListFragment.java @@ -89,6 +89,7 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); SendBird.addConnectionHandler(CONNECTION_HANDLER_ID, this); + SendBirdUIKit.connect(null); } @Override diff --git a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/community/CreateCommunityActivity.java b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/community/CreateCommunityActivity.java index 2b1258c5..9d938fd1 100644 --- a/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/community/CreateCommunityActivity.java +++ b/uikit-custom-sample/src/main/java/com/sendbird/uikit/customsample/openchannel/community/CreateCommunityActivity.java @@ -5,7 +5,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.Editable; @@ -25,6 +24,7 @@ import com.sendbird.android.OpenChannel; import com.sendbird.android.OpenChannelParams; import com.sendbird.android.SendBird; +import com.sendbird.uikit.SendBirdUIKit; import com.sendbird.uikit.customsample.R; import com.sendbird.uikit.customsample.consts.StringSet; import com.sendbird.uikit.customsample.databinding.ActivityCreateCommunityBinding; @@ -45,7 +45,7 @@ public class CreateCommunityActivity extends AppCompatActivity { - private String[] REQUIRED_PERMISSIONS; + private final String[] REQUIRED_PERMISSIONS = PermissionUtils.CAMERA_PERMISSION; private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 1001; private static final int PERMISSION_SETTINGS_REQUEST_ID = 2000; @@ -75,7 +75,7 @@ protected void onCreate(Bundle savedInstanceState) { return; } - ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + requestPermission(REQUIRED_PERMISSIONS); }); binding.etTitle.addTextChangedListener(new TextWatcher() { @Override @@ -91,15 +91,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { public void afterTextChanged(Editable s) {} }); binding.clearButton.setOnClickListener(v -> binding.etTitle.setText("")); - - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } else { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } + SendBirdUIKit.connect(null); } private void createCommunityChannel() { @@ -171,6 +163,7 @@ private void updateChannelCover() { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERMISSIONS_REQUEST_CODE && grantResults.length == REQUIRED_PERMISSIONS.length) { boolean isAllGranted = true; for (int result : grantResults) { @@ -182,26 +175,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis if (isAllGranted) { showMediaSelectDialog(); - } else { - String[] notGranted = PermissionUtils.getNotGrantedPermissions(this, permissions); - List deniedList = PermissionUtils.getShowRequestPermissionRationale(this, permissions); - if (deniedList.size() == 0) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); - builder.setMessage(getPermissionGuildeMessage(this, notGranted[0])); - builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + getPackageName())); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); - } } } } @@ -224,7 +197,7 @@ private void showMediaSelectDialog() { if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_camera) { takeCamera(); } else if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_gallery) { - pickImage(); + takePhoto(); } else { removeFile(); } @@ -242,8 +215,8 @@ private void takeCamera() { } } - private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + private void takePhoto() { + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_ACTIVITY_REQUEST_CODE); } @@ -253,7 +226,7 @@ private void removeFile() { binding.ivChannelCover.setImageResource(0); } - private static String getPermissionGuildeMessage(@NonNull Context context, @NonNull String permission) { + private static String getPermissionGuideMessage(@NonNull Context context, @NonNull String permission) { int textResId; if (Manifest.permission.CAMERA.equals(permission)) { textResId = com.sendbird.uikit.R.string.sb_text_need_to_allow_permission_camera; @@ -262,4 +235,40 @@ private static String getPermissionGuildeMessage(@NonNull Context context, @NonN } return String.format(Locale.US, context.getString(textResId), ContextUtils.getApplicationName(context)); } + + private void requestPermission(@NonNull String[] permissions) { + // 1. check permission + final boolean hasPermission = PermissionUtils.hasPermissions(this, permissions); + if (hasPermission) { + showMediaSelectDialog(); + return; + } + + // 2. determine whether rationale popup should show + final List deniedList = PermissionUtils.getExplicitDeniedPermissionList(this, permissions); + if (!deniedList.isEmpty()) { + showPermissionRationalePopup(deniedList.get(0)); + return; + } + // 3. request permission + ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + } + + private void showPermissionRationalePopup(@NonNull String permission) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(getPermissionGuideMessage(this, permission)); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); + } } \ No newline at end of file diff --git a/uikit-custom-sample/src/main/res/values-ko-rKR/strings.xml b/uikit-custom-sample/src/main/res/values-ko-rKR/strings.xml index bd96a133..b1162ea8 100644 --- a/uikit-custom-sample/src/main/res/values-ko-rKR/strings.xml +++ b/uikit-custom-sample/src/main/res/values-ko-rKR/strings.xml @@ -170,4 +170,25 @@ 사진 삭제 라이브 %s명 + + + 채널을 나가시겠습니까? + 확인 + %d명 선택 + + SendbirdUIKitCustomSample + Sendbird UIKit Sample + + UI Kit v%1$s      SDK v%2$s + 사용자 ID + 사용자 닉네임 + SIGN IN + + SIGN OUT + Home + Group channel + Open channel + 1 on 1, Group chat with members + Live streams, Open community chat + %s\n푸시 알림을 받기위해 알림설정이 필요합니다. 권한을 받기위해 설정으로 이동하세요. \ No newline at end of file diff --git a/uikit-custom-sample/src/main/res/values/strings.xml b/uikit-custom-sample/src/main/res/values/strings.xml index 1f8968fd..f3ff7809 100644 --- a/uikit-custom-sample/src/main/res/values/strings.xml +++ b/uikit-custom-sample/src/main/res/values/strings.xml @@ -37,8 +37,6 @@ Remove photo LIVE %s participants - Connection must be made. - Couldn\'t update user information. - Couldn\'t update disturb setting. Over 10 messages + %s\nneeds permission to receive push notification. Go to Settings to allow access \ No newline at end of file diff --git a/uikit-sample/build.gradle b/uikit-sample/build.gradle index 901f94a2..6fc95383 100644 --- a/uikit-sample/build.gradle +++ b/uikit-sample/build.gradle @@ -2,22 +2,15 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' android { - compileSdkVersion 30 - buildToolsVersion "29.0.3" + compileSdkVersion 33 defaultConfig { applicationId "com.sendbird.uikit.sample" minSdkVersion 16 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } + buildConfigField "String", "VERSION_NAME", "\"$UIKIT_VERSION\"" } compileOptions { @@ -32,8 +25,8 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) -// implementation project(":uikit") - implementation "com.sendbird.sdk:uikit:2.2.5" + implementation project(":uikit") +// implementation "com.sendbird.sdk:uikit:$UIKIT_VERSION" implementation "androidx.multidex:multidex:2.0.1" implementation 'com.google.firebase:firebase-messaging:21.0.0' @@ -42,10 +35,6 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.appcompat:appcompat:1.2.0' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - - implementation 'com.github.bumptech.glide:glide:4.11.0' - annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' + implementation 'com.github.bumptech.glide:glide:4.13.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0' } diff --git a/uikit-sample/src/main/AndroidManifest.xml b/uikit-sample/src/main/AndroidManifest.xml index 9eb98ca4..66349bab 100644 --- a/uikit-sample/src/main/AndroidManifest.xml +++ b/uikit-sample/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + - + diff --git a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/HomeActivity.java b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/HomeActivity.java index d92046d5..7ff94cc5 100644 --- a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/HomeActivity.java +++ b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/HomeActivity.java @@ -1,13 +1,24 @@ package com.sendbird.uikit_messaging_android; +import android.Manifest; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.view.View; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.PermissionChecker; import androidx.databinding.DataBindingUtil; import com.sendbird.android.GroupChannelTotalUnreadMessageCountParams; @@ -17,6 +28,7 @@ import com.sendbird.android.User; import com.sendbird.uikit.BuildConfig; import com.sendbird.uikit.SendBirdUIKit; +import com.sendbird.uikit.utils.ContextUtils; import com.sendbird.uikit.widgets.WaitingDialog; import com.sendbird.uikit_messaging_android.databinding.ActivityHomeBinding; import com.sendbird.uikit_messaging_android.groupchannel.GroupChannelMainActivity; @@ -25,6 +37,7 @@ import com.sendbird.uikit_messaging_android.utils.PushUtils; import java.util.List; +import java.util.Locale; import java.util.Map; @@ -32,6 +45,11 @@ public class HomeActivity extends AppCompatActivity { private ActivityHomeBinding binding; private static final String USER_EVENT_HANDLER_KEY = "USER_EVENT_HANDLER_KEY" + System.currentTimeMillis(); + @NonNull + private final ActivityResultLauncher requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}); + @NonNull + private final ActivityResultLauncher appSettingLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), intent -> {}); + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -45,6 +63,18 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { binding.tvUnreadCount.setTextAppearance(this, R.style.SendbirdCaption3OnDark01); binding.tvUnreadCount.setBackgroundResource(R.drawable.shape_badge_background); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + final String permission = Manifest.permission.POST_NOTIFICATIONS; + if (ContextCompat.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED) { + return; + } + if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { + showPermissionRationalePopup(); + return; + } + requestPermissionLauncher.launch(permission); + } } @Override @@ -120,4 +150,22 @@ public void onError(SendBirdException e) { } }); } + + private void showPermissionRationalePopup() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(String.format(Locale.US, getString(R.string.sb_text_need_to_allow_permission_notification), ContextUtils.getApplicationName(this))); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + appSettingLauncher.launch(intent); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); + } } \ No newline at end of file diff --git a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/SettingsFragment.java b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/SettingsFragment.java index 07ade538..cd6a3059 100644 --- a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/SettingsFragment.java +++ b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/SettingsFragment.java @@ -1,11 +1,12 @@ package com.sendbird.uikit_messaging_android; +import static android.app.Activity.RESULT_OK; + import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.view.LayoutInflater; @@ -48,10 +49,8 @@ import java.util.Locale; import java.util.TimeZone; -import static android.app.Activity.RESULT_OK; - public class SettingsFragment extends Fragment { - private String[] REQUIRED_PERMISSIONS; + private final String[] REQUIRED_PERMISSIONS = PermissionUtils.CAMERA_PERMISSION; private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 1001; private static final int PERMISSION_SETTINGS_REQUEST_ID = 2000; @@ -61,6 +60,12 @@ public class SettingsFragment extends Fragment { private FragmentSettingsBinding binding; private Uri mediaUri; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + SendBirdUIKit.connect(null); + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -156,26 +161,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis if (isAllGranted) { showMediaSelectDialog(); - } else { - String[] notGranted = PermissionUtils.getNotGrantedPermissions(getContext(), permissions); - List deniedList = PermissionUtils.getShowRequestPermissionRationale(getActivity(), permissions); - if (deniedList.size() == 0 && getActivity() != null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(getActivity().getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); - builder.setMessage(getPermissionGuildeMessage(getActivity(), notGranted[0])); - builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + getActivity().getPackageName())); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getContext(), com.sendbird.uikit.R.color.secondary_300)); - } } } } @@ -185,15 +170,6 @@ private void initPage() { return; } - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } else { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - boolean useHeader = true; boolean useDoNotDisturb = true; if (getArguments() != null) { @@ -313,7 +289,8 @@ private void showEditProfileDialog() { return; } - requestPermissions(REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + if (getActivity() == null) return; + requestPermission(REQUIRED_PERMISSIONS); } }).showSingle(getFragmentManager()); } @@ -407,7 +384,7 @@ private void showMediaSelectDialog() { if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_camera) { takeCamera(); } else if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_gallery) { - pickImage(); + takePhoto(); } } catch (Exception e) { Logger.e(e); @@ -427,12 +404,12 @@ private void takeCamera() { } } - private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + private void takePhoto() { + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_ACTIVITY_REQUEST_CODE); } - private static String getPermissionGuildeMessage(@NonNull Context context, @NonNull String permission) { + private static String getPermissionGuideMessage(@NonNull Context context, @NonNull String permission) { int textResId; if (Manifest.permission.CAMERA.equals(permission)) { textResId = com.sendbird.uikit.R.string.sb_text_need_to_allow_permission_camera; @@ -446,4 +423,41 @@ protected boolean isActive() { boolean isDeactivated = isRemoving() || isDetached() || getContext() == null; return !isDeactivated; } + + private void requestPermission(@NonNull String[] permissions) { + if (getContext() == null || getActivity() == null) return; + // 1. check permission + final boolean hasPermission = PermissionUtils.hasPermissions(getContext(), permissions); + if (hasPermission) { + showMediaSelectDialog(); + return; + } + + // 2. determine whether rationale popup should show + final List deniedList = PermissionUtils.getExplicitDeniedPermissionList(getActivity(), permissions); + if (!deniedList.isEmpty()) { + showPermissionRationalePopup(deniedList.get(0)); + return; + } + // 3. request permission + requestPermissions(REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + } + + private void showPermissionRationalePopup(@NonNull String permission) { + AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(getPermissionGuideMessage(requireContext(), permission)); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + requireContext().getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), com.sendbird.uikit.R.color.secondary_300)); + } } diff --git a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/fcm/MyFirebaseMessagingService.java b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/fcm/MyFirebaseMessagingService.java index 2f03fb18..216664ee 100644 --- a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/fcm/MyFirebaseMessagingService.java +++ b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/fcm/MyFirebaseMessagingService.java @@ -1,21 +1,21 @@ -/** - * Copyright 2016 Google Inc. All Rights Reserved. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + Copyright 2016 Google Inc. All Rights Reserved. +

+ Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

+ http://www.apache.org/licenses/LICENSE-2.0 +

+ Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ - package com.sendbird.uikit_messaging_android.fcm; +import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -26,7 +26,6 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; -import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; @@ -35,9 +34,7 @@ import com.google.firebase.messaging.RemoteMessage; import com.sendbird.android.SendBird; -import com.sendbird.android.SendBirdException; import com.sendbird.android.SendBirdPushHandler; -import com.sendbird.android.SendBirdPushHelper; import com.sendbird.uikit.log.Logger; import com.sendbird.uikit_messaging_android.R; import com.sendbird.uikit_messaging_android.consts.StringSet; @@ -53,10 +50,6 @@ public class MyFirebaseMessagingService extends SendBirdPushHandler { private static final String TAG = "MyFirebaseMsgService"; private static final AtomicReference pushToken = new AtomicReference<>(); - public interface ITokenResult { - void onPushTokenReceived(String pushToken, SendBirdException e); - } - @Override protected boolean isUniquePushToken() { return false; @@ -89,6 +82,7 @@ public void onMessageReceived(Context context, RemoteMessage remoteMessage) { if (remoteMessage.getData().containsKey(StringSet.sendbird)) { String jsonStr = remoteMessage.getData().get(StringSet.sendbird); SendBird.markAsDelivered(remoteMessage.getData()); + if (jsonStr == null) return; sendNotification(context, new JSONObject(jsonStr)); } @@ -123,7 +117,10 @@ public static void sendNotification(@NonNull Context context, @NonNull JSONObjec Intent intent = GroupChannelMainActivity.newRedirectToChannelIntent(context, channelUrl); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent pendingIntent = PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, 0); + @SuppressLint("UnspecifiedImmutableFlag") + PendingIntent pendingIntent = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ? + PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, PendingIntent.FLAG_IMMUTABLE) : + PendingIntent.getActivity(context, channelUrl.hashCode() /* Request code */, intent, 0); Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID) @@ -140,24 +137,4 @@ public static void sendNotification(@NonNull Context context, @NonNull JSONObjec notificationManager.notify(String.valueOf(System.currentTimeMillis()), 0, notificationBuilder.build()); } - - - public static void getPushToken(ITokenResult listener) { - String token = pushToken.get(); - if (!TextUtils.isEmpty(token)) { - listener.onPushTokenReceived(token, null); - return; - } - - SendBirdPushHelper.getPushToken((token1, e) -> { - Log.d(TAG, "FCM token : " + token1); - if (listener != null) { - listener.onPushTokenReceived(token1, e); - } - - if (e == null) { - pushToken.set(token1); - } - }); - } } \ No newline at end of file diff --git a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/openchannel/community/CreateCommunityActivity.java b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/openchannel/community/CreateCommunityActivity.java index 9d4ce28d..3cc26329 100644 --- a/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/openchannel/community/CreateCommunityActivity.java +++ b/uikit-sample/src/main/java/com/sendbird/uikit_messaging_android/openchannel/community/CreateCommunityActivity.java @@ -5,7 +5,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.Editable; @@ -46,7 +45,7 @@ import java.util.Locale; public class CreateCommunityActivity extends AppCompatActivity { - private String[] REQUIRED_PERMISSIONS; + private final String[] REQUIRED_PERMISSIONS = PermissionUtils.CAMERA_PERMISSION; private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 1001; private static final int PERMISSION_SETTINGS_REQUEST_ID = 2000; @@ -77,7 +76,7 @@ protected void onCreate(Bundle savedInstanceState) { return; } - ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + requestPermission(REQUIRED_PERMISSIONS); }); binding.etTitle.addTextChangedListener(new TextWatcher() { @Override @@ -93,19 +92,11 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { public void afterTextChanged(Editable s) {} }); binding.clearButton.setOnClickListener(v -> binding.etTitle.setText("")); - - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } else { - REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } + SendBirdUIKit.connect(null); } private void createCommunityChannel() { - if (TextUtils.isEmpty(binding.etTitle.getText()) || SendBird.getCurrentUser() == null) { + if (TextUtils.isEmpty(binding.etTitle.getText()) || SendBirdUIKit.getAdapter().getUserInfo().getUserId() == null) { return; } @@ -173,6 +164,7 @@ private void updateChannelCover() { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERMISSIONS_REQUEST_CODE && grantResults.length == REQUIRED_PERMISSIONS.length) { boolean isAllGranted = true; for (int result : grantResults) { @@ -184,26 +176,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis if (isAllGranted) { showMediaSelectDialog(); - } else { - String[] notGranted = PermissionUtils.getNotGrantedPermissions(this, permissions); - List deniedList = PermissionUtils.getShowRequestPermissionRationale(this, permissions); - if (deniedList.size() == 0) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); - builder.setMessage(getPermissionGuildeMessage(this, notGranted[0])); - builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + getPackageName())); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); - } } } } @@ -226,7 +198,7 @@ private void showMediaSelectDialog() { if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_camera) { takeCamera(); } else if (key == com.sendbird.uikit.R.string.sb_text_channel_settings_change_channel_image_gallery) { - pickImage(); + takePhoto(); } else { removeFile(); } @@ -244,8 +216,8 @@ private void takeCamera() { } } - private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + private void takePhoto() { + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_ACTIVITY_REQUEST_CODE); } @@ -255,7 +227,7 @@ private void removeFile() { binding.ivChannelCover.setImageResource(0); } - private static String getPermissionGuildeMessage(@NonNull Context context, @NonNull String permission) { + private static String getPermissionGuideMessage(@NonNull Context context, @NonNull String permission) { int textResId; if (Manifest.permission.CAMERA.equals(permission)) { textResId = com.sendbird.uikit.R.string.sb_text_need_to_allow_permission_camera; @@ -264,4 +236,40 @@ private static String getPermissionGuildeMessage(@NonNull Context context, @NonN } return String.format(Locale.US, context.getString(textResId), ContextUtils.getApplicationName(context)); } + + private void requestPermission(@NonNull String[] permissions) { + // 1. check permission + final boolean hasPermission = PermissionUtils.hasPermissions(this, permissions); + if (hasPermission) { + showMediaSelectDialog(); + return; + } + + // 2. determine whether rationale popup should show + final List deniedList = PermissionUtils.getExplicitDeniedPermissionList(this, permissions); + if (!deniedList.isEmpty()) { + showPermissionRationalePopup(deniedList.get(0)); + return; + } + // 3. request permission + ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); + } + + private void showPermissionRationalePopup(@NonNull String permission) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title)); + builder.setMessage(getPermissionGuideMessage(this, permission)); + builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300)); + } } \ No newline at end of file diff --git a/uikit-sample/src/main/res/values/strings.xml b/uikit-sample/src/main/res/values/strings.xml index afbeeb0f..32729763 100644 --- a/uikit-sample/src/main/res/values/strings.xml +++ b/uikit-sample/src/main/res/values/strings.xml @@ -43,4 +43,5 @@ Connection must be made. Couldn\'t update user information. Couldn\'t update disturb setting. + %s\nneeds permission to receive push notification. Go to Settings to allow access diff --git a/uikit/build.gradle b/uikit/build.gradle index 3c8a12c6..e83934b1 100644 --- a/uikit/build.gradle +++ b/uikit/build.gradle @@ -1,17 +1,18 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 30 - buildToolsVersion "29.0.3" + compileSdkVersion 33 version = UIKIT_VERSION defaultConfig { minSdkVersion 16 - targetSdkVersion 30 + targetSdkVersion 33 versionCode Integer.parseInt(UIKIT_VERSION_CODE) versionName UIKIT_VERSION + buildConfigField "String", "VERSION_NAME", "\"$UIKIT_VERSION\"" } + buildTypes { release { debuggable false @@ -40,8 +41,8 @@ android { targetCompatibility = 1.8 } - dataBinding { - enabled = true + buildFeatures { + dataBinding true } packagingOptions { @@ -57,19 +58,15 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // Sendbird - api 'com.sendbird.sdk:sendbird-android-sdk:3.1.9' + api 'com.sendbird.sdk:sendbird-android-sdk:3.1.14' - implementation 'com.github.bumptech.glide:glide:4.11.0' - annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' + implementation 'com.github.bumptech.glide:glide:4.13.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation "androidx.viewpager2:viewpager2:1.0.0" - implementation 'com.google.android.material:material:1.2.1' - - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' -} + implementation 'com.google.android.material:material:1.5.0' +} \ No newline at end of file diff --git a/uikit/src/main/AndroidManifest.xml b/uikit/src/main/AndroidManifest.xml index e4c61694..eae62cc4 100644 --- a/uikit/src/main/AndroidManifest.xml +++ b/uikit/src/main/AndroidManifest.xml @@ -3,13 +3,9 @@ xmlns:tools="http://schemas.android.com/tools" package="com.sendbird.uikit"> - - + + - diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java index de8009cb..b662347e 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java +++ b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java @@ -103,6 +103,14 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return false; } + BaseMessage oldParentMessage = oldMessage.getParentMessage(); + BaseMessage newParentMessage = newMessage.getParentMessage(); + if (oldParentMessage != null && newParentMessage != null) { + if (oldParentMessage.getUpdatedAt() != newParentMessage.getUpdatedAt()) { + return false; + } + } + if (useMessageGroupUI) { BaseMessage oldPrevMessage = oldItemPosition - 1 < 0 ? null : oldMessageList.get(oldItemPosition - 1); BaseMessage newPrevMessage = newItemPosition - 1 < 0 ? null : newMessageList.get(newItemPosition - 1); diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelFragment.java index 5a777a39..8016731d 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelFragment.java @@ -83,6 +83,7 @@ import com.sendbird.uikit.utils.FileUtils; import com.sendbird.uikit.utils.IntentUtils; import com.sendbird.uikit.utils.MessageUtils; +import com.sendbird.uikit.utils.PermissionUtils; import com.sendbird.uikit.utils.ReactionUtils; import com.sendbird.uikit.utils.SoftInputUtils; import com.sendbird.uikit.utils.TextUtils; @@ -826,13 +827,7 @@ public void takeCamera() { checkPermission(PERMISSION_REQUEST_ALL, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.CAMERA_PERMISSION; } @Override @@ -856,11 +851,7 @@ public void takePhoto() { checkPermission(PERMISSION_REQUEST_STORAGE, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override @@ -881,11 +872,7 @@ public void takeFile() { checkPermission(PERMISSION_REQUEST_STORAGE, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override @@ -1389,8 +1376,7 @@ protected void saveFileMessage(@NonNull FileMessage message) { @Override @NonNull public String[] getPermissions(int requestCode) { - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelSettingsFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelSettingsFragment.java index fde8edb3..2a212423 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelSettingsFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/ChannelSettingsFragment.java @@ -44,6 +44,7 @@ import com.sendbird.uikit.utils.DialogUtils; import com.sendbird.uikit.utils.FileUtils; import com.sendbird.uikit.utils.IntentUtils; +import com.sendbird.uikit.utils.PermissionUtils; import com.sendbird.uikit.utils.TextUtils; import com.sendbird.uikit.widgets.ChannelSettingsView; @@ -207,18 +208,13 @@ public void onDestroy() { } private boolean isCurrentChannel(@NonNull String channelUrl) { + if (channel == null) return false; return channelUrl.equals(channel.getUrl()); } @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.CAMERA_PERMISSION; } @Override @@ -397,7 +393,7 @@ private void takeCamera() { } private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_PERMISSIONS_REQUEST_CODE); } diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/ModerationFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/ModerationFragment.java index 37e5a66c..54fa4eb5 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/ModerationFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/ModerationFragment.java @@ -168,6 +168,7 @@ public void onDestroy() { } private boolean isCurrentChannel(@NonNull String channelUrl) { + if (channel == null) return false; return channelUrl.equals(channel.getUrl()); } diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelFragment.java index 83e7cebc..b5383786 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelFragment.java @@ -69,6 +69,7 @@ import com.sendbird.uikit.utils.FileUtils; import com.sendbird.uikit.utils.IntentUtils; import com.sendbird.uikit.utils.MessageUtils; +import com.sendbird.uikit.utils.PermissionUtils; import com.sendbird.uikit.utils.SoftInputUtils; import com.sendbird.uikit.utils.TextUtils; import com.sendbird.uikit.vm.FileDownloader; @@ -583,13 +584,7 @@ public void takeCamera() { checkPermission(PERMISSION_REQUEST_ALL, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.CAMERA_PERMISSION; } @Override @@ -613,11 +608,7 @@ public void takePhoto() { checkPermission(PERMISSION_REQUEST_STORAGE, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override @@ -638,11 +629,7 @@ public void takeFile() { checkPermission(PERMISSION_REQUEST_STORAGE, new IPermissionHandler() { @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override @@ -1051,8 +1038,7 @@ protected void saveFileMessage(@NonNull FileMessage message) { @Override @NonNull public String[] getPermissions(int requestCode) { - return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.GET_CONTENT_PERMISSION; } @Override diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelSettingsFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelSettingsFragment.java index eb51d4c7..890f10ee 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelSettingsFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/OpenChannelSettingsFragment.java @@ -37,6 +37,7 @@ import com.sendbird.uikit.utils.DialogUtils; import com.sendbird.uikit.utils.FileUtils; import com.sendbird.uikit.utils.IntentUtils; +import com.sendbird.uikit.utils.PermissionUtils; import com.sendbird.uikit.utils.TextUtils; import com.sendbird.uikit.widgets.OpenChannelSettingsView; @@ -187,18 +188,13 @@ public void onDestroy() { } private boolean isCurrentChannel(@NonNull String channelUrl) { + if (channel == null) return false; return channelUrl.equals(channel.getUrl()); } @Override public String[] getPermissions(int requestCode) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } - return new String[]{Manifest.permission.CAMERA, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; + return PermissionUtils.CAMERA_PERMISSION; } @Override @@ -336,7 +332,7 @@ private void takeCamera() { } private void pickImage() { - Intent intent = IntentUtils.getGalleryIntent(); + Intent intent = IntentUtils.getImageGalleryIntent(); startActivityForResult(intent, PICK_IMAGE_PERMISSIONS_REQUEST_CODE); } diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/PermissionFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/PermissionFragment.java index 42b0ed9f..9d7a4e21 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/PermissionFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/PermissionFragment.java @@ -1,5 +1,7 @@ package com.sendbird.uikit.fragments; +import static android.app.Activity.RESULT_OK; + import android.Manifest; import android.app.Activity; import android.content.Context; @@ -7,16 +9,16 @@ import android.content.pm.PackageManager; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.Build; import android.provider.Settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; import com.sendbird.uikit.R; @@ -26,8 +28,6 @@ import java.util.List; import java.util.Locale; -import static android.app.Activity.RESULT_OK; - public abstract class PermissionFragment extends Fragment { interface IPermissionHandler { String[] getPermissions(int requestCode); @@ -39,18 +39,33 @@ interface IPermissionHandler { private final int PERMISSION_SETTINGS_REQUEST_ID = 100; void checkPermission(int requestCode, @NonNull IPermissionHandler handler) { + if (getContext() == null || getActivity() == null) return; this.requestCode = requestCode; this.handler = handler; final String[] permissions = handler.getPermissions(requestCode); + // 1. check permission final boolean hasPermission = PermissionUtils.hasPermissions(getContext(), permissions); if (hasPermission) { - handler.onPermissionGranted(requestCode); + notifyPermissionResult(handler); + return; + } + + // 2. determine whether rationale popup should show + final List deniedList = PermissionUtils.getExplicitDeniedPermissionList(getActivity(), permissions); + if (!deniedList.isEmpty()) { + showPermissionRationalePopup(deniedList.get(0)); return; } requestPermissions(permissions, requestCode); } + private void notifyPermissionResult(@Nullable IPermissionHandler handler) { + if (handler != null) { + handler.onPermissionGranted(requestCode); + } + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { final String[] requested = handler.getPermissions(requestCode); @@ -64,31 +79,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } if (isAllGranted) { - handler.onPermissionGranted(requestCode); - } else { - String[] notGranted = PermissionUtils.getNotGrantedPermissions(getContext(), permissions); - List deniedList = PermissionUtils.getShowRequestPermissionRationale(getActivity(), permissions); - if (deniedList != null && deniedList.size() == 0) { - Drawable icon = getPermissionDrawable(getActivity(), notGranted[0]); - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(getActivity().getString(R.string.sb_text_dialog_permission_title)); - builder.setMessage(getPermissionGuideMessage(getActivity(), notGranted[0])); - if (icon != null) { - builder.setIcon(icon); - } - builder.setPositiveButton(R.string.sb_text_go_to_settings, (dialogInterface, i) -> { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + getActivity().getPackageName())); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getContext(), R.color.secondary_300)); - } + notifyPermissionResult(handler); } } } @@ -101,38 +92,56 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d String[] permissions = handler.getPermissions(this.requestCode); final boolean hasPermission = PermissionUtils.hasPermissions(getContext(), permissions); if (hasPermission) { - handler.onPermissionGranted(requestCode); + handler.onPermissionGranted(this.requestCode); } } } } - private static Drawable getPermissionDrawable(Activity activity, String permission) { + private void showPermissionRationalePopup(@NonNull String permission) { + Drawable icon = getPermissionDrawable(requireActivity(), permission); + AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); + builder.setTitle(requireContext().getString(R.string.sb_text_dialog_permission_title)); + builder.setMessage(getPermissionGuideMessage(requireContext(), permission)); + if (icon != null) { + builder.setIcon(icon); + } + builder.setPositiveButton(R.string.sb_text_go_to_settings, (dialogInterface, i) -> { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + requireContext().getPackageName())); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivityForResult(intent, PERMISSION_SETTINGS_REQUEST_ID); + }); + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.secondary_300)); + } + + @Nullable + private static Drawable getPermissionDrawable(@NonNull Activity activity, @NonNull String permission) { Drawable drawable = null; try { PackageManager pm = activity.getPackageManager(); PermissionInfo permissionInfo = pm.getPermissionInfo(permission, 0); + if (permissionInfo.group == null) return null; PermissionGroupInfo groupInfo = pm.getPermissionGroupInfo(permissionInfo.group, 0); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - drawable = pm.getResourcesForApplication("android").getDrawable(groupInfo.icon, activity.getTheme()); - } else { - drawable = pm.getResourcesForApplication("android").getDrawable(groupInfo.icon); - } - } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { + drawable = ResourcesCompat.getDrawable(pm.getResourcesForApplication("android"), groupInfo.icon, activity.getTheme()); + } catch (Exception e) { + //Logger.w(e); } return drawable; } + @NonNull private static String getPermissionGuideMessage(@NonNull Context context, @NonNull String permission) { int textResId; - switch (permission) { - case Manifest.permission.CAMERA: - textResId = R.string.sb_text_need_to_allow_permission_camera; - break; - default: - textResId = R.string.sb_text_need_to_allow_permission_storage; - break; - + if (Manifest.permission.CAMERA.equals(permission)) { + textResId = R.string.sb_text_need_to_allow_permission_camera; + } else { + textResId = R.string.sb_text_need_to_allow_permission_storage; } return String.format(Locale.US, context.getString(textResId), ContextUtils.getApplicationName(context)); } diff --git a/uikit/src/main/java/com/sendbird/uikit/utils/IntentUtils.java b/uikit/src/main/java/com/sendbird/uikit/utils/IntentUtils.java index 933507c3..9eecc749 100644 --- a/uikit/src/main/java/com/sendbird/uikit/utils/IntentUtils.java +++ b/uikit/src/main/java/com/sendbird/uikit/utils/IntentUtils.java @@ -31,18 +31,37 @@ public static Intent getCameraIntent(@NonNull Context context, @NonNull Uri uri) return intent; } + @NonNull + public static Intent getImageGalleryIntent() { + return getGalleryIntent(new String[]{"image/*"}); + } + + @NonNull public static Intent getGalleryIntent() { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_GET_CONTENT); - if ( Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT ) { - intent.setType("*/*"); - String[] mimetypes = {"image/*", "video/*"}; - intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes); - } else { - intent.setType("image/*|video/*"); + return getGalleryIntent(new String[]{"image/*", "video/*"}); + } + + @NonNull + private static Intent getGalleryIntent(@NonNull String[] mimetypes) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_GET_CONTENT); + if ( Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT ) { + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes); + } else { + intent.setType("image/*|video/*"); + } + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + return Intent.createChooser(intent, null); } - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - return Intent.createChooser(intent, null); + + Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); + if (mimetypes.length == 1) { + // ACTION_PICK_IMAGES supports only two mimetypes. + intent.setType(mimetypes[0]); + } + return intent; } public static Intent getFileChooserIntent() { diff --git a/uikit/src/main/java/com/sendbird/uikit/utils/PermissionUtils.java b/uikit/src/main/java/com/sendbird/uikit/utils/PermissionUtils.java index c85c4e70..c94373c3 100644 --- a/uikit/src/main/java/com/sendbird/uikit/utils/PermissionUtils.java +++ b/uikit/src/main/java/com/sendbird/uikit/utils/PermissionUtils.java @@ -1,5 +1,6 @@ package com.sendbird.uikit.utils; +import android.Manifest; import android.app.Activity; import android.content.Context; import android.os.Build; @@ -9,13 +10,37 @@ import androidx.core.content.PermissionChecker; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; public class PermissionUtils { + public final static String[] CAMERA_PERMISSION = getCameraPermission(); + public final static String[] GET_CONTENT_PERMISSION = getGetContentPermission(); + private PermissionUtils() { } + private static String[] getCameraPermission() { + String[] permissions = new String[]{Manifest.permission.CAMERA, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE}; + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + permissions = new String[]{Manifest.permission.CAMERA}; + } + return permissions; + } + + private static String[] getGetContentPermission() { + String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissions = new String[] {}; + } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; + } + return permissions; + } public static boolean hasPermissions(Context context, @NonNull String... permissions) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { for (String permission : permissions) { @@ -48,4 +73,20 @@ public static List getShowRequestPermissionRationale(Activity activity, } return result; } + + @NonNull + public static List getExplicitDeniedPermissionList(@NonNull Activity activity, @NonNull Collection permissions) { + List result = new ArrayList<>(); + for (String permission : permissions) { + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { + result.add(permission); + } + } + return result; + } + + @NonNull + public static List getExplicitDeniedPermissionList(@NonNull Activity activity, @NonNull String... permissions) { + return getExplicitDeniedPermissionList(activity, Arrays.asList(permissions)); + } } diff --git a/uikit/src/main/java/com/sendbird/uikit/utils/UserUtils.java b/uikit/src/main/java/com/sendbird/uikit/utils/UserUtils.java index 71e0496c..0332a8f4 100644 --- a/uikit/src/main/java/com/sendbird/uikit/utils/UserUtils.java +++ b/uikit/src/main/java/com/sendbird/uikit/utils/UserUtils.java @@ -33,10 +33,17 @@ public String getProfileUrl() { @NonNull public static String getDisplayName(@NonNull Context context, @Nullable User user) { + return getDisplayName(context, user, false); + } + + @NonNull + public static String getDisplayName(@NonNull Context context, @Nullable User user, boolean usePronouns) { String nickname = context.getString(R.string.sb_text_channel_list_title_unknown); if (user == null) return nickname; - if (user.getUserId() != null && user.getUserId().equals(SendBird.getCurrentUser().getUserId())) { + if (usePronouns && user.getUserId() != null && + SendBird.getCurrentUser() != null && + user.getUserId().equals(SendBird.getCurrentUser().getUserId())) { nickname = context.getString(R.string.sb_text_you); } else if (!TextUtils.isEmpty(user.getNickname())) { nickname = user.getNickname(); diff --git a/uikit/src/main/java/com/sendbird/uikit/vm/ChannelViewModel.java b/uikit/src/main/java/com/sendbird/uikit/vm/ChannelViewModel.java index 150043b4..07be7eff 100644 --- a/uikit/src/main/java/com/sendbird/uikit/vm/ChannelViewModel.java +++ b/uikit/src/main/java/com/sendbird/uikit/vm/ChannelViewModel.java @@ -238,7 +238,7 @@ public void onMessagesAdded(@NonNull MessageContext context, @NonNull GroupChann Logger.d(">> ChannelViewModel::onMessagesAdded() from=%s", context.getCollectionEventSource()); if (messages.isEmpty()) return; - if (context.getMessagesSendingStatus() == BaseMessage.SendingStatus.SUCCEEDED) { + if (context.getMessagesSendingStatus() == BaseMessage.SendingStatus.SUCCEEDED || context.getMessagesSendingStatus() == BaseMessage.SendingStatus.NONE) { cachedMessages.addAll(messages); notifyDataSetChanged(context); } else if (context.getMessagesSendingStatus() == BaseMessage.SendingStatus.PENDING) { diff --git a/uikit/src/main/java/com/sendbird/uikit/vm/OpenChannelViewModel.java b/uikit/src/main/java/com/sendbird/uikit/vm/OpenChannelViewModel.java index 6d021ef6..e1ce8821 100644 --- a/uikit/src/main/java/com/sendbird/uikit/vm/OpenChannelViewModel.java +++ b/uikit/src/main/java/com/sendbird/uikit/vm/OpenChannelViewModel.java @@ -84,6 +84,7 @@ public class OpenChannelViewModel extends BaseViewModel implements LifecycleObse } private boolean isCurrentChannel(@NonNull String channelUrl) { + if (channel == null) return false; return channelUrl.equals(channel.getUrl()); } diff --git a/uikit/src/main/java/com/sendbird/uikit/vm/UserTypeListViewModel.java b/uikit/src/main/java/com/sendbird/uikit/vm/UserTypeListViewModel.java index ae039db0..647a70b7 100644 --- a/uikit/src/main/java/com/sendbird/uikit/vm/UserTypeListViewModel.java +++ b/uikit/src/main/java/com/sendbird/uikit/vm/UserTypeListViewModel.java @@ -1,6 +1,7 @@ package com.sendbird.uikit.vm; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LiveData; @@ -23,6 +24,10 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; public class UserTypeListViewModel extends BaseViewModel implements LifecycleObserver, PagerRecyclerView.Pageable> { @@ -35,6 +40,10 @@ public class UserTypeListViewModel extends BaseViewModel implements LifecycleObs private final CustomMemberListQueryHandler queryHandler; protected BaseChannel channel; private volatile boolean isInitialRequest = true; + @NonNull + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + @Nullable + private Future currentFuture; @Override protected void onCleared() { @@ -95,6 +104,7 @@ public LiveData getChannelDeleted() { } private boolean isCurrentChannel(@NonNull String channelUrl) { + if (channel == null) return false; return channelUrl.equals(channel.getUrl()); } @@ -220,13 +230,17 @@ public boolean hasPrevious() { return false; } - public void loadInitial() { + public synchronized void loadInitial() { Logger.d(">> MemberListViewModel::loadInitial()"); - List origin = this.memberList.getValue(); - if (origin != null) { - origin.clear(); - } - queryHandler.loadInitial(UserTypeListViewModel.this::onResult); + if (this.currentFuture != null) this.currentFuture.cancel(true); + this.currentFuture = executorService.schedule(() -> { + List origin = memberList.getValue(); + if (origin != null) { + origin.clear(); + } + queryHandler.loadInitial(UserTypeListViewModel.this::onResult); + return true; + }, 500, TimeUnit.MILLISECONDS); } @Override diff --git a/uikit/src/main/java/com/sendbird/uikit/widgets/MyQuotedMessageView.java b/uikit/src/main/java/com/sendbird/uikit/widgets/MyQuotedMessageView.java index 6abcd342..30c6f0d1 100644 --- a/uikit/src/main/java/com/sendbird/uikit/widgets/MyQuotedMessageView.java +++ b/uikit/src/main/java/com/sendbird/uikit/widgets/MyQuotedMessageView.java @@ -85,7 +85,7 @@ public void drawQuotedMessage(@Nullable BaseMessage message) { binding.ivQuoteReplyMessageIcon.setVisibility(GONE); binding.quoteReplyThumbnailPanel.setVisibility(GONE); binding.tvQuoteReplyTitle.setText(String.format(getContext().getString(R.string.sb_text_replied_to), - getContext().getString(R.string.sb_text_you), UserUtils.getDisplayName(getContext(), parentMessage.getSender()))); + getContext().getString(R.string.sb_text_you), UserUtils.getDisplayName(getContext(), parentMessage.getSender(), true))); binding.ivQuoteReplyThumbnailOveray.setVisibility(GONE); RequestListener requestListener = new RequestListener() { diff --git a/uikit/src/main/java/com/sendbird/uikit/widgets/OtherQuotedMessageView.java b/uikit/src/main/java/com/sendbird/uikit/widgets/OtherQuotedMessageView.java index d1af7ea0..c6a3c014 100644 --- a/uikit/src/main/java/com/sendbird/uikit/widgets/OtherQuotedMessageView.java +++ b/uikit/src/main/java/com/sendbird/uikit/widgets/OtherQuotedMessageView.java @@ -85,8 +85,8 @@ public void drawQuotedMessage(@Nullable BaseMessage message) { binding.ivQuoteReplyMessageIcon.setVisibility(GONE); binding.quoteReplyThumbnailPanel.setVisibility(GONE); binding.tvQuoteReplyTitle.setText(String.format(getContext().getString(R.string.sb_text_replied_to), - UserUtils.getDisplayName(getContext(), message.getSender()), - UserUtils.getDisplayName(getContext(), parentMessage.getSender()))); + UserUtils.getDisplayName(getContext(), message.getSender(), true), + UserUtils.getDisplayName(getContext(), parentMessage.getSender(), true))); binding.ivQuoteReplyThumbnailOveray.setVisibility(GONE); RequestListener requestListener = new RequestListener() { @Override diff --git a/uikit/src/main/res/layout/sb_view_my_file_message_component.xml b/uikit/src/main/res/layout/sb_view_my_file_message_component.xml index 0dd6341c..1e4f8bc9 100644 --- a/uikit/src/main/res/layout/sb_view_my_file_message_component.xml +++ b/uikit/src/main/res/layout/sb_view_my_file_message_component.xml @@ -78,7 +78,7 @@ android:paddingStart="@dimen/sb_size_12" android:paddingEnd="@dimen/sb_size_12" app:layout_constraintHorizontal_bias="0" - app:layout_constraintTop_toBottomOf="@id/quoteReplyPanel" + app:layout_constraintTop_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="@+id/contentBarrier" app:layout_constraintBottom_toTopOf="@id/rvEmojiReactionList" >