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

Commit f0fd893b authored by Anna Zappone's avatar Anna Zappone Committed by Flavio Fiszman
Browse files

Register conversation listeners

Newly registered after reboots and after being added to Launcher. Stored
in-memory to avoid duplicate registration. Refactors code out of
PeopleSpaceUtils to better handle race conditions

Test: PeopleSpaceWidgetManagerTest
Bug: 178792356
Change-Id: Ia1bc2671cb29696e537495ff8c1adabb873f0713
parent b8d3b7d2
Loading
Loading
Loading
Loading
+4 −24
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.app.Activity;
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -34,12 +33,10 @@ import android.provider.Settings;
import android.util.Log;
import android.view.ViewGroup;

import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;

import java.util.Collections;
import java.util.List;

import javax.inject.Inject;
@@ -54,15 +51,14 @@ public class PeopleSpaceActivity extends Activity {

    private ViewGroup mPeopleSpaceLayout;
    private IPeopleManager mPeopleManager;
    private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
    private INotificationManager mNotificationManager;
    private PackageManager mPackageManager;
    private LauncherApps mLauncherApps;
    private Context mContext;
    private AppWidgetManager mAppWidgetManager;
    private NotificationEntryManager mNotificationEntryManager;
    private int mAppWidgetId;
    private boolean mShowSingleConversation;
    private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();

    @Inject
    public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager) {
@@ -81,8 +77,8 @@ public class PeopleSpaceActivity extends Activity {
        mPackageManager = getPackageManager();
        mPeopleManager = IPeopleManager.Stub.asInterface(
                ServiceManager.getService(Context.PEOPLE_SERVICE));
        mPeopleSpaceWidgetManager = new PeopleSpaceWidgetManager(mContext);
        mLauncherApps = mContext.getSystemService(LauncherApps.class);
        mAppWidgetManager = AppWidgetManager.getInstance(mContext);
        setTileViewsWithPriorityConversations();
        mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
                INVALID_APPWIDGET_ID);
@@ -142,29 +138,13 @@ public class PeopleSpaceActivity extends Activity {
                        + mAppWidgetId);
            }
        }

        PeopleSpaceUtils.setStorageForTile(mContext, tile, mAppWidgetId);
        int[] widgetIds = new int[mAppWidgetId];
        // TODO: Populate new widget with existing conversation notification, if there is any.
        PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager,
                mPeopleManager);
        if (mLauncherApps != null) {
            try {
                if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
                mLauncherApps.cacheShortcuts(tile.getPackageName(),
                        Collections.singletonList(tile.getId()),
                        tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
            } catch (Exception e) {
                Log.w(TAG, "Exception caching shortcut:" + e);
            }
        }
        mPeopleSpaceWidgetManager.addNewWidget(tile, mAppWidgetId);
        finishActivity();
    }

    /** Finish activity with a successful widget configuration result. */
    private void finishActivity() {
        if (DEBUG) Log.d(TAG, "Widget added!");
        mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
        setActivityResult(RESULT_OK);
        finish();
    }
