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

Commit c4bc1853 authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

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

parents 4db655fa a6717e81
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.