Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fac9c78 authored by Anna Zappone's avatar Anna Zappone
Browse files

Launch app unavailable dialog when WP is off

Test: LaunchConversationActivityTest
Bug: 180113387
Change-Id: I35460bd14840ff70654bd15fe65c23f59cb35153
parent 8017f4ed
Loading
Loading
Loading
Loading
+3 −21
Original line number Diff line number Diff line
@@ -23,18 +23,14 @@ import static com.android.systemui.people.PeopleTileViewHelper.getPersonIconBitm
import static com.android.systemui.people.PeopleTileViewHelper.getSizeInDp;

import android.app.Activity;
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -43,7 +39,6 @@ import android.widget.LinearLayout;

import com.android.systemui.R;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;

import java.util.ArrayList;
import java.util.List;
@@ -56,19 +51,13 @@ public class PeopleSpaceActivity extends Activity {
    private static final String TAG = "PeopleSpaceActivity";
    private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;

    private IPeopleManager mPeopleManager;
    private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
    private INotificationManager mNotificationManager;
    private LauncherApps mLauncherApps;
    private Context mContext;
    private NotificationEntryManager mNotificationEntryManager;
    private int mAppWidgetId;

    @Inject
    public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager,
            PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
    public PeopleSpaceActivity(PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
        super();
        mNotificationEntryManager = notificationEntryManager;
        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;

    }
@@ -77,11 +66,6 @@ public class PeopleSpaceActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getApplicationContext();
        mNotificationManager = INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
        mPeopleManager = IPeopleManager.Stub.asInterface(
                ServiceManager.getService(Context.PEOPLE_SERVICE));
        mLauncherApps = mContext.getSystemService(LauncherApps.class);
        mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
                INVALID_APPWIDGET_ID);
        setResult(RESULT_CANCELED);
