Merge "Maintaining diff for all widget operations instead of just the Views update" into nyc-mr1-dev
am: 6f84a27a75
* commit '6f84a27a7597a3bc34316baf2af2bda30a2d75de':
Maintaining diff for all widget operations instead of just the Views update
Change-Id: Iae3f2a6fc040d4484788ba203e0e0b6a66ed5c48
This commit is contained in:
@@ -34,7 +34,6 @@ import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
@@ -187,19 +186,28 @@ public class AppWidgetHost {
|
||||
idsToUpdate[i] = mViews.keyAt(i);
|
||||
}
|
||||
}
|
||||
List<RemoteViews> updatedViews;
|
||||
int[] updatedIds = new int[idsToUpdate.length];
|
||||
List<PendingHostUpdate> updates;
|
||||
try {
|
||||
updatedViews = sService.startListening(
|
||||
mCallbacks, mContextOpPackageName, mHostId, idsToUpdate, updatedIds).getList();
|
||||
updates = sService.startListening(
|
||||
mCallbacks, mContextOpPackageName, mHostId, idsToUpdate).getList();
|
||||
}
|
||||
catch (RemoteException e) {
|
||||
throw new RuntimeException("system server dead?", e);
|
||||
}
|
||||
|
||||
int N = updatedViews.size();
|
||||
int N = updates.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
updateAppWidgetView(updatedIds[i], updatedViews.get(i));
|
||||
PendingHostUpdate update = updates.get(i);
|
||||
switch (update.type) {
|
||||
case PendingHostUpdate.TYPE_VIEWS_UPDATE:
|
||||
updateAppWidgetView(update.appWidgetId, update.views);
|
||||
break;
|
||||
case PendingHostUpdate.TYPE_PROVIDER_CHANGED:
|
||||
onProviderChanged(update.appWidgetId, update.widgetInfo);
|
||||
break;
|
||||
case PendingHostUpdate.TYPE_VIEW_DATA_CHANGED:
|
||||
viewDataChanged(update.appWidgetId, update.viewId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
125
core/java/android/appwidget/PendingHostUpdate.java
Normal file
125
core/java/android/appwidget/PendingHostUpdate.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 android.appwidget;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class PendingHostUpdate implements Parcelable {
|
||||
|
||||
static final int TYPE_VIEWS_UPDATE = 0;
|
||||
static final int TYPE_PROVIDER_CHANGED = 1;
|
||||
static final int TYPE_VIEW_DATA_CHANGED = 2;
|
||||
|
||||
final int appWidgetId;
|
||||
final int type;
|
||||
RemoteViews views;
|
||||
AppWidgetProviderInfo widgetInfo;
|
||||
int viewId;
|
||||
|
||||
public static PendingHostUpdate updateAppWidget(int appWidgetId, RemoteViews views) {
|
||||
PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEWS_UPDATE);
|
||||
update.views = views;
|
||||
return update;
|
||||
}
|
||||
|
||||
public static PendingHostUpdate providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
|
||||
PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_PROVIDER_CHANGED);
|
||||
update.widgetInfo = info;
|
||||
return update;
|
||||
}
|
||||
|
||||
public static PendingHostUpdate viewDataChanged(int appWidgetId, int viewId) {
|
||||
PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEW_DATA_CHANGED);
|
||||
update.viewId = viewId;
|
||||
return update;
|
||||
}
|
||||
|
||||
private PendingHostUpdate(int appWidgetId, int type) {
|
||||
this.appWidgetId = appWidgetId;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private PendingHostUpdate(Parcel in) {
|
||||
appWidgetId = in.readInt();
|
||||
type = in.readInt();
|
||||
|
||||
switch (type) {
|
||||
case TYPE_VIEWS_UPDATE:
|
||||
if (0 != in.readInt()) {
|
||||
views = new RemoteViews(in);
|
||||
}
|
||||
break;
|
||||
case TYPE_PROVIDER_CHANGED:
|
||||
if (0 != in.readInt()) {
|
||||
widgetInfo = new AppWidgetProviderInfo(in);
|
||||
}
|
||||
break;
|
||||
case TYPE_VIEW_DATA_CHANGED:
|
||||
viewId = in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(appWidgetId);
|
||||
dest.writeInt(type);
|
||||
switch (type) {
|
||||
case TYPE_VIEWS_UPDATE:
|
||||
writeNullParcelable(views, dest, flags);
|
||||
break;
|
||||
case TYPE_PROVIDER_CHANGED:
|
||||
writeNullParcelable(widgetInfo, dest, flags);
|
||||
break;
|
||||
case TYPE_VIEW_DATA_CHANGED:
|
||||
dest.writeInt(viewId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNullParcelable(Parcelable p, Parcel dest, int flags) {
|
||||
if (p != null) {
|
||||
dest.writeInt(1);
|
||||
p.writeToParcel(dest, flags);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable.Creator that instantiates PendingHostUpdate objects
|
||||
*/
|
||||
public static final Parcelable.Creator<PendingHostUpdate> CREATOR
|
||||
= new Parcelable.Creator<PendingHostUpdate>() {
|
||||
public PendingHostUpdate createFromParcel(Parcel parcel) {
|
||||
return new PendingHostUpdate(parcel);
|
||||
}
|
||||
|
||||
public PendingHostUpdate[] newArray(int size) {
|
||||
return new PendingHostUpdate[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -34,7 +34,7 @@ interface IAppWidgetService {
|
||||
// for AppWidgetHost
|
||||
//
|
||||
ParceledListSlice startListening(IAppWidgetHost host, String callingPackage, int hostId,
|
||||
in int[] appWidgetIds, out int[] updatedIds);
|
||||
in int[] appWidgetIds);
|
||||
void stopListening(String callingPackage, int hostId);
|
||||
int allocateAppWidgetId(String callingPackage, int hostId);
|
||||
void deleteAppWidgetId(String callingPackage, int appWidgetId);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.appwidget.PendingHostUpdate;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -70,10 +71,12 @@ import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.Display;
|
||||
@@ -732,8 +735,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice<RemoteViews> startListening(IAppWidgetHost callbacks,
|
||||
String callingPackage, int hostId, int[] appWidgetIds, int[] updatedIds) {
|
||||
public ParceledListSlice<PendingHostUpdate> startListening(IAppWidgetHost callbacks,
|
||||
String callingPackage, int hostId, int[] appWidgetIds) {
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
|
||||
if (DEBUG) {
|
||||
@@ -753,18 +756,19 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
host.callbacks = callbacks;
|
||||
|
||||
int N = appWidgetIds.length;
|
||||
ArrayList<RemoteViews> outViews = new ArrayList<>(N);
|
||||
RemoteViews rv;
|
||||
int added = 0;
|
||||
ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
|
||||
|
||||
LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
|
||||
for (int i = 0; i < N; i++) {
|
||||
rv = host.getPendingViewsForId(appWidgetIds[i]);
|
||||
if (rv != null) {
|
||||
updatedIds[added] = appWidgetIds[i];
|
||||
outViews.add(rv);
|
||||
added++;
|
||||
if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
|
||||
// We key the updates based on time, so that the values are sorted by time.
|
||||
int M = updatesMap.size();
|
||||
for (int j = 0; j < M; j++) {
|
||||
outUpdates.add(updatesMap.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ParceledListSlice<>(outViews);
|
||||
return new ParceledListSlice<>(outUpdates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1804,6 +1808,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
|
||||
if (viewId == ID_VIEWS_UPDATE || viewId == ID_PROVIDER_CHANGED) {
|
||||
// A view id should never collide with these constants but a developer can call this
|
||||
// method with a wrong id. In that case, ignore the call.
|
||||
return;
|
||||
}
|
||||
long requestTime = SystemClock.uptimeMillis();
|
||||
if (widget != null) {
|
||||
widget.updateTimes.put(viewId, requestTime);
|
||||
}
|
||||
if (widget == null || widget.host == null || widget.host.zombie
|
||||
|| widget.host.callbacks == null || widget.provider == null
|
||||
|| widget.provider.zombie) {
|
||||
@@ -1813,6 +1826,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = widget.host;
|
||||
args.arg2 = widget.host.callbacks;
|
||||
args.arg3 = requestTime;
|
||||
args.argi1 = widget.appWidgetId;
|
||||
args.argi2 = viewId;
|
||||
|
||||
@@ -1823,9 +1837,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
|
||||
|
||||
private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
|
||||
int appWidgetId, int viewId) {
|
||||
int appWidgetId, int viewId, long requestTime) {
|
||||
try {
|
||||
callbacks.viewDataChanged(appWidgetId, viewId);
|
||||
host.lastWidgetUpdateTime = requestTime;
|
||||
} catch (RemoteException re) {
|
||||
// It failed; remove the callback. No need to prune because
|
||||
// we know that this host is still referenced by this instance.
|
||||
@@ -1874,7 +1889,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
|
||||
long requestTime = SystemClock.uptimeMillis();
|
||||
if (widget != null) {
|
||||
widget.lastUpdateTime = requestTime;
|
||||
widget.updateTimes.put(ID_VIEWS_UPDATE, requestTime);
|
||||
}
|
||||
if (widget == null || widget.provider == null || widget.provider.zombie
|
||||
|| widget.host.callbacks == null || widget.host.zombie) {
|
||||
@@ -1907,6 +1922,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
private void scheduleNotifyProviderChangedLocked(Widget widget) {
|
||||
long requestTime = SystemClock.uptimeMillis();
|
||||
if (widget != null) {
|
||||
// When the provider changes, reset everything else.
|
||||
widget.updateTimes.clear();
|
||||
widget.updateTimes.append(ID_PROVIDER_CHANGED, requestTime);
|
||||
}
|
||||
if (widget == null || widget.provider == null || widget.provider.zombie
|
||||
|| widget.host.callbacks == null || widget.host.zombie) {
|
||||
return;
|
||||
@@ -1916,6 +1937,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
args.arg1 = widget.host;
|
||||
args.arg2 = widget.host.callbacks;
|
||||
args.arg3 = widget.provider.info;
|
||||
args.arg4 = requestTime;
|
||||
args.argi1 = widget.appWidgetId;
|
||||
|
||||
mCallbackHandler.obtainMessage(
|
||||
@@ -1924,9 +1946,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
|
||||
int appWidgetId, AppWidgetProviderInfo info) {
|
||||
int appWidgetId, AppWidgetProviderInfo info, long requestTime) {
|
||||
try {
|
||||
callbacks.providerChanged(appWidgetId, info);
|
||||
host.lastWidgetUpdateTime = requestTime;
|
||||
} catch (RemoteException re) {
|
||||
synchronized (mLock){
|
||||
Slog.e(TAG, "Widget host dead: " + host.id, re);
|
||||
@@ -3410,10 +3433,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
Host host = (Host) args.arg1;
|
||||
IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
|
||||
AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
|
||||
long requestTime = (Long) args.arg4;
|
||||
final int appWidgetId = args.argi1;
|
||||
args.recycle();
|
||||
|
||||
handleNotifyProviderChanged(host, callbacks, appWidgetId, info);
|
||||
handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestTime);
|
||||
} break;
|
||||
|
||||
case MSG_NOTIFY_PROVIDERS_CHANGED: {
|
||||
@@ -3429,11 +3453,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
Host host = (Host) args.arg1;
|
||||
IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
|
||||
long requestTime = (Long) args.arg3;
|
||||
final int appWidgetId = args.argi1;
|
||||
final int viewId = args.argi2;
|
||||
args.recycle();
|
||||
|
||||
handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId);
|
||||
handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
|
||||
requestTime);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -3772,20 +3798,41 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RemoveViews for the provided widget id if an update is pending
|
||||
* for that widget.
|
||||
* Adds all pending updates in {@param outUpdates} keys by the update time.
|
||||
*/
|
||||
public RemoteViews getPendingViewsForId(int appWidgetId) {
|
||||
public boolean getPendingUpdatesForId(int appWidgetId,
|
||||
LongSparseArray<PendingHostUpdate> outUpdates) {
|
||||
long updateTime = lastWidgetUpdateTime;
|
||||
int N = widgets.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
Widget widget = widgets.get(i);
|
||||
if (widget.appWidgetId == appWidgetId
|
||||
&& widget.lastUpdateTime > updateTime) {
|
||||
return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
|
||||
if (widget.appWidgetId == appWidgetId) {
|
||||
outUpdates.clear();
|
||||
for (int j = widget.updateTimes.size() - 1; j >= 0; j--) {
|
||||
long time = widget.updateTimes.valueAt(j);
|
||||
if (time <= updateTime) {
|
||||
continue;
|
||||
}
|
||||
int id = widget.updateTimes.keyAt(j);
|
||||
final PendingHostUpdate update;
|
||||
switch (id) {
|
||||
case ID_PROVIDER_CHANGED:
|
||||
update = PendingHostUpdate.providerChanged(
|
||||
appWidgetId, widget.provider.info);
|
||||
break;
|
||||
case ID_VIEWS_UPDATE:
|
||||
update = PendingHostUpdate.updateAppWidget(appWidgetId,
|
||||
cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
|
||||
break;
|
||||
default:
|
||||
update = PendingHostUpdate.viewDataChanged(appWidgetId, id);
|
||||
}
|
||||
outUpdates.put(time, update);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3850,6 +3897,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
}
|
||||
}
|
||||
|
||||
// These can be any constants that would not collide with a resource id.
|
||||
private static final int ID_VIEWS_UPDATE = 0;
|
||||
private static final int ID_PROVIDER_CHANGED = 1;
|
||||
|
||||
private static final class Widget {
|
||||
int appWidgetId;
|
||||
int restoredId; // tracking & remapping any restored state
|
||||
@@ -3858,7 +3909,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
|
||||
RemoteViews maskedViews;
|
||||
Bundle options;
|
||||
Host host;
|
||||
long lastUpdateTime;
|
||||
// timestamps for various operations
|
||||
SparseLongArray updateTimes = new SparseLongArray(2);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
Reference in New Issue
Block a user