Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57b77c44 authored by Pierre Barbier de Reuille's avatar Pierre Barbier de Reuille Committed by Automerger Merge Worker
Browse files

Merge "Save/restore view states when reapplying RemoteViews for color changes"...

Merge "Save/restore view states when reapplying RemoteViews for color changes" into sc-dev am: 6d82bd39

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14294133

Change-Id: I04f6a140f7badde59cdc438e6e511e256a479449
parents b15d26c9 6d82bd39
Loading
Loading
Loading
Loading
+49 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.appwidget;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityOptions;
import android.compat.annotation.UnsupportedAppUsage;
@@ -68,6 +69,7 @@ public class AppWidgetHostView extends FrameLayout {

    static final String TAG = "AppWidgetHostView";
    private static final String KEY_JAILED_ARRAY = "jail";
    private static final String KEY_INFLATION_ID = "inflation_id";

    static final boolean LOGD = false;

@@ -97,9 +99,12 @@ public class AppWidgetHostView extends FrameLayout {
    private RemoteViews.ColorResources mColorResources = null;
    // Stores the last remote views last inflated.
    private RemoteViews mLastInflatedRemoteViews = null;
    private long mLastInflatedRemoteViewsId = -1;

    private Executor mAsyncExecutor;
    private CancellationSignal mLastExecutionSignal;
    private SparseArray<Parcelable> mDelayedRestoredState;
    private long mDelayedRestoredInflationId;

    /**
     * Create a host view.  Uses default fade animations.
@@ -226,6 +231,8 @@ public class AppWidgetHostView extends FrameLayout {

        Bundle bundle = new Bundle();
        bundle.putSparseParcelableArray(KEY_JAILED_ARRAY, jail);
        bundle.putLong(KEY_INFLATION_ID, mLastInflatedRemoteViewsId);
        container.put(generateId(), bundle);
        container.put(generateId(), bundle);
    }

@@ -239,14 +246,30 @@ public class AppWidgetHostView extends FrameLayout {
        final Parcelable parcelable = container.get(generateId());

        SparseArray<Parcelable> jail = null;
        long inflationId = -1;
        if (parcelable instanceof Bundle) {
            jail = ((Bundle) parcelable).getSparseParcelableArray(KEY_JAILED_ARRAY);
            Bundle bundle = (Bundle) parcelable;
            jail = bundle.getSparseParcelableArray(KEY_JAILED_ARRAY);
            inflationId = bundle.getLong(KEY_INFLATION_ID, -1);
        }

        if (jail == null) jail = new SparseArray<>();

        mDelayedRestoredState = jail;
        mDelayedRestoredInflationId = inflationId;
        restoreInstanceState();
    }

    void restoreInstanceState() {
        long inflationId = mDelayedRestoredInflationId;
        SparseArray<Parcelable> state = mDelayedRestoredState;
        if (inflationId == -1 || inflationId != mLastInflatedRemoteViewsId) {
            return; // We don't restore.
        }
        mDelayedRestoredInflationId = -1;
        mDelayedRestoredState = null;
        try  {
            super.dispatchRestoreInstanceState(jail);
            super.dispatchRestoreInstanceState(state);
        } catch (Exception e) {
            Log.e(TAG, "failed to restoreInstanceState for widget id: " + mAppWidgetId + ", "
                    + (mInfo == null ? "null" : mInfo.provider), e);
@@ -476,7 +499,7 @@ public class AppWidgetHostView extends FrameLayout {
     * AppWidget provider. Will animate into these new views as needed
     */
    public void updateAppWidget(RemoteViews remoteViews) {
        this.mLastInflatedRemoteViews = remoteViews;
        mLastInflatedRemoteViews = remoteViews;
        applyRemoteViews(remoteViews, true);
    }

@@ -484,17 +507,23 @@ public class AppWidgetHostView extends FrameLayout {
     * Reapply the last inflated remote views, or the default view is none was inflated.
     */
    private void reapplyLastRemoteViews() {
        SparseArray<Parcelable> savedState = new SparseArray<>();
        saveHierarchyState(savedState);
        applyRemoteViews(mLastInflatedRemoteViews, true);
        restoreHierarchyState(savedState);
    }

    /**
     * @hide
     */
    protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) {
    protected void applyRemoteViews(@Nullable RemoteViews remoteViews, boolean useAsyncIfPossible) {
        boolean recycled = false;
        View content = null;
        Exception exception = null;

        // Block state restore until the end of the apply.
        mLastInflatedRemoteViewsId = -1;

        if (mLastExecutionSignal != null) {
            mLastExecutionSignal.cancel();
            mLastExecutionSignal = null;
@@ -525,6 +554,7 @@ public class AppWidgetHostView extends FrameLayout {
                    rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
                            mColorResources);
                    content = mView;
                    mLastInflatedRemoteViewsId = rvToApply.computeUniqueId(remoteViews);
                    recycled = true;
                    if (LOGD) Log.d(TAG, "was able to recycle existing layout");
                } catch (RuntimeException e) {
@@ -537,6 +567,7 @@ public class AppWidgetHostView extends FrameLayout {
                try {
                    content = rvToApply.apply(mContext, this, mInteractionHandler,
                            mCurrentSize, mColorResources);
                    mLastInflatedRemoteViewsId = rvToApply.computeUniqueId(remoteViews);
                    if (LOGD) Log.d(TAG, "had to inflate new layout");
                } catch (RuntimeException e) {
                    exception = e;
@@ -574,12 +605,16 @@ public class AppWidgetHostView extends FrameLayout {
        }
    }

    private void inflateAsync(RemoteViews remoteViews) {
    private void inflateAsync(@NonNull RemoteViews remoteViews) {
        // Prepare a local reference to the remote Context so we're ready to
        // inflate any requested LayoutParams.
        mRemoteContext = getRemoteContext();
        int layoutId = remoteViews.getLayoutId();

        if (mLastExecutionSignal != null) {
            mLastExecutionSignal.cancel();
        }

        // If our stale view has been prepared to match active, and the new
        // layout matches, try recycling it
        if (layoutId == mLayoutId && mView != null) {
@@ -611,7 +646,10 @@ public class AppWidgetHostView extends FrameLayout {
        private final boolean mIsReapply;
        private final int mLayoutId;

        public ViewApplyListener(RemoteViews views, int layoutId, boolean isReapply) {
        ViewApplyListener(
                RemoteViews views,
                int layoutId,
                boolean isReapply) {
            mViews = views;
            mLayoutId = layoutId;
            mIsReapply = isReapply;
@@ -623,6 +661,10 @@ public class AppWidgetHostView extends FrameLayout {
            mViewMode = VIEW_MODE_CONTENT;

            applyContent(v, mIsReapply, null);

            mLastInflatedRemoteViewsId = mViews.computeUniqueId(mLastInflatedRemoteViews);
            restoreInstanceState();
            mLastExecutionSignal = null;
        }

        @Override
@@ -638,6 +680,7 @@ public class AppWidgetHostView extends FrameLayout {
            } else {
                applyContent(null, false, e);
            }
            mLastExecutionSignal = null;
        }
    }

+89 −0
Original line number Diff line number Diff line
@@ -385,6 +385,11 @@ public class RemoteViews implements Parcelable, Filter {
     */
    private int mViewId = View.NO_ID;

    /**
     * Id used to uniquely identify a {@link RemoteViews} instance coming from a given provider.
     */
    private long mProviderInstanceId = -1;

    /** Class cookies of the Parcel this instance was read from. */
    private Map<Class, Object> mClassCookies;

@@ -3646,6 +3651,7 @@ public class RemoteViews implements Parcelable, Filter {
        mApplyFlags = src.mApplyFlags;
        mClassCookies = src.mClassCookies;
        mIdealSize = src.mIdealSize;
        mProviderInstanceId = src.mProviderInstanceId;

        if (src.hasLandscapeAndPortraitLayouts()) {
            mLandscape = new RemoteViews(src.mLandscape);
@@ -3744,6 +3750,7 @@ public class RemoteViews implements Parcelable, Filter {
            mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
        }
        mApplyFlags = parcel.readInt();
        mProviderInstanceId = parcel.readLong();
    }

    private void readActionsFromParcel(Parcel parcel, int depth) {
@@ -6021,6 +6028,7 @@ public class RemoteViews implements Parcelable, Filter {
            mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
        }
        dest.writeInt(mApplyFlags);
        dest.writeLong(mProviderInstanceId);
    }

    private void writeActionsToParcel(Parcel parcel) {
@@ -6711,4 +6719,85 @@ public class RemoteViews implements Parcelable, Filter {
    public @IdRes int getViewId() {
        return mViewId;
    }

    /**
     * Set the provider instance ID.
     *
     * This should only be used by {@link com.android.server.appwidget.AppWidgetService}.
     * @hide
     */
    public void setProviderInstanceId(long id) {
        mProviderInstanceId = id;
    }

    /**
     * Get the provider instance id.
     *
     * This should uniquely identifies {@link RemoteViews} coming from a given App Widget
     * Provider. This changes each time the App Widget provider update the {@link RemoteViews} of
     * its widget. Returns -1 if the {@link RemoteViews} doesn't come from an App Widget provider.
     * @hide
     */
    public long getProviderInstanceId() {
        return mProviderInstanceId;
    }

    /**
     * Identify the child of this {@link RemoteViews}, or 0 if this is not a child.
     *
     * The returned value is always a small integer, currently between 0 and 17.
     */
    private int getChildId(@NonNull RemoteViews child) {
        if (child == this) {
            return 0;
        }
        if (hasSizedRemoteViews()) {
            for (int i = 0; i < mSizedRemoteViews.size(); i++) {
                if (mSizedRemoteViews.get(i) == child) {
                    return i + 1;
                }
            }
        }
        if (hasLandscapeAndPortraitLayouts()) {
            if (mLandscape == child) {
                return 1;
            } else if (mPortrait == child) {
                return 2;
            }
        }
        // This is not a child of this RemoteViews.
        return 0;
    }

    /**
     * Identify uniquely this RemoteViews, or returns -1 if not possible.
     *
     * @param parent If the {@link RemoteViews} is not a root {@link RemoteViews}, this should be
     *              the parent that contains it.
     *
     * @hide
     */
    public long computeUniqueId(@Nullable RemoteViews parent) {
        if (mIsRoot) {
            long viewId = getProviderInstanceId();
            if (viewId != -1) {
                viewId <<= 8;
            }
            return viewId;
        }
        if (parent == null) {
            return -1;
        }
        long viewId = parent.getProviderInstanceId();
        if (viewId == -1) {
            return -1;
        }
        int childId = parent.getChildId(this);
        if (childId == -1) {
            return -1;
        }
        viewId <<= 8;
        viewId |= childId;
        return viewId;
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -86,8 +86,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
    // Default height for the default loading view, in case we cannot get inflate the first view
    private static final int DEFAULT_LOADING_VIEW_HEIGHT = 50;

    // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
    // structures;
    // We cache the FixedSizeRemoteViewsCaches across orientation and re-inflation due to color
    // palette changes. These are the related data structures:
    private static final HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>
            sCachedRemoteViewsCaches = new HashMap<>();
    private static final HashMap<RemoteViewsCacheKey, Runnable>
+5 −0
Original line number Diff line number Diff line
@@ -1839,6 +1839,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
                // For a full update we replace the RemoteViews completely.
                widget.views = views;
            }
            widget.views.setProviderInstanceId(UPDATE_COUNTER.get());

            int memoryUsage;
            if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
                    (widget.views != null) &&
@@ -1939,6 +1941,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
                || widget.host.callbacks == null || widget.host.zombie) {
            return;
        }
        if (updateViews != null) {
            updateViews.setProviderInstanceId(requestId);
        }

        SomeArgs args = SomeArgs.obtain();
        args.arg1 = widget.host;