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

Commit 7b0e2c76 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fixing async inflation for nested RemoteViews

> Fixing isRootNamespace check
> Updating ViewTree when ViewStub is inflated
> Applying ViewGroupAction on previously found views instead of finding it again
  as the viewTree might have changed.

Test: am instrument -w -e class android.widget.RemoteViewsTest com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
Bug: 32639592

Change-Id: I0815fb3a981efbc04fb0d080b81949985c2d9bc3
parent 5f667270
Loading
Loading
Loading
Loading
+69 −27
Original line number Diff line number Diff line
@@ -142,11 +142,17 @@ public final class ViewStub extends View {
     * @see #getInflatedId()
     * @attr ref android.R.styleable#ViewStub_inflatedId
     */
    @android.view.RemotableViewMethod
    @android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync")
    public void setInflatedId(@IdRes int inflatedId) {
        mInflatedId = inflatedId;
    }

    /** @hide **/
    public Runnable setInflatedIdAsync(@IdRes int inflatedId) {
        mInflatedId = inflatedId;
        return null;
    }

    /**
     * Returns the layout resource that will be used by {@link #setVisibility(int)} or
     * {@link #inflate()} to replace this StubbedView
@@ -176,11 +182,17 @@ public final class ViewStub extends View {
     * @see #inflate()
     * @attr ref android.R.styleable#ViewStub_layout
     */
    @android.view.RemotableViewMethod
    @android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync")
    public void setLayoutResource(@LayoutRes int layoutResource) {
        mLayoutResource = layoutResource;
    }

    /** @hide **/
    public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) {
        mLayoutResource = layoutResource;
        return null;
    }

    /**
     * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null}
     * to use the default.
@@ -220,7 +232,7 @@ public final class ViewStub extends View {
     * @see #inflate() 
     */
    @Override
    @android.view.RemotableViewMethod
    @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
    public void setVisibility(int visibility) {
        if (mInflatedViewRef != null) {
            View view = mInflatedViewRef.get();
@@ -237,32 +249,32 @@ public final class ViewStub extends View {
        }
    }

    /**
     * Inflates the layout resource identified by {@link #getLayoutResource()}
     * and replaces this StubbedView in its parent by the inflated layout resource.
     *
     * @return The inflated layout resource.
     *
     */
    public View inflate() {
        final ViewParent viewParent = getParent();
    /** @hide **/
    public Runnable setVisibilityAsync(int visibility) {
        if (visibility == VISIBLE || visibility == INVISIBLE) {
            ViewGroup parent = (ViewGroup) getParent();
            return new ViewReplaceRunnable(inflateViewNoAdd(parent));
        } else {
            return null;
        }
    }

        if (viewParent != null && viewParent instanceof ViewGroup) {
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
    private View inflateViewNoAdd(ViewGroup parent) {
        final LayoutInflater factory;
        if (mInflater != null) {
            factory = mInflater;
        } else {
            factory = LayoutInflater.from(mContext);
        }
                final View view = factory.inflate(mLayoutResource, parent,
                        false);
        final View view = factory.inflate(mLayoutResource, parent, false);

        if (mInflatedId != NO_ID) {
            view.setId(mInflatedId);
        }
        return view;
    }

    private void replaceSelfWithView(View view, ViewGroup parent) {
        final int index = parent.indexOfChild(this);
        parent.removeViewInLayout(this);

@@ -272,9 +284,25 @@ public final class ViewStub extends View {
        } else {
            parent.addView(view, index);
        }
    }

    /**
     * Inflates the layout resource identified by {@link #getLayoutResource()}
     * and replaces this StubbedView in its parent by the inflated layout resource.
     *
     * @return The inflated layout resource.
     *
     */
    public View inflate() {
        final ViewParent viewParent = getParent();

                mInflatedViewRef = new WeakReference<View>(view);
        if (viewParent != null && viewParent instanceof ViewGroup) {
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
                final View view = inflateViewNoAdd(parent);
                replaceSelfWithView(view, parent);

                mInflatedViewRef = new WeakReference<>(view);
                if (mInflateListener != null) {
                    mInflateListener.onInflate(this, view);
                }
@@ -317,4 +345,18 @@ public final class ViewStub extends View {
         */
        void onInflate(ViewStub stub, View inflated);
    }

    /** @hide **/
    public class ViewReplaceRunnable implements Runnable {
        public final View view;

        ViewReplaceRunnable(View view) {
            this.view = view;
        }

        @Override
        public void run() {
            replaceSelfWithView(view, (ViewGroup) getParent());
        }
    }
}
+37 −9
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.view.RemotableViewMethod;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.AdapterView.OnItemClickListener;

import com.android.internal.R;
@@ -1456,6 +1457,13 @@ public class RemoteViews implements Parcelable, Filter {
                    if (endAction == null) {
                        return ACTION_NOOP;
                    } else {
                        // Special case view stub
                        if (endAction instanceof ViewStub.ViewReplaceRunnable) {
                            root.createTree();
                            // Replace child tree
                            root.findViewTreeById(viewId).replaceView(
                                    ((ViewStub.ViewReplaceRunnable) endAction).view);
                        }
                        return new RunnableAction(endAction);
                    }
                }
@@ -1581,16 +1589,26 @@ public class RemoteViews implements Parcelable, Filter {
            if ((target == null) || !(target.mRoot instanceof ViewGroup)) {
                return ACTION_NOOP;
            }
            final ViewGroup targetVg = (ViewGroup) target.mRoot;
            if (nestedViews == null) {
                // Clear all children when nested views omitted
                target.mChildren = null;
                return this;
                return new RuntimeAction() {
                    @Override
                    public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
                            throws ActionException {
                        targetVg.removeAllViews();
                    }
                };
            } else {
                // Inflate nested views and perform all the async tasks for the child remoteView.
                final Context context = root.mRoot.getContext();
                final AsyncApplyTask task = nestedViews.getAsyncApplyTask(
                        context, (ViewGroup) target.mRoot, null, handler);
                        context, targetVg, null, handler);
                final ViewTree tree = task.doInBackground();
                if (tree == null) {
                    throw new ActionException(task.mError);
                }

                // Update the global view tree, so that next call to findViewTreeById
                // goes through the subtree as well.
@@ -1600,10 +1618,8 @@ public class RemoteViews implements Parcelable, Filter {

                    @Override
                    public void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException {
                        // This view will exist as we have already made sure
                        final ViewGroup target = (ViewGroup) root.findViewById(viewId);
                        task.onPostExecute(tree);
                        target.addView(task.mResult);
                        targetVg.addView(task.mResult);
                    }
                };
            }
@@ -3360,7 +3376,7 @@ public class RemoteViews implements Parcelable, Filter {
                    int count = mRV.mActions.size();
                    mActions = new Action[count];
                    for (int i = 0; i < count && !isCancelled(); i++) {
                        // TODO: check if isCanclled in nested views.
                        // TODO: check if isCancelled in nested views.
                        mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler);
                    }
                } else {
@@ -3629,7 +3645,7 @@ public class RemoteViews implements Parcelable, Filter {
     * and can be searched.
     */
    private static class ViewTree {
        private final View mRoot;
        private View mRoot;

        private ArrayList<ViewTree> mChildren;

@@ -3643,7 +3659,7 @@ public class RemoteViews implements Parcelable, Filter {
            }

            mChildren = new ArrayList<>();
            if (mRoot instanceof ViewGroup && mRoot.isRootNamespace()) {
            if (mRoot instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) mRoot;
                int count = vg.getChildCount();
                for (int i = 0; i < count; i++) {
@@ -3668,6 +3684,12 @@ public class RemoteViews implements Parcelable, Filter {
            return null;
        }

        public void replaceView(View v) {
            mRoot = v;
            mChildren = null;
            createTree();
        }

        public View findViewById(int id) {
            if (mChildren == null) {
                return mRoot.findViewById(id);
@@ -3685,6 +3707,12 @@ public class RemoteViews implements Parcelable, Filter {
        }

        private void addViewChild(View v) {
            // ViewTree only contains Views which can be found using findViewById.
            // If isRootNamespace is true, this view is skipped.
            // @see ViewGroup#findViewTraversal(int)
            if (v.isRootNamespace()) {
                return;
            }
            final ViewTree target;

            // If the view has a valid id, i.e., if can be found using findViewById, add it to the
@@ -3697,7 +3725,7 @@ public class RemoteViews implements Parcelable, Filter {
                target = this;
            }

            if (v instanceof ViewGroup && v.isRootNamespace()) {
            if (v instanceof ViewGroup) {
                if (target.mChildren == null) {
                    target.mChildren = new ArrayList<>();
                    ViewGroup vg = (ViewGroup) v;
+2 −2
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</LinearLayout>
    android:layout_height="match_parent" />
+21 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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
  -->

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
+27 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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
  -->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1">

    <ViewStub android:id="@+id/viewStub"
              android:inflatedId="@+id/stub_inflated"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />
</FrameLayout>
Loading