+33 −60
Original line number Diff line number Diff line
@@ -220,7 +220,7 @@ public class PeopleSpaceUtils {
    }

    @Nullable
    private static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager,
    public static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager,
            AppWidgetManager appWidgetManager,
            Context context, int appWidgetId) {
        try {
@@ -230,7 +230,7 @@ public class PeopleSpaceUtils {
            String pkg = widgetSp.getString(PACKAGE_NAME, EMPTY_STRING);
            int userId = widgetSp.getInt(USER_ID, INVALID_USER_ID);
            String shortcutId = widgetSp.getString(SHORTCUT_ID, EMPTY_STRING);
            if (pkg.isEmpty() || shortcutId.isEmpty() || userId == INVALID_WIDGET_ID) {
            if (!validKey(shortcutId, pkg, userId)) {
                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
                shortcutId = sp.getString(String.valueOf(appWidgetId), null);
                if (shortcutId == null) {
@@ -268,6 +268,17 @@ public class PeopleSpaceUtils {
        }
    }

    /** Returns stored widgets for the conversation specified. */
    public static Set<String> getStoredWidgetIds(SharedPreferences sp, String shortcutId,
            String packageName, int userId) {
        if (shortcutId == null || packageName == null) {
            return new HashSet<>();
        }
        String key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
        return new HashSet<>(sp.getStringSet(key, new HashSet<>()));
    }


    /** Best-effort attempts to migrate existing users to the new storage format. */
    // TODO: Remove after sufficient time. Temporary migration storage for existing users.
    private static void migrateExistingUsersToNewStorage(Context context, String shortcutId,
@@ -286,7 +297,11 @@ public class PeopleSpaceUtils {
                if (DEBUG) Log.d(TAG, "Migrate storage for " + entry.get().getUserName());
                setStorageForTile(context, entry.get(), appWidgetId);
            } else {
                Log.e(TAG, "Could not migrate user");
                Log.e(TAG, "Could not migrate user. Delete old storage");
                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
                SharedPreferences.Editor editor = sp.edit();
                editor.remove(String.valueOf(appWidgetId));
                editor.apply();
            }
        } catch (Exception e) {
            Log.e(TAG, "Could not query conversations");
@@ -320,17 +335,10 @@ public class PeopleSpaceUtils {
    }

    /** Removes stored data when tile is deleted. */
    public static void removeStorageForTile(Context context, int widgetId) {
        SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
                Context.MODE_PRIVATE);
        String packageName = widgetSp.getString(PACKAGE_NAME, null);
        String shortcutId = widgetSp.getString(SHORTCUT_ID, null);
        int userId = widgetSp.getInt(USER_ID, -1);

    public static void removeStorageForTile(Context context, String key, int widgetId) {
        // Delete widgetId mapping to key.
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = sp.edit();
        String key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
        Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>()));
        storedWidgetIds.remove(String.valueOf(widgetId));
        editor.putStringSet(key, storedWidgetIds);
@@ -338,6 +346,8 @@ public class PeopleSpaceUtils {
        editor.apply();

        // Delete all data specifically mapped to widgetId.
        SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
                Context.MODE_PRIVATE);
        SharedPreferences.Editor widgetEditor = widgetSp.edit();
        widgetEditor.remove(PACKAGE_NAME);
        widgetEditor.remove(USER_ID);
@@ -345,21 +355,6 @@ public class PeopleSpaceUtils {
        widgetEditor.apply();
    }

    /**
     * Returns whether the data mapped to app widget specified by {@code appWidgetId} matches the
     * requested update data.
     */
    public static boolean isCorrectAppWidget(Context context, int appWidgetId, String shortcutId,
            String packageName, int userId) {
        SharedPreferences sp = context.getSharedPreferences(String.valueOf(appWidgetId),
                Context.MODE_PRIVATE);
        String storedPackage = sp.getString(PACKAGE_NAME, EMPTY_STRING);
        int storedUserId = sp.getInt(USER_ID, INVALID_USER_ID);
        String storedShortcutId = sp.getString(SHORTCUT_ID, EMPTY_STRING);
        return storedPackage.equals(packageName) && storedShortcutId.equals(shortcutId)
                && storedUserId == userId;
    }

    static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
            List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
        if (notificationEntryManager == null) {
@@ -396,39 +391,8 @@ public class PeopleSpaceUtils {
        return augmentTileFromNotification(context, tile, visibleNotifications.get(key).getSbn());
    }

    /**
     * If incoming notification changed tile, store the changes in the tile options.
     */
    public static void updateWidgetWithNotificationChanged(IPeopleManager peopleManager,
            Context context,
            StatusBarNotification sbn,
            NotificationAction notificationAction, AppWidgetManager appWidgetManager,
            int appWidgetId) {
        PeopleSpaceTile storedTile = getPeopleSpaceTile(peopleManager, appWidgetManager, context,
                appWidgetId);
        if (storedTile == null) {
            if (DEBUG) Log.d(TAG, "Could not find stored tile to add notification to");
            return;
        }
        if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
            if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
            storedTile = augmentTileFromNotification(context, storedTile, sbn);
        } else {
            if (DEBUG) {
                Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
            }
            storedTile = storedTile
                    .toBuilder()
                    .setNotificationKey(null)
                    .setNotificationContent(null)
                    .setNotificationDataUri(null)
                    .setNotificationCategory(null)
                    .build();
        }
        updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, storedTile);
    }

    static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
    /** Augments {@code tile} with the notification content from {@code sbn}. */
    public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
            StatusBarNotification sbn) {
        Notification notification = sbn.getNotification();
        if (notification == null) {
@@ -992,7 +956,7 @@ public class PeopleSpaceUtils {
    }

    /** Update app widget options and the current view. */
    private static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
    public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
            Context context, int appWidgetId, PeopleSpaceTile tile) {
        updateAppWidgetOptions(appWidgetManager, appWidgetId, tile);
        RemoteViews views = createRemoteViews(context, tile, appWidgetId);
@@ -1065,10 +1029,19 @@ public class PeopleSpaceUtils {
     *     <li>"a/b/0" + "/" + 0 + "/" + "packageName"</li>
     * </ul>
     */
    @Nullable
    public static String getKey(String shortcutId, String packageName, int userId) {
        if (!validKey(shortcutId, packageName, userId)) {
            return null;
        }
        return shortcutId + "/" + userId + "/" + packageName;
    }

    /** Returns whether the key is valid. */
    public static boolean validKey(String shortcutId, String packageName, int userId) {
        return !TextUtils.isEmpty(shortcutId) && !TextUtils.isEmpty(packageName) && userId >= 0;
    }

    /** Returns the userId associated with a {@link PeopleSpaceTile} */
    public static int getUserId(PeopleSpaceTile tile) {
        return tile.getUserHandle().getIdentifier();
+269 −58

File changed.

Preview size limit exceeded, changes collapsed.

+42 −75
Original line number Diff line number Diff line
@@ -16,31 +16,17 @@

package com.android.systemui.people.widget;

import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID;
import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;

import android.app.PendingIntent;
import android.app.people.IPeopleManager;
import android.annotation.NonNull;
import android.app.people.ConversationChannel;
import android.app.people.PeopleManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.LauncherApps;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.widget.RemoteViews;

import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.people.PeopleSpaceUtils;

import java.util.Collections;

/** People Space Widget Provider class. */
public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
    private static final String TAG = "PeopleSpaceWidgetPvd";
@@ -50,7 +36,26 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
    public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
    public static final String EXTRA_USER_HANDLE = "extra_user_handle";

    public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
    public PeopleSpaceWidgetManager peopleSpaceWidgetManager;

    /** Listener for the shortcut data changes. */
    public class TileConversationListener implements PeopleManager.ConversationListener {

        @Override
        public void onConversationUpdate(@NonNull ConversationChannel conversation) {
            if (DEBUG) {
                Log.d(TAG,
                        "Received updated conversation: "
                                + conversation.getShortcutInfo().getLabel());
            }
            if (peopleSpaceWidgetManager == null) {
                // This shouldn't happen since onUpdate is called at reboot.
                Log.e(TAG, "Skipping conversation update: WidgetManager uninitialized");
                return;
            }
            peopleSpaceWidgetManager.updateWidgetsWithConversationChanged(conversation);
        }
    }

    /** Called when widget updates. */
    @Override
@@ -58,70 +63,32 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        if (DEBUG) Log.d(TAG, "onUpdate called");
        boolean showSingleConversation = Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
        if (showSingleConversation) {
            PeopleSpaceUtils.updateSingleConversationWidgets(context, appWidgetIds,
                    appWidgetManager, IPeopleManager.Stub.asInterface(
                            ServiceManager.getService(Context.PEOPLE_SERVICE)));
        ensurePeopleSpaceWidgetManagerInitialized(context);
        peopleSpaceWidgetManager.updateWidgets(appWidgetIds);
        for (int appWidgetId : appWidgetIds) {
            PeopleSpaceWidgetProvider.TileConversationListener
                    newListener = new PeopleSpaceWidgetProvider.TileConversationListener();
            peopleSpaceWidgetManager.registerConversationListenerIfNeeded(appWidgetId,
                    newListener);
        }
        return;
    }
        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int appWidgetId : appWidgetIds) {
            RemoteViews views =
                    new RemoteViews(context.getPackageName(), R.layout.people_space_widget);

            Intent intent = new Intent(context, PeopleSpaceWidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            views.setRemoteAdapter(R.id.widget_list_view, intent);

            Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
            activityIntent.addFlags(
                    Intent.FLAG_ACTIVITY_NEW_TASK
                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
                            | Intent.FLAG_ACTIVITY_NO_HISTORY
                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    context,
                    appWidgetId,
                    activityIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
            views.setPendingIntentTemplate(R.id.widget_list_view, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app widget
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_list_view);
            appWidgetManager.updateAppWidget(appWidgetId, views);
    private void ensurePeopleSpaceWidgetManagerInitialized(Context context) {
        if (peopleSpaceWidgetManager == null) {
            peopleSpaceWidgetManager = new PeopleSpaceWidgetManager(context);
        }
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        LauncherApps launcherApps = context.getSystemService(LauncherApps.class);

        for (int widgetId : appWidgetIds) {
            if (DEBUG) Log.d(TAG, "Widget removed");
            mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_DELETED);
            if (launcherApps != null) {
                SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
                        Context.MODE_PRIVATE);
                String packageName = widgetSp.getString(PACKAGE_NAME, null);
                String shortcutId = widgetSp.getString(SHORTCUT_ID, null);
                int userId = widgetSp.getInt(USER_ID, -1);

                if (packageName != null && shortcutId != null && userId != -1) {
                    try {
                        if (DEBUG) Log.d(TAG, "Uncaching shortcut for PeopleTile: " + shortcutId);
                        launcherApps.uncacheShortcuts(packageName,
                                Collections.singletonList(shortcutId),
                                UserHandle.of(userId),
                                LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
                    } catch (Exception e) {
                        Log.d(TAG, "Exception uncaching shortcut:" + e);
                    }
                }
            }
            PeopleSpaceUtils.removeStorageForTile(context, widgetId);
        ensurePeopleSpaceWidgetManagerInitialized(context);
        peopleSpaceWidgetManager.deleteWidgets(appWidgetIds);
    }

    @VisibleForTesting
    public void setPeopleSpaceWidgetManager(PeopleSpaceWidgetManager manager) {
        peopleSpaceWidgetManager = manager;
    }
}
+175 −41

File changed.

Preview size limit exceeded, changes collapsed.