@@ -92,10 +76,8 @@ public class PeopleSpaceActivity extends Activity {
        List<PeopleSpaceTile> priorityTiles = new ArrayList<>();
        List<PeopleSpaceTile> recentTiles = new ArrayList<>();
        try {
            priorityTiles = PeopleSpaceUtils.getPriorityTiles(mContext, mNotificationManager,
                    mPeopleManager, mLauncherApps, mNotificationEntryManager);
            recentTiles = PeopleSpaceUtils.getRecentTiles(mContext, mNotificationManager,
                    mPeopleManager, mLauncherApps, mNotificationEntryManager);
            priorityTiles = mPeopleSpaceWidgetManager.getPriorityTiles();
            recentTiles = mPeopleSpaceWidgetManager.getRecentTiles();
        } catch (Exception e) {
            Log.e(TAG, "Couldn't retrieve conversations", e);
        }
+6 −58
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.systemui.people;
import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.Notification.EXTRA_MESSAGES;

import android.annotation.NonNull;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
@@ -44,8 +42,8 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -127,58 +125,6 @@ public class PeopleSpaceUtils {
        }
    }

    /** Returns a list of map entries corresponding to user's priority conversations. */
    @NonNull
    public static List<PeopleSpaceTile> getPriorityTiles(
            Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
            LauncherApps launcherApps, NotificationEntryManager notificationEntryManager)
            throws Exception {
        List<ConversationChannelWrapper> conversations =
                notificationManager.getConversations(
                        false).getList();
        // Add priority conversations to tiles list.
        Stream<ShortcutInfo> priorityConversations = conversations.stream()
                .filter(c -> c.getNotificationChannel() != null
                        && c.getNotificationChannel().isImportantConversation())
                .map(c -> c.getShortcutInfo());
        List<PeopleSpaceTile> priorityTiles = getSortedTiles(peopleManager, launcherApps,
                priorityConversations);
        priorityTiles = augmentTilesFromVisibleNotifications(
                context, priorityTiles, notificationEntryManager);
        return priorityTiles;
    }

    /** Returns a list of map entries corresponding to user's recent conversations. */
    @NonNull
    public static List<PeopleSpaceTile> getRecentTiles(
            Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
            LauncherApps launcherApps, NotificationEntryManager notificationEntryManager)
            throws Exception {
        if (DEBUG) Log.d(TAG, "Add recent conversations");
        List<ConversationChannelWrapper> conversations =
                notificationManager.getConversations(
                        false).getList();
        Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
                .filter(c -> c.getNotificationChannel() == null
                        || !c.getNotificationChannel().isImportantConversation())
                .map(c -> c.getShortcutInfo());

        List<ConversationChannel> recentConversationsList =
                peopleManager.getRecentConversations().getList();
        Stream<ShortcutInfo> recentConversations = recentConversationsList
                .stream()
                .map(c -> c.getShortcutInfo());

        Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
                recentConversations);
        List<PeopleSpaceTile> recentTiles =
                getSortedTiles(peopleManager, launcherApps, mergedStream);

        recentTiles = augmentTilesFromVisibleNotifications(
                context, recentTiles, notificationEntryManager);
        return recentTiles;
    }

    /** Returns stored widgets for the conversation specified. */
    public static Set<String> getStoredWidgetIds(SharedPreferences sp, PeopleTileKey key) {
        if (!key.isValid()) {
@@ -255,7 +201,8 @@ public class PeopleSpaceUtils {
        return augmentedTile.get(0);
    }

    static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
    /** Adds to {@code tiles} any visible notifications. */
    public static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
            List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
        if (notificationEntryManager == null) {
            Log.w(TAG, "NotificationEntryManager is null");
@@ -356,11 +303,12 @@ public class PeopleSpaceUtils {
    }

    /** Returns a list sorted by ascending last interaction time from {@code stream}. */
    private static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
            LauncherApps launcherApps,
    public static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
            LauncherApps launcherApps, UserManager userManager,
            Stream<ShortcutInfo> stream) {
        return stream
                .filter(Objects::nonNull)
                .filter(c -> !userManager.isQuietModeEnabled(c.getUserHandle()))
                .map(c -> new PeopleSpaceTile.Builder(c, launcherApps).build())
                .filter(c -> shouldKeepConversation(c))
                .map(c -> c.toBuilder().setLastInteractionTimestamp(
+17 −1
Original line number Diff line number Diff line
@@ -23,11 +23,13 @@ import android.content.pm.LauncherApps;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationStats;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.statusbar.IStatusBarService;
@@ -48,15 +50,17 @@ public class LaunchConversationActivity extends Activity {
    private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
    private NotificationEntryManager mNotificationEntryManager;
    private final Optional<BubblesManager> mBubblesManagerOptional;
    private final UserManager mUserManager;
    private boolean mIsForTesting;
    private IStatusBarService mIStatusBarService;

    @Inject
    public LaunchConversationActivity(NotificationEntryManager notificationEntryManager,
            Optional<BubblesManager> bubblesManagerOptional) {
            Optional<BubblesManager> bubblesManagerOptional, UserManager userManager) {
        super();
        mNotificationEntryManager = notificationEntryManager;
        mBubblesManagerOptional = bubblesManagerOptional;
        mUserManager = userManager;
    }

    @Override
@@ -80,12 +84,24 @@ public class LaunchConversationActivity extends Activity {
            }
            mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_CLICKED);
            try {

                if (mUserManager.isQuietModeEnabled(userHandle)) {
                    if (DEBUG) Log.d(TAG, "Cannot launch app when quieted");
                    final Intent dialogIntent =
                            UnlaunchableAppActivity.createInQuietModeDialogIntent(
                                    userHandle.getIdentifier());
                    this.getApplicationContext().startActivity(dialogIntent);
                    finish();
                    return;
                }

                NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
                        notificationKey);
                if (entry != null && entry.canBubble() && mBubblesManagerOptional.isPresent()) {
                    if (DEBUG) Log.d(TAG, "Open bubble for conversation");
                    mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
                    // Just opt-out and don't cancel the notification for bubbles.
                    finish();
                    return;
                }

+63 −2
Original line number Diff line number Diff line
@@ -31,7 +31,9 @@ import static com.android.systemui.people.PeopleSpaceUtils.getStoredWidgetIds;
import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView;
import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetViews;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
@@ -51,7 +53,9 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.PreferenceManager;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
@@ -76,6 +80,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

import javax.inject.Inject;
import javax.inject.Singleton;
@@ -96,6 +101,8 @@ public class PeopleSpaceWidgetManager {
    private NotificationEntryManager mNotificationEntryManager;
    private PackageManager mPackageManager;
    private PeopleSpaceWidgetProvider mPeopleSpaceWidgetProvider;
    private INotificationManager mINotificationManager;
    private UserManager mUserManager;
    public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
    @GuardedBy("mLock")
    public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener>
@@ -121,17 +128,21 @@ public class PeopleSpaceWidgetManager {
        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
        mPackageManager = mContext.getPackageManager();
        mPeopleSpaceWidgetProvider = new PeopleSpaceWidgetProvider();
        mINotificationManager = INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
        mUserManager = context.getSystemService(UserManager.class);
    }

    /**
     * AppWidgetManager setter used for testing.
     */
    @VisibleForTesting
    protected void setAppWidgetManager(
    public void setAppWidgetManager(
            AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
            PeopleManager peopleManager, LauncherApps launcherApps,
            NotificationEntryManager notificationEntryManager, PackageManager packageManager,
            boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider) {
            boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider,
            UserManager userManager, INotificationManager notificationManager) {
        mAppWidgetManager = appWidgetManager;
        mIPeopleManager = iPeopleManager;
        mPeopleManager = peopleManager;
@@ -140,6 +151,8 @@ public class PeopleSpaceWidgetManager {
        mPackageManager = packageManager;
        mIsForTesting = isForTesting;
        mPeopleSpaceWidgetProvider = peopleSpaceWidgetProvider;
        mUserManager = userManager;
        mINotificationManager = notificationManager;
    }

    /**
@@ -783,4 +796,52 @@ public class PeopleSpaceWidgetManager {
        ComponentName componentName = new ComponentName(mContext, PeopleSpaceWidgetProvider.class);
        return mAppWidgetManager.requestPinAppWidget(componentName, extras, successCallback);
    }

    /** Returns a list of map entries corresponding to user's priority conversations. */
    @NonNull
    public List<PeopleSpaceTile> getPriorityTiles()
            throws Exception {
        List<ConversationChannelWrapper> conversations =
                mINotificationManager.getConversations(true).getList();
        // Add priority conversations to tiles list.
        Stream<ShortcutInfo> priorityConversations = conversations.stream()
                .filter(c -> c.getNotificationChannel() != null
                        && c.getNotificationChannel().isImportantConversation())
                .map(c -> c.getShortcutInfo());
        List<PeopleSpaceTile> priorityTiles = PeopleSpaceUtils.getSortedTiles(mIPeopleManager,
                mLauncherApps, mUserManager,
                priorityConversations);
        priorityTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications(
                mContext, priorityTiles, mNotificationEntryManager);
        return priorityTiles;
    }

    /** Returns a list of map entries corresponding to user's recent conversations. */
    @NonNull
    public List<PeopleSpaceTile> getRecentTiles()
            throws Exception {
        if (DEBUG) Log.d(TAG, "Add recent conversations");
        List<ConversationChannelWrapper> conversations =
                mINotificationManager.getConversations(false).getList();
        Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
                .filter(c -> c.getNotificationChannel() == null
                        || !c.getNotificationChannel().isImportantConversation())
                .map(c -> c.getShortcutInfo());

        List<ConversationChannel> recentConversationsList =
                mIPeopleManager.getRecentConversations().getList();
        Stream<ShortcutInfo> recentConversations = recentConversationsList
                .stream()
                .map(c -> c.getShortcutInfo());

        Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
                recentConversations);
        List<PeopleSpaceTile> recentTiles =
                PeopleSpaceUtils.getSortedTiles(mIPeopleManager, mLauncherApps, mUserManager,
                        mergedStream);

        recentTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications(
                mContext, recentTiles, mNotificationEntryManager);
        return recentTiles;
    }
}
+0 −115
Original line number Diff line number Diff line
@@ -22,8 +22,6 @@ import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -35,10 +33,7 @@ import static org.mockito.Mockito.when;

import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Person;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
@@ -47,7 +42,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -57,7 +51,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.ContactsContract;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
@@ -81,10 +74,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RunWith(AndroidTestingRunner.class)
@SmallTest
@@ -185,8 +176,6 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
    @Mock
    private IPeopleManager mPeopleManager;
    @Mock
    private LauncherApps mLauncherApps;
    @Mock
    private IAppWidgetService mIAppWidgetService;
    @Mock
    private AppWidgetManager mAppWidgetManager;
@@ -238,84 +227,6 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
                .thenReturn(List.of(mNotificationEntry1, mNotificationEntry2, mNotificationEntry3));
    }

    @Test
    public void testGetRecentTilesReturnsSortedListWithOnlyRecentConversations() throws Exception {
        // Ensure the less-recent Important conversation is before more recent conversations.
        ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1, false, 3);
        ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1 + 1, true, 3);
        ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1 + 2,
                true, 1);
        when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
                new ParceledListSlice(Arrays.asList(
                        newerNonImportantConversation, newerImportantConversation,
                        olderImportantConversation)));

        // Ensure the non-Important conversation is sorted between these recent conversations.
        ConversationChannel recentConversationBeforeNonImportantConversation =
                getConversationChannel(
                        SHORTCUT_ID_1 + 3, 4);
        ConversationChannel recentConversationAfterNonImportantConversation =
                getConversationChannel(SHORTCUT_ID_1 + 4,
                        2);
        when(mPeopleManager.getRecentConversations()).thenReturn(
                new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation,
                        recentConversationBeforeNonImportantConversation)));

        List<String> orderedShortcutIds = PeopleSpaceUtils.getRecentTiles(
                mContext, mNotificationManager, mPeopleManager,
                mLauncherApps, mNotificationEntryManager)
                .stream().map(tile -> tile.getId()).collect(Collectors.toList());

        // Check for sorted recent conversations.
        assertThat(orderedShortcutIds).containsExactly(
                recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(),
                newerNonImportantConversation.getShortcutInfo().getId(),
                recentConversationAfterNonImportantConversation.getShortcutInfo().getId())
                .inOrder();
    }

    @Test
    public void testGetPriorityTilesReturnsSortedListWithOnlyImportantConversations()
            throws Exception {
        // Ensure the less-recent Important conversation is before more recent conversations.
        ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1, false, 3);
        ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1 + 1, true, 3);
        ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(
                SHORTCUT_ID_1 + 2,
                true, 1);
        when(mNotificationManager.getConversations(anyBoolean())).thenReturn(
                new ParceledListSlice(Arrays.asList(
                        newerNonImportantConversation, newerImportantConversation,
                        olderImportantConversation)));

        // Ensure the non-Important conversation is sorted between these recent conversations.
        ConversationChannel recentConversationBeforeNonImportantConversation =
                getConversationChannel(
                        SHORTCUT_ID_1 + 3, 4);
        ConversationChannel recentConversationAfterNonImportantConversation =
                getConversationChannel(SHORTCUT_ID_1 + 4,
                        2);
        when(mPeopleManager.getRecentConversations()).thenReturn(
                new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation,
                        recentConversationBeforeNonImportantConversation)));

        List<String> orderedShortcutIds = PeopleSpaceUtils.getPriorityTiles(
                mContext, mNotificationManager, mPeopleManager,
                mLauncherApps, mNotificationEntryManager)
                .stream().map(tile -> tile.getId()).collect(Collectors.toList());

        // Check for sorted priority conversations.
        assertThat(orderedShortcutIds).containsExactly(
                newerImportantConversation.getShortcutInfo().getId(),
                olderImportantConversation.getShortcutInfo().getId())
                .inOrder();
    }

    @Test
    public void testGetMessagingStyleMessagesNoMessage() {
        Notification notification = new Notification.Builder(mContext, "test")
@@ -570,30 +481,4 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
                any());
    }

    private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId,
            boolean importantConversation, long lastInteractionTimestamp) throws Exception {
        ConversationChannelWrapper convo = new ConversationChannelWrapper();
        NotificationChannel notificationChannel = new NotificationChannel(shortcutId,
                "channel" + shortcutId,
                NotificationManager.IMPORTANCE_DEFAULT);
        notificationChannel.setImportantConversation(importantConversation);
        convo.setNotificationChannel(notificationChannel);
        convo.setShortcutInfo(new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
                "name").build());
        when(mPeopleManager.getLastInteraction(anyString(), anyInt(),
                eq(shortcutId))).thenReturn(lastInteractionTimestamp);
        return convo;
    }

    private ConversationChannel getConversationChannel(String shortcutId,
            long lastInteractionTimestamp) throws Exception {
        ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
                "name").build();
        ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null,
                lastInteractionTimestamp, false);
        when(mPeopleManager.getLastInteraction(anyString(), anyInt(),
                eq(shortcutId))).thenReturn(lastInteractionTimestamp);
        return convo;
    }
}
Loading