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

Commit 6b83f955 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Reusing RemoteViews logic to inflate default views in widgetHost" into main

parents 7b85af82 6bc57a0a
Loading
Loading
Loading
Loading
+28 −75
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.appwidget;

import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
import static android.appwidget.flags.Flags.FLAG_ENGAGEMENT_METRICS;
import static android.appwidget.flags.Flags.engagementMetrics;
import static android.content.res.Flags.selfTargetingAndroidResourceFrro;
@@ -34,7 +36,6 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -51,7 +52,6 @@ import android.util.SizeF;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -89,18 +89,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
    static final int VIEW_MODE_ERROR = 2;
    static final int VIEW_MODE_DEFAULT = 3;

    // Set of valid colors resources.
    private static final int FIRST_RESOURCE_COLOR_ID = android.R.color.system_neutral1_0;
    private static final int LAST_RESOURCE_COLOR_ID = android.R.color.system_accent3_1000;

    // When we're inflating the initialLayout for a AppWidget, we only allow
    // views that are allowed in RemoteViews.
    private static final LayoutInflater.Filter INFLATER_FILTER =
            (clazz) -> clazz.isAnnotationPresent(RemoteViews.RemoteView.class);

    Context mContext;
    Context mRemoteContext;

    @UnsupportedAppUsage
    int mAppWidgetId;
    @UnsupportedAppUsage
