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

Commit bd350dfc authored by Anna Zappone's avatar Anna Zappone Committed by Automerger Merge Worker
Browse files

Merge "Update on reboots, package uninstalls" into sc-dev am: c331d562

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15000272

Change-Id: I75ed932e999d1e961fd79907dd066e461449696f
parents 44dc1633 c331d562
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -494,7 +494,8 @@ public class PeopleSpaceUtils {
     * match the data by {@link ContactsContract.ContactsColumns#LOOKUP_KEY} key to ensure proper
     * matching across all the Contacts DB tables.
     */
    private static List<String> getContactLookupKeysWithBirthdaysToday(Context context) {
    @VisibleForTesting
    public static List<String> getContactLookupKeysWithBirthdaysToday(Context context) {
        List<String> lookupKeysWithBirthdaysToday = new ArrayList<>(1);
        String today = new SimpleDateFormat("MM-dd").format(new Date());
        String[] projection = new String[]{
@@ -503,13 +504,19 @@ public class PeopleSpaceUtils {
        String where =
                ContactsContract.Data.MIMETYPE
                        + "= ? AND " + ContactsContract.CommonDataKinds.Event.TYPE + "="
                        + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + " AND substr("
                        + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) = ?";
                        + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + " AND (substr("
                        // Birthdays stored with years will match this format
                        + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) = ? OR substr("
                        // Birthdays stored without years will match this format
                        + ContactsContract.CommonDataKinds.Event.START_DATE + ",3) = ? )";
        String[] selection =
                new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, today};
                new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, today,
                        today};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
            cursor = context
                    .getContentResolver()
                    .query(ContactsContract.Data.CONTENT_URI,
                            projection, where, selection, null);
            while (cursor != null && cursor.moveToNext()) {
                String lookupKey = cursor.getString(
+1 −1
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ public class PeopleTileViewHelper {

    private RemoteViews createSuppressedView() {
        RemoteViews views;
        if (mTile.isUserQuieted()) {
        if (mTile != null && mTile.isUserQuieted()) {
            views = new RemoteViews(mContext.getPackageName(),
                    R.layout.people_tile_work_profile_quiet_layout);
        } else {
+90 −55
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;

import static com.android.systemui.people.NotificationHelper.getContactUri;
@@ -62,6 +63,7 @@ import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
@@ -172,6 +174,7 @@ public class PeopleSpaceWidgetManager {
    public void init() {
        synchronized (mLock) {
            if (!mRegisteredReceivers) {
                if (DEBUG) Log.d(TAG, "Register receivers");
                IntentFilter filter = new IntentFilter();
                filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
                filter.addAction(ACTION_BOOT_COMPLETED);
@@ -185,6 +188,14 @@ public class PeopleSpaceWidgetManager {
                mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter,

                        null /* executor */, UserHandle.ALL);
                IntentFilter perAppFilter = new IntentFilter(ACTION_PACKAGE_REMOVED);
                perAppFilter.addDataScheme("package");
                // BroadcastDispatcher doesn't allow data schemes.
                mContext.registerReceiver(mBaseBroadcastReceiver, perAppFilter);
                IntentFilter bootComplete = new IntentFilter(ACTION_BOOT_COMPLETED);
                bootComplete.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                // BroadcastDispatcher doesn't allow priority.
                mContext.registerReceiver(mBaseBroadcastReceiver, bootComplete);
                mRegisteredReceivers = true;
            }
        }
@@ -303,10 +314,6 @@ public class PeopleSpaceWidgetManager {

    /** Updates tile in app widget options and the current view. */
    public void updateAppWidgetOptionsAndView(int appWidgetId, PeopleSpaceTile tile) {
        if (tile == null) {
            if (DEBUG) Log.w(TAG, "Requested to store null tile");
            return;
        }
        synchronized (mTiles) {
            mTiles.put(appWidgetId, tile);
        }
@@ -320,6 +327,17 @@ public class PeopleSpaceWidgetManager {
     */
    @Nullable
    public PeopleSpaceTile getTileForExistingWidget(int appWidgetId) {
        try {
            return getTileForExistingWidgetThrowing(appWidgetId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to retrieve conversation for tile: " + e);
            return null;
        }
    }

    @Nullable
    private PeopleSpaceTile getTileForExistingWidgetThrowing(int appWidgetId) throws
            PackageManager.NameNotFoundException {
        // First, check if tile is cached in memory.
        PeopleSpaceTile tile;
        synchronized (mTiles) {
@@ -348,7 +366,8 @@ public class PeopleSpaceWidgetManager {
     * If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.
     */
    @Nullable
    public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) {
    public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) throws
            PackageManager.NameNotFoundException {
        if (!key.isValid()) {
            Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
            return null;
@@ -358,7 +377,6 @@ public class PeopleSpaceWidgetManager {
            Log.d(TAG, "System services are null");
            return null;
        }

        try {
            if (DEBUG) Log.d(TAG, "Retrieving Tile from storage: " + key.toString());
            ConversationChannel channel = mIPeopleManager.getConversation(
@@ -383,9 +401,9 @@ public class PeopleSpaceWidgetManager {
            }

            // Add current state.
            return updateWithCurrentState(storedTile.build(), ACTION_BOOT_COMPLETED);
        } catch (Exception e) {
            Log.e(TAG, "Failed to retrieve conversation for tile: " + e);
            return getTileWithCurrentState(storedTile.build(), ACTION_BOOT_COMPLETED);
        } catch (RemoteException e) {
            Log.e(TAG, "Could not retrieve data: " + e);
            return null;
        }
    }
@@ -397,7 +415,6 @@ public class PeopleSpaceWidgetManager {
    public void updateWidgetsWithNotificationChanged(StatusBarNotification sbn,
            PeopleSpaceUtils.NotificationAction notificationAction) {
        if (DEBUG) {
            Log.d(TAG, "updateWidgetsWithNotificationChanged called");
            if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
                Log.d(TAG, "Notification posted, key: " + sbn.getKey());
            } else {
@@ -414,7 +431,6 @@ public class PeopleSpaceWidgetManager {
            PeopleTileKey key = new PeopleTileKey(
                    sbn.getShortcutId(), sbn.getUser().getIdentifier(), sbn.getPackageName());
            if (!key.isValid()) {
                Log.d(TAG, "Sbn doesn't contain valid PeopleTileKey: " + key.toString());
                return;
            }
            int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
@@ -775,7 +791,13 @@ public class PeopleSpaceWidgetManager {
    /** Adds a widget based on {@code key} mapped to {@code appWidgetId}. */
    public void addNewWidget(int appWidgetId, PeopleTileKey key) {
        if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId);
        PeopleSpaceTile tile = getTileFromPersistentStorage(key, appWidgetId);
        PeopleSpaceTile tile = null;
        try {
            tile = getTileFromPersistentStorage(key, appWidgetId);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Cannot add widget since app was uninstalled");
            return;
        }
        if (tile == null) {
            return;
        }
@@ -1017,39 +1039,49 @@ public class PeopleSpaceWidgetManager {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DEBUG) Log.d(TAG, "Update widgets from: " + action);
            mBgExecutor.execute(() -> updateWidgetsOnStateChange(action));
            if (DEBUG) Log.d(TAG, "Update widgets from: " + intent.getAction());
            mBgExecutor.execute(() -> updateWidgetsFromBroadcastInBackground(intent.getAction()));
        }
    };

    /** Updates any app widget based on the current state. */
    /** Updates any app widget to the current state, triggered by a broadcast update. */
    @VisibleForTesting
    void updateWidgetsOnStateChange(String entryPoint) {
    void updateWidgetsFromBroadcastInBackground(String entryPoint) {
        int[] appWidgetIds = mAppWidgetManager.getAppWidgetIds(
                new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
        if (appWidgetIds == null) {
            return;
        }
        synchronized (mLock) {
        for (int appWidgetId : appWidgetIds) {
                PeopleSpaceTile tile = getTileForExistingWidget(appWidgetId);
                if (tile == null) {
            PeopleSpaceTile existingTile = null;
            PeopleSpaceTile updatedTile = null;
            try {
                synchronized (mLock) {
                    existingTile = getTileForExistingWidgetThrowing(appWidgetId);
                    if (existingTile == null) {
                        Log.e(TAG, "Matching conversation not found for shortcut ID");
                } else {
                    tile = updateWithCurrentState(tile, entryPoint);
                        return;
                    }
                updateAppWidgetOptionsAndView(appWidgetId, tile);
                    updatedTile = getTileWithCurrentState(existingTile, entryPoint);
                    updateAppWidgetOptionsAndView(appWidgetId, updatedTile);
                }
            } catch (PackageManager.NameNotFoundException e) {
                // Delete data for uninstalled widgets.
                Log.e(TAG, "Package no longer found for tile: " + e);
                synchronized (mLock) {
                    updateAppWidgetOptionsAndView(appWidgetId, updatedTile);
                }
                deleteWidgets(new int[]{appWidgetId});
            }
        }
    }

    /** Checks the current state of {@code tile} dependencies, updating fields as necessary. */
    /** Checks the current state of {@code tile} dependencies, modifying fields as necessary. */
    @Nullable
    private PeopleSpaceTile updateWithCurrentState(PeopleSpaceTile tile,
            String entryPoint) {
    private PeopleSpaceTile getTileWithCurrentState(PeopleSpaceTile tile,
            String entryPoint) throws
            PackageManager.NameNotFoundException {
        PeopleSpaceTile.Builder updatedTile = tile.toBuilder();
        try {
        switch (entryPoint) {
            case NotificationManager
                    .ACTION_INTERRUPTION_FILTER_CHANGED:
@@ -1072,17 +1104,20 @@ public class PeopleSpaceWidgetManager {
                        getPackageSuspended(tile)).setNotificationPolicyState(
                        getNotificationPolicyState());
        }
        } catch (Exception e) {
            Log.e(TAG, "Package no longer found for tile: " + tile.toString() + e);
            return null;
        }
        return updatedTile.build();
    }

    private boolean getPackageSuspended(PeopleSpaceTile tile) throws Exception {
    private boolean getPackageSuspended(PeopleSpaceTile tile) throws
            PackageManager.NameNotFoundException {
        boolean packageSuspended = !TextUtils.isEmpty(tile.getPackageName())
                && mPackageManager.isPackageSuspended(tile.getPackageName());
        if (DEBUG) Log.d(TAG, "Package suspended: " + packageSuspended);
        // isPackageSuspended() only throws an exception if the app has been uninstalled, and the
        // app data has also been cleared. We want to empty the layout when the app is uninstalled
        // regardless of app data clearing, which getApplicationInfoAsUser() handles.
        mPackageManager.getApplicationInfoAsUser(
                tile.getPackageName(), PackageManager.GET_META_DATA,
                PeopleSpaceUtils.getUserId(tile));
        return packageSuspended;
    }

+92 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.people;

import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
import static com.android.systemui.people.PeopleSpaceUtils.getContactLookupKeysWithBirthdaysToday;

import static com.google.common.truth.Truth.assertThat;

@@ -35,6 +36,7 @@ import android.app.Person;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -64,12 +66,17 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -112,6 +119,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
                    .setNotificationDataUri(URI)
                    .setMessagesCount(1)
                    .build();
    private static final String TEST_DISPLAY_NAME = "Display Name";

    private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext,
            SHORTCUT_ID_1).setLongLabel(
@@ -227,6 +235,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
                .thenReturn(List.of(mNotificationEntry1, mNotificationEntry2, mNotificationEntry3));
    }

    @After
    public void tearDown() {
        cleanupTestContactFromContactProvider();
    }


    @Test
    public void testAugmentTileFromNotification() {
        PeopleSpaceTile tile =
@@ -467,4 +481,82 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
                eq(WIDGET_ID_WITH_SHORTCUT),
                any());
    }

    @Test
    public void testBirthdayQueriesWithYear() throws Exception {
        String birthdayToday = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        addBirthdayToContactsDatabase(birthdayToday);

        List<String> lookupKeys = getContactLookupKeysWithBirthdaysToday(mContext);

        assertThat(lookupKeys).hasSize(1);
    }

    @Test
    public void testBirthdayQueriesWithoutYear() throws Exception {
        String birthdayToday = new SimpleDateFormat("--MM-dd").format(new Date());
        addBirthdayToContactsDatabase(birthdayToday);

        List<String> lookupKeys = getContactLookupKeysWithBirthdaysToday(mContext);

        assertThat(lookupKeys).hasSize(1);
    }

    @Test
    public void testBirthdayQueriesWithDifferentDates() throws Exception {
        Date yesterday = new Date(System.currentTimeMillis() - Duration.ofDays(1).toMillis());
        String birthdayYesterday = new SimpleDateFormat("--MM-dd").format(yesterday);
        addBirthdayToContactsDatabase(birthdayYesterday);

        List<String> lookupKeys = getContactLookupKeysWithBirthdaysToday(mContext);

        assertThat(lookupKeys).isEmpty();
    }

    private void addBirthdayToContactsDatabase(String birthdayDate) throws Exception {
        ContentResolver resolver = mContext.getContentResolver();
        ArrayList<ContentProviderOperation> ops = new ArrayList<>(3);
        ops.add(ContentProviderOperation
                .newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "com.google")
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "fakeAccountName")
                .build());
        ops.add(ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
                        TEST_DISPLAY_NAME)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(
                        ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(
                        ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)
                .withValue(
                        ContactsContract.CommonDataKinds.Event.TYPE,
                        ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY)
                .withValue(
                        ContactsContract.CommonDataKinds.Event.START_DATE, birthdayDate)
                .build());
        resolver.applyBatch(ContactsContract.AUTHORITY, ops);
    }

    private void cleanupTestContactFromContactProvider() {
        Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
                null,
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + "=?",
                new String[]{TEST_DISPLAY_NAME},
                null);
        while (cursor.moveToNext()) {
            String contactId = cursor.getString(cursor.getColumnIndex(
                    ContactsContract.Contacts.NAME_RAW_CONTACT_ID));
            mContext.getContentResolver().delete(ContactsContract.Data.CONTENT_URI,
                    ContactsContract.Data.RAW_CONTACT_ID + "=?",
                    new String[]{contactId});
        }
        cursor.close();
    }
}
+55 −25

File changed.

Preview size limit exceeded, changes collapsed.