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

Commit c79d577f authored by Brian Isganitis's avatar Brian Isganitis
Browse files

Load widgets in wallpaper app launcher preview

Test: Widgets in wallpaper app launcher preview rendered
Bug: 185306338
Change-Id: I38569d2ff0b64ba55eb188afa42fba4100aae7ff
parent 485796e8
Loading
Loading
Loading
Loading
+49 −8
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially

import android.annotation.TargetApi;
import android.app.Fragment;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
@@ -83,6 +84,8 @@ import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetHost;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
@@ -202,6 +205,7 @@ public class LauncherPreviewRenderer extends ContextWrapper
    private final InsettableFrameLayout mRootView;
    private final Hotseat mHotseat;
    private final CellLayout mWorkspace;
    private final AppWidgetHost mAppWidgetHost;

    public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp) {
        super(context);
@@ -255,6 +259,10 @@ public class LauncherPreviewRenderer extends ContextWrapper
                mDp.workspacePadding.top,
                mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
                mDp.workspacePadding.bottom);

        mAppWidgetHost = FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()
                ? new LauncherPreviewAppWidgetHost(context)
                : null;
    }

    /** Populate preview and render it. */
@@ -354,7 +362,11 @@ public class LauncherPreviewRenderer extends ContextWrapper

    private void inflateAndAddWidgets(
            LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
        AppWidgetHostView view = new NavigableAppWidgetHostView(this) {
        AppWidgetHostView view;
        if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
            view = mAppWidgetHost.createView(mContext, info.appWidgetId, providerInfo);
        } else {
            view = new NavigableAppWidgetHostView(this) {
                @Override
                protected boolean shouldAllowDirectClick() {
                    return false;
@@ -362,6 +374,8 @@ public class LauncherPreviewRenderer extends ContextWrapper
            };
            view.setAppWidget(-1, providerInfo);
            view.updateAppWidget(null);
        }

        view.setTag(info);
        addInScreenFromBind(view, info);
    }
@@ -477,4 +491,31 @@ public class LauncherPreviewRenderer extends ContextWrapper
        view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
        view.layout(0, 0, width, height);
    }

    private class LauncherPreviewAppWidgetHost extends AppWidgetHost {

        private LauncherPreviewAppWidgetHost(Context context) {
            super(context, LauncherAppWidgetHost.APPWIDGET_HOST_ID);
        }

        @Override
        protected AppWidgetHostView onCreateView(
                Context context,
                int appWidgetId,
                AppWidgetProviderInfo appWidget) {
            return new LauncherPreviewAppWidgetHostView(LauncherPreviewRenderer.this);
        }
    }

    private static class LauncherPreviewAppWidgetHostView extends BaseLauncherAppWidgetHostView {

        private LauncherPreviewAppWidgetHostView(Context context) {
            super(context);
        }

        @Override
        protected boolean shouldAllowDirectClick() {
            return false;
        }
    }
}
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 com.android.launcher3.widget;

import android.content.Context;
import android.graphics.Outline;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.RemoteViews;

import androidx.annotation.UiThread;

import com.android.launcher3.R;
import com.android.launcher3.util.Executors;

/**
 * Launcher AppWidgetHostView with support for rounded corners and a fallback View.
 */
public abstract class BaseLauncherAppWidgetHostView extends NavigableAppWidgetHostView {

    protected final LayoutInflater mInflater;

    private final Rect mEnforcedRectangle = new Rect();
    private final float mEnforcedCornerRadius;
    private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
                outline.setEmpty();
            } else {
                outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
            }
        }
    };

    public BaseLauncherAppWidgetHostView(Context context) {
        super(context);

        setExecutor(Executors.THREAD_POOL_EXECUTOR);

        mInflater = LayoutInflater.from(context);
        mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
    }

    @Override
    protected View getErrorView() {
        return mInflater.inflate(R.layout.appwidget_error, this, false);
    }

    /**
     * Fall back to error layout instead of showing widget.
     */
    public void switchToErrorView() {
        // Update the widget with 0 Layout id, to reset the view to error view.
        updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        try {
            super.onLayout(changed, left, top, right, bottom);
        } catch (final RuntimeException e) {
            post(this::switchToErrorView);
        }

        enforceRoundedCorners();
    }

    @UiThread
    private void resetRoundedCorners() {
        setOutlineProvider(ViewOutlineProvider.BACKGROUND);
        setClipToOutline(false);
    }

    @UiThread
    private void enforceRoundedCorners() {
        if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
            resetRoundedCorners();
            return;
        }
        View background = RoundedCornerEnforcement.findBackground(this);
        if (background == null
                || RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
            resetRoundedCorners();
            return;
        }
        RoundedCornerEnforcement.computeRoundedRectangle(this,
                background,
                mEnforcedRectangle);
        setOutlineProvider(mCornerRadiusEnforcementOutline);
        setClipToOutline(true);
    }

    /** Returns the corner radius currently enforced, in pixels. */
    public float getEnforcedCornerRadius() {
        return mEnforcedCornerRadius;
    }

    /** Returns true if the corner radius are enforced for this App Widget. */
    public boolean hasEnforcedCornerRadius() {
        return getClipToOutline();
    }
}
+2 −82
Original line number Diff line number Diff line
@@ -20,19 +20,16 @@ import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AdapterView;
import android.widget.Advanceable;
@@ -40,7 +37,6 @@ import android.widget.RemoteViews;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;