@@ -148,7 +136,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
    @SuppressWarnings({"UnusedDeclaration"})
    public AppWidgetHostView(Context context, int animationIn, int animationOut) {
        super(context);
        mContext = context;
        // We want to segregate the view ids within AppWidgets to prevent
        // problems when those ids collide with view ids in the AppWidgetHost.
        setIsRootNamespace(true);
@@ -190,12 +177,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
            super(context);
        }

        @Override
        public Context getRemoteContextEnsuringCorrectCachedApkPath() {
            // To reduce noise in error messages
            return null;
        }

        @Override
        protected boolean isVisibilityTrackingPermitted() {
            // Do not track visibility for individual adapter items
@@ -523,14 +504,11 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
        AppWidgetManager.getInstance(mContext).updateAppWidgetOptions(mAppWidgetId, options);
    }

    /** {@inheritDoc} */
    /** @hide **/
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        // We're being asked to inflate parameters, probably by a LayoutInflater
        // in a remote Context. To help resolve any remote references, we
        // inflate through our last mRemoteContext when it exists.
        final Context context = mRemoteContext != null ? mRemoteContext : mContext;
        return new FrameLayout.LayoutParams(context, attrs);
    public LayoutParams generateLayoutParams(Context inflationContext, AttributeSet attrs) {
        // Widget's layout parameter should be inflated in widget's context
        return new FrameLayout.LayoutParams(inflationContext, attrs);
    }

    /**
@@ -626,9 +604,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
                inflateAsync(rvToApply);
                return;
            }
            // Prepare a local reference to the remote Context so we're ready to
            // inflate any requested LayoutParams.
            mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();

            if (!mColorMappingChanged && rvToApply.canRecycleView(mView)) {
                try {
@@ -689,7 +664,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
    private void inflateAsync(@NonNull RemoteViews remoteViews) {
        // Prepare a local reference to the remote Context so we're ready to
        // inflate any requested LayoutParams.
        mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
        int layoutId = remoteViews.getLayoutId();

        if (mLastExecutionSignal != null) {
@@ -788,30 +762,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
        }
    }

    /**
     * Build a {@link Context} cloned into another package name, usually for the
     * purposes of reading remote resources.
     *
     * @hide
     */
    protected Context getRemoteContextEnsuringCorrectCachedApkPath() {
        try {
            Context newContext = mContext.createApplicationContext(
                    mInfo.providerInfo.applicationInfo,
                    Context.CONTEXT_RESTRICTED);
            if (mColorResources != null) {
                mColorResources.apply(newContext);
            }
            return newContext;
        } catch (NameNotFoundException e) {
            Log.e(TAG, "Package name " + mInfo.providerInfo.packageName + " not found");
            return mContext;
        } catch (NullPointerException e) {
            Log.e(TAG, "Error trying to create the remote context.", e);
            return mContext;
        }
    }

    /**
     * Prepare the given view to be shown. This might include adjusting
     * {@link FrameLayout.LayoutParams} before inserting.
@@ -839,33 +789,28 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
        Exception exception = null;

        try {
            if (mInfo != null) {
                Context theirContext = getRemoteContextEnsuringCorrectCachedApkPath();
                mRemoteContext = theirContext;
                LayoutInflater inflater = (LayoutInflater)
                        theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                inflater = inflater.cloneInContext(theirContext);
                inflater.setFilter(INFLATER_FILTER);
                AppWidgetManager manager = AppWidgetManager.getInstance(mContext);
                Bundle options = manager.getAppWidgetOptions(mAppWidgetId);

            if (mInfo != null && mInfo.initialLayout != 0) {
                int layoutId = mInfo.initialLayout;
                if (options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
                    int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY);
                    if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
                int kgLayoutId = mInfo.initialKeyguardLayout;
                        // If a default keyguard layout is not specified, use the standard
                        // default layout.
                        layoutId = kgLayoutId == 0 ? layoutId : kgLayoutId;
                if (kgLayoutId != 0 && kgLayoutId != layoutId) {
                    // If this this a keyguard widget, use keyguard layout
                    Bundle options = AppWidgetManager.getInstance(mContext)
                            .getAppWidgetOptions(mAppWidgetId);
                    if (options.containsKey(OPTION_APPWIDGET_HOST_CATEGORY)
                            && options.getInt(OPTION_APPWIDGET_HOST_CATEGORY)
                                    == WIDGET_CATEGORY_KEYGUARD) {
                        layoutId = kgLayoutId;
                    }
                }
                defaultView = inflater.inflate(layoutId, this, false);

                defaultView = new RemoteViewsWrapper(mInfo.providerInfo.applicationInfo, layoutId)
                        .apply(mContext, this, mInteractionLogger, null, mColorResources);
                if (!(defaultView instanceof AdapterView)) {
                    // AdapterView does not support onClickListener
                    defaultView.setOnClickListener(this::onDefaultViewClicked);
                }
            } else {
                Log.w(TAG, "can't inflate defaultView because mInfo is missing");
                Log.w(TAG, "can't inflate defaultView, missing defaultLayout, mInfo: " + mInfo);
            }
        } catch (RuntimeException e) {
            exception = e;
@@ -1279,5 +1224,13 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
                + ")";
        }
    }

    private static class RemoteViewsWrapper extends RemoteViews {

        RemoteViewsWrapper(ApplicationInfo application, int layoutId) {
            super(application, layoutId);
        }
    }

}
+5 −4
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ public abstract class LayoutInflater {
                                    root);
                        }
                        // Create layout params that match root, if supplied
                        params = root.generateLayoutParams(attrs);
                        params = root.generateLayoutParams(inflaterContext, attrs);
                        if (!attachToRoot) {
                            // Set the layout params for temp if we are not
                            // attaching. (If we are, we use addView, below)
@@ -1011,7 +1011,8 @@ public abstract class LayoutInflater {
            } else {
                final View view = createViewFromTag(parent, name, context, attrs);
                final ViewGroup viewGroup = (ViewGroup) parent;
                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                final ViewGroup.LayoutParams params =
                        viewGroup.generateLayoutParams(context, attrs);
                rInflateChildren(parser, view, attrs, true);
                viewGroup.addView(view, params);
            }
@@ -1134,12 +1135,12 @@ public abstract class LayoutInflater {
                // tag, false means we need to rely on the included layout params.
                ViewGroup.LayoutParams params = null;
                try {
                    params = group.generateLayoutParams(attrs);
                    params = group.generateLayoutParams(context, attrs);
                } catch (RuntimeException e) {
                    // Ignore, just fail over to child attrs.
                }
                if (params == null) {
                    params = group.generateLayoutParams(childAttrs);
                    params = group.generateLayoutParams(context, childAttrs);
                }
                view.setLayoutParams(params);

+6 −0
Original line number Diff line number Diff line
@@ -6848,6 +6848,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return new LayoutParams(getContext(), attrs);
    }

    /** @hide */
    public LayoutParams generateLayoutParams(Context inflationContext, AttributeSet attrs) {
        // Call the previous method for backwards compatibility
        return generateLayoutParams(attrs);
    }

    /**
     * Returns a safe set of layout parameters based on the supplied layout params.
     * When a ViewGroup is passed a View whose layout params do not pass the test of
+1 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ android_test {
        ":HelloWorldUsingSdk1And2",
        ":HelloWorldUsingSdk1AndSdk1",
        ":HelloWorldUsingSdkMalformedNegativeVersion",
        ":NoUpdateAppWidgetTestApp",
        ":com.android.cts.helpers.aosp",
    ],
}
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
        <option name="test-file-name" value="BinderProxyCountingTestService.apk" />
        <option name="test-file-name" value="AppThatUsesAppOps.apk" />
        <option name="test-file-name" value="AppThatCallsBinderMethods.apk" />
        <option name="test-file-name" value="NoUpdateAppWidgetTestApp.apk" />
    </target_preparer>

    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
Loading