Fixing same pending update being sent every time startListening is called
if there was no widget update in-between Bug: 67736800 Test: Added corresponding test in AppWidgetServiceImplTest Change-Id: Ib3213f8f79ac11ed05b317e25110d7e37561b837
This commit is contained in:
@@ -71,7 +71,6 @@ import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.service.appwidget.AppWidgetServiceDumpProto;
|
||||
import android.service.appwidget.WidgetProto;
|
||||
import android.text.TextUtils;
|
||||
@@ -159,7 +158,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
// Bump if the stored widgets need to be upgraded.
|
||||
private static final int CURRENT_VERSION = 1;
|
||||
|
||||
private static final AtomicLong REQUEST_COUNTER = new AtomicLong();
|
||||
// Every widget update request is associated which an increasing sequence number. This is
|
||||
// used to verify which request has successfully been received by the host.
|
||||
private static final AtomicLong UPDATE_COUNTER = new AtomicLong();
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
@@ -814,9 +815,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
Host host = lookupOrAddHostLocked(id);
|
||||
host.callbacks = callbacks;
|
||||
|
||||
long updateSequenceNo = UPDATE_COUNTER.incrementAndGet();
|
||||
int N = appWidgetIds.length;
|
||||
ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
|
||||
|
||||
LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
|
||||
@@ -828,6 +829,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reset the update counter once all the updates have been calculated
|
||||
host.lastWidgetUpdateSequenceNo = updateSequenceNo;
|
||||
return new ParceledListSlice<>(outUpdates);
|
||||
}
|
||||
}
|
||||
@@ -1914,9 +1917,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
// method with a wrong id. In that case, ignore the call.
|
||||
return;
|
||||
}
|
||||
long requestId = REQUEST_COUNTER.incrementAndGet();
|
||||
long requestId = UPDATE_COUNTER.incrementAndGet();
|
||||
if (widget != null) {
|
||||
widget.updateRequestIds.put(viewId, requestId);
|
||||
widget.updateSequenceNos.put(viewId, requestId);
|
||||
}
|
||||
if (widget == null || widget.host == null || widget.host.zombie
|
||||
|| widget.host.callbacks == null || widget.provider == null
|
||||
@@ -1941,7 +1944,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
int appWidgetId, int viewId, long requestId) {
|
||||
try {
|
||||
callbacks.viewDataChanged(appWidgetId, viewId);
|
||||
host.lastWidgetUpdateRequestId = requestId;
|
||||
host.lastWidgetUpdateSequenceNo = requestId;
|
||||
} catch (RemoteException re) {
|
||||
// It failed; remove the callback. No need to prune because
|
||||
// we know that this host is still referenced by this instance.
|
||||
@@ -1988,9 +1991,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
|
||||
long requestId = REQUEST_COUNTER.incrementAndGet();
|
||||
long requestId = UPDATE_COUNTER.incrementAndGet();
|
||||
if (widget != null) {
|
||||
widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId);
|
||||
widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId);
|
||||
}
|
||||
if (widget == null || widget.provider == null || widget.provider.zombie
|
||||
|| widget.host.callbacks == null || widget.host.zombie) {
|
||||
@@ -2013,7 +2016,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
int appWidgetId, RemoteViews views, long requestId) {
|
||||
try {
|
||||
callbacks.updateAppWidget(appWidgetId, views);
|
||||
host.lastWidgetUpdateRequestId = requestId;
|
||||
host.lastWidgetUpdateSequenceNo = requestId;
|
||||
} catch (RemoteException re) {
|
||||
synchronized (mLock) {
|
||||
Slog.e(TAG, "Widget host dead: " + host.id, re);
|
||||
@@ -2023,11 +2026,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
private void scheduleNotifyProviderChangedLocked(Widget widget) {
|
||||
long requestId = REQUEST_COUNTER.incrementAndGet();
|
||||
long requestId = UPDATE_COUNTER.incrementAndGet();
|
||||
if (widget != null) {
|
||||
// When the provider changes, reset everything else.
|
||||
widget.updateRequestIds.clear();
|
||||
widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId);
|
||||
widget.updateSequenceNos.clear();
|
||||
widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId);
|
||||
}
|
||||
if (widget == null || widget.provider == null || widget.provider.zombie
|
||||
|| widget.host.callbacks == null || widget.host.zombie) {
|
||||
@@ -2050,7 +2053,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
int appWidgetId, AppWidgetProviderInfo info, long requestId) {
|
||||
try {
|
||||
callbacks.providerChanged(appWidgetId, info);
|
||||
host.lastWidgetUpdateRequestId = requestId;
|
||||
host.lastWidgetUpdateSequenceNo = requestId;
|
||||
} catch (RemoteException re) {
|
||||
synchronized (mLock){
|
||||
Slog.e(TAG, "Widget host dead: " + host.id, re);
|
||||
@@ -3887,7 +3890,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
|
||||
|
||||
int tag = TAG_UNDEFINED; // for use while saving state (the index)
|
||||
long lastWidgetUpdateRequestId; // request id for the last update successfully sent
|
||||
// Sequence no for the last update successfully sent. This is updated whenever a
|
||||
// widget update is successfully sent to the host callbacks. As all new/undelivered updates
|
||||
// will have sequenceNo greater than this, all those updates will be sent when the host
|
||||
// callbacks are attached again.
|
||||
long lastWidgetUpdateSequenceNo;
|
||||
|
||||
public int getUserId() {
|
||||
return UserHandle.getUserId(id.uid);
|
||||
@@ -3914,18 +3921,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
*/
|
||||
public boolean getPendingUpdatesForId(int appWidgetId,
|
||||
LongSparseArray<PendingHostUpdate> outUpdates) {
|
||||
long updateRequestId = lastWidgetUpdateRequestId;
|
||||
long updateSequenceNo = lastWidgetUpdateSequenceNo;
|
||||
int N = widgets.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
Widget widget = widgets.get(i);
|
||||
if (widget.appWidgetId == appWidgetId) {
|
||||
outUpdates.clear();
|
||||
for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) {
|
||||
long requestId = widget.updateRequestIds.valueAt(j);
|
||||
if (requestId <= updateRequestId) {
|
||||
for (int j = widget.updateSequenceNos.size() - 1; j >= 0; j--) {
|
||||
long requestId = widget.updateSequenceNos.valueAt(j);
|
||||
if (requestId <= updateSequenceNo) {
|
||||
continue;
|
||||
}
|
||||
int id = widget.updateRequestIds.keyAt(j);
|
||||
int id = widget.updateSequenceNos.keyAt(j);
|
||||
final PendingHostUpdate update;
|
||||
switch (id) {
|
||||
case ID_PROVIDER_CHANGED:
|
||||
@@ -4021,8 +4028,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
RemoteViews maskedViews;
|
||||
Bundle options;
|
||||
Host host;
|
||||
// Request ids for various operations
|
||||
SparseLongArray updateRequestIds = new SparseLongArray(2);
|
||||
// Map of request type to updateSequenceNo.
|
||||
SparseLongArray updateSequenceNos = new SparseLongArray(2);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -247,6 +247,26 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
|
||||
assertEquals(7, updates.size());
|
||||
}
|
||||
|
||||
public void testUpdatesReceived_queueEmptyAfterStartListening() {
|
||||
int widgetId = setupHostAndWidget();
|
||||
int widgetId2 = bindNewWidget();
|
||||
mService.stopListening(mPkgName, HOST_ID);
|
||||
|
||||
sendDummyUpdates(widgetId, 22, 23);
|
||||
sendDummyUpdates(widgetId2, 100, 101, 102);
|
||||
|
||||
List<PendingHostUpdate> updates = mService.startListening(
|
||||
mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
|
||||
// 3 updates for first widget and 4 for second
|
||||
assertEquals(7, updates.size());
|
||||
|
||||
// Stop and start listening again
|
||||
mService.stopListening(mPkgName, HOST_ID);
|
||||
updates = mService.startListening(
|
||||
mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
|
||||
assertTrue(updates.isEmpty());
|
||||
}
|
||||
|
||||
public void testGetInstalledProvidersForPackage() {
|
||||
List<AppWidgetProviderInfo> allProviders = mManager.getInstalledProviders();
|
||||
assertTrue(!allProviders.isEmpty());
|
||||
|
||||
Reference in New Issue
Block a user