Loading packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +13 −6 Original line number Diff line number Diff line Loading @@ -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[]{ Loading @@ -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( Loading packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +90 −55 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -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); } Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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; } } Loading @@ -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 { Loading @@ -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( Loading Loading @@ -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; } Loading Loading @@ -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: Loading @@ -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; } Loading packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +92 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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 = Loading Loading @@ -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(); } } packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +55 −25 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +13 −6 Original line number Diff line number Diff line Loading @@ -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[]{ Loading @@ -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( Loading
packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading
packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +90 −55 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -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); } Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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; } } Loading @@ -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 { Loading @@ -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( Loading Loading @@ -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; } Loading Loading @@ -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: Loading @@ -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; } Loading
packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +92 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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 = Loading Loading @@ -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(); } }
packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +55 −25 File changed.Preview size limit exceeded, changes collapsed. Show changes