Merge "Update People Space widgets on posted notifications."
This commit is contained in:
committed by
Android (Google) Code Review
commit
794771116c
@@ -65,6 +65,7 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.systemui.dagger.qualifiers.DisplayId;
|
||||
@@ -188,6 +189,13 @@ public class FrameworkServicesModule {
|
||||
return context.getSystemService(InputMethodManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static IAppWidgetService provideIAppWidgetService() {
|
||||
return IAppWidgetService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.APPWIDGET_SERVICE));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static IPackageManager provideIPackageManager() {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.people.widget;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.ServiceManager;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.people.PeopleSpaceUtils;
|
||||
import com.android.systemui.statusbar.NotificationListener;
|
||||
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/** Manager for People Space widget. */
|
||||
@Singleton
|
||||
public class PeopleSpaceWidgetManager {
|
||||
private static final String TAG = "PeopleSpaceWidgetMgr";
|
||||
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
|
||||
|
||||
private final Context mContext;
|
||||
private IAppWidgetService mAppWidgetManager;
|
||||
|
||||
@Inject
|
||||
public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) {
|
||||
if (DEBUG) Log.d(TAG, "constructor");
|
||||
mContext = context;
|
||||
mAppWidgetManager = appWidgetService;
|
||||
}
|
||||
|
||||
/** Constructor used for testing. */
|
||||
@VisibleForTesting
|
||||
protected PeopleSpaceWidgetManager(Context context) {
|
||||
if (DEBUG) Log.d(TAG, "constructor");
|
||||
mContext = context;
|
||||
mAppWidgetManager = IAppWidgetService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.APPWIDGET_SERVICE));
|
||||
}
|
||||
|
||||
/** AppWidgetManager setter used for testing. */
|
||||
@VisibleForTesting
|
||||
protected void setAppWidgetManager(IAppWidgetService appWidgetService) {
|
||||
mAppWidgetManager = appWidgetService;
|
||||
}
|
||||
|
||||
/** Updates People Space widgets. */
|
||||
public void updateWidgets() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "updateWidgets called");
|
||||
int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
|
||||
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
|
||||
);
|
||||
|
||||
if (widgetIds.length == 0) {
|
||||
if (DEBUG) Log.d(TAG, "no widgets to update");
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
|
||||
mAppWidgetManager
|
||||
.notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
|
||||
R.id.widget_list_view);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the manager to the pipeline, making it ready to receive events. Should only be
|
||||
* called once.
|
||||
*/
|
||||
public void attach(NotificationListener listenerService) {
|
||||
if (DEBUG) Log.d(TAG, "attach");
|
||||
listenerService.addNotificationHandler(mListener);
|
||||
}
|
||||
|
||||
private final NotificationHandler mListener = new NotificationHandler() {
|
||||
@Override
|
||||
public void onNotificationPosted(
|
||||
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
|
||||
if (DEBUG) Log.d(TAG, "onNotificationPosted");
|
||||
updateWidgets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRemoved(
|
||||
StatusBarNotification sbn,
|
||||
NotificationListenerService.RankingMap rankingMap
|
||||
) {
|
||||
if (DEBUG) Log.d(TAG, "onNotificationRemoved");
|
||||
updateWidgets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRemoved(
|
||||
StatusBarNotification sbn,
|
||||
NotificationListenerService.RankingMap rankingMap,
|
||||
int reason) {
|
||||
if (DEBUG) Log.d(TAG, "onNotificationRemoved with reason " + reason);
|
||||
updateWidgets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRankingUpdate(
|
||||
NotificationListenerService.RankingMap rankingMap) { }
|
||||
|
||||
@Override
|
||||
public void onNotificationsInitialized() {
|
||||
if (DEBUG) Log.d(TAG, "onNotificationsInitialized");
|
||||
updateWidgets();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import android.util.Log;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationListener;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||
@@ -49,6 +50,7 @@ public class NotifPipelineInitializer implements Dumpable {
|
||||
private final ShadeListBuilder mListBuilder;
|
||||
private final NotifCoordinators mNotifPluggableCoordinators;
|
||||
private final NotifInflaterImpl mNotifInflater;
|
||||
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
|
||||
private final DumpManager mDumpManager;
|
||||
private final ShadeViewManagerFactory mShadeViewManagerFactory;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
@@ -62,6 +64,7 @@ public class NotifPipelineInitializer implements Dumpable {
|
||||
ShadeListBuilder listBuilder,
|
||||
NotifCoordinators notifCoordinators,
|
||||
NotifInflaterImpl notifInflater,
|
||||
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
|
||||
DumpManager dumpManager,
|
||||
ShadeViewManagerFactory shadeViewManagerFactory,
|
||||
FeatureFlags featureFlags) {
|
||||
@@ -72,6 +75,7 @@ public class NotifPipelineInitializer implements Dumpable {
|
||||
mNotifPluggableCoordinators = notifCoordinators;
|
||||
mDumpManager = dumpManager;
|
||||
mNotifInflater = notifInflater;
|
||||
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
|
||||
mShadeViewManagerFactory = shadeViewManagerFactory;
|
||||
mFeatureFlags = featureFlags;
|
||||
}
|
||||
@@ -99,6 +103,7 @@ public class NotifPipelineInitializer implements Dumpable {
|
||||
mListBuilder.attach(mNotifCollection);
|
||||
mNotifCollection.attach(mGroupCoalescer);
|
||||
mGroupCoalescer.attach(notificationService);
|
||||
mPeopleSpaceWidgetManager.attach(notificationService);
|
||||
|
||||
Log.d(TAG, "Notif pipeline initialized");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.people.widget;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.NotificationListener;
|
||||
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
|
||||
import com.android.systemui.statusbar.notification.collection.NoManSimulator;
|
||||
import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
private static final long MIN_LINGER_DURATION = 5;
|
||||
|
||||
private static final String TEST_PACKAGE_A = "com.test.package_a";
|
||||
private static final String TEST_PACKAGE_B = "com.test.package_b";
|
||||
|
||||
private PeopleSpaceWidgetManager mManager;
|
||||
|
||||
@Mock private NotificationListener mListenerService;
|
||||
@Mock private IAppWidgetService mIAppWidgetService;
|
||||
@Mock private Context mContext;
|
||||
|
||||
@Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
|
||||
|
||||
private final NoManSimulator mNoMan = new NoManSimulator();
|
||||
private final FakeSystemClock mClock = new FakeSystemClock();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mManager =
|
||||
new PeopleSpaceWidgetManager(mContext);
|
||||
mManager.setAppWidgetManager(mIAppWidgetService);
|
||||
mManager.attach(mListenerService);
|
||||
|
||||
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
|
||||
NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
|
||||
mNoMan.addListener(serviceListener);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDoNotNotifyAppWidgetIfNoWidgets() throws RemoteException {
|
||||
int[] widgetIdsArray = {};
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
new NotificationEntryBuilder()
|
||||
.setId(0)
|
||||
.setPkg(TEST_PACKAGE_A));
|
||||
mClock.advanceTime(MIN_LINGER_DURATION);
|
||||
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyAppWidgetIfWidgets() throws RemoteException {
|
||||
int[] widgetIdsArray = {1};
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
new NotificationEntryBuilder()
|
||||
.setId(0)
|
||||
.setPkg(TEST_PACKAGE_A));
|
||||
mClock.advanceTime(MIN_LINGER_DURATION);
|
||||
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(1))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyAppWidgetTwiceIfTwoNotifications() throws RemoteException {
|
||||
int[] widgetIdsArray = {1, 2};
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_A)
|
||||
.setId(1));
|
||||
mClock.advanceTime(4);
|
||||
NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_B)
|
||||
.setId(2));
|
||||
|
||||
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(2))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyAppWidgetTwiceIfNotificationPostedAndRemoved() throws RemoteException {
|
||||
int[] widgetIdsArray = {1, 2};
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_A)
|
||||
.setId(1));
|
||||
mClock.advanceTime(4);
|
||||
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
|
||||
|
||||
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(2))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user