import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Launcher;
@@ -51,7 +47,6 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
@@ -61,7 +56,7 @@ import java.util.List;
/**
 * {@inheritDoc}
 */
public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
        implements TouchCompleteListener, View.OnLongClickListener,
        LocalColorExtractor.Listener {

@@ -76,8 +71,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
    // Maximum duration for which updates can be deferred.
    private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;

    protected final LayoutInflater mInflater;

    private final CheckLongPressHelper mLongPressHelper;
    protected final Launcher mLauncher;
    private final Workspace mWorkspace;
@@ -101,18 +94,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
    private final Rect mWidgetSizeAtDrag = new Rect();

    private final RectF mTempRectF = new RectF();
    private final Rect mEnforcedRectangle = new Rect();
    private final float mEnforcedCornerRadius;
    private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
                outline.setEmpty();
            } else {
                outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
            }
        }
    };
    private final Object mUpdateLock = new Object();
    private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
    private long mDeferUpdatesUntilMillis = 0;
@@ -123,18 +104,15 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
        mLauncher = Launcher.getLauncher(context);
        mWorkspace = mLauncher.getWorkspace();
        mLongPressHelper = new CheckLongPressHelper(this, this);
        mInflater = LayoutInflater.from(context);
        setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
        setBackgroundResource(R.drawable.widget_internal_focus_bg);

        setExecutor(Executors.THREAD_POOL_EXECUTOR);
        if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
            setOnLightBackground(true);
        }
        mColorExtractor = LocalColorExtractor.newInstance(getContext());
        mColorExtractor.setListener(this);

        mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
        mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
    }

@@ -165,11 +143,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
        return true;
    }

    @Override
    protected View getErrorView() {
        return mInflater.inflate(R.layout.appwidget_error, this, false);
    }

    @Override
    public void updateAppWidget(RemoteViews remoteViews) {
        synchronized (mUpdateLock) {
@@ -304,34 +277,17 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
        }
    }

    public void switchToErrorView() {
        // Update the widget with 0 Layout id, to reset the view to error view.
        updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        try {
        super.onLayout(changed, left, top, right, bottom);
        } catch (final RuntimeException e) {
            post(new Runnable() {
                @Override
                public void run() {
                    switchToErrorView();
                }
            });
        }

        mIsScrollable = checkScrollableRecursively(this);
        if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {

            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
            mDragLayerRelativeCoordinateHelper.viewToRect(this, mCurrentWidgetSize);
            updateColorExtraction(mCurrentWidgetSize,
                    mWorkspace.getPageIndexForScreenId(info.screenId));
        }

        enforceRoundedCorners();
    }

    /** Starts the drag mode. */
@@ -502,40 +458,4 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
        }
        return false;
    }

    @UiThread
    private void resetRoundedCorners() {
        setOutlineProvider(ViewOutlineProvider.BACKGROUND);
        setClipToOutline(false);
    }

    @UiThread
    private void enforceRoundedCorners() {
        if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
            resetRoundedCorners();
            return;
        }
        View background = RoundedCornerEnforcement.findBackground(this);
        if (background == null
                || RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
            resetRoundedCorners();
            return;
        }
        RoundedCornerEnforcement.computeRoundedRectangle(this,
                background,
                mEnforcedRectangle);
        setOutlineProvider(mCornerRadiusEnforcementOutline);
        setClipToOutline(true);
    }

    /** Returns the corner radius currently enforced, in pixels. */
    public float getEnforcedCornerRadius() {
        return mEnforcedCornerRadius;
    }

    /** Returns true if the corner radius are enforced for this App Widget. */
    public boolean hasEnforcedCornerRadius() {
        return getClipToOutline();
    }

}