Loading core/java/android/appwidget/AppWidgetHost.java +15 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading core/java/android/appwidget/PendingHostUpdate.java 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * 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]; } }; } core/java/com/android/internal/appwidget/IAppWidgetService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +76 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -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; Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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); Loading Loading @@ -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: { Loading @@ -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; } } Loading Loading @@ -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); } return null; outUpdates.put(time, update); } return true; } } return false; } @Override Loading Loading @@ -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 Loading @@ -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() { Loading Loading
core/java/android/appwidget/AppWidgetHost.java +15 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading
core/java/android/appwidget/PendingHostUpdate.java 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * 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]; } }; }
core/java/com/android/internal/appwidget/IAppWidgetService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +76 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -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; Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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); Loading Loading @@ -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: { Loading @@ -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; } } Loading Loading @@ -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); } return null; outUpdates.put(time, update); } return true; } } return false; } @Override Loading Loading @@ -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 Loading @@ -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() { Loading