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

Commit 302ecabf authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fixing Fallback recents crashes when going to modal state

> Adding robo tests to prevent such regressions
Bug: 155570625

Change-Id: I5cfbfc454849116f881322e8785dfdbad6f24d08
parent 0e0bcc76
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -371,4 +371,16 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
    protected DepthController getDepthController() {
        return mActivity.getDepthController();
    }

    @Override
    public void setModalStateEnabled(boolean isModalState) {
        super.setModalStateEnabled(isModalState);
        if (isModalState) {
            mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK);
        } else {
            if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
                mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
            }
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -2177,6 +2177,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
        return null;
    }

    /**
     * Enables or disables modal state for RecentsView
     * @param isModalState
     */
    public void setModalStateEnabled(boolean isModalState) { }

    /**
     * Used to register callbacks for when our empty message state changes.
     *
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.quickstep;

import static com.android.launcher3.util.LauncherUIHelper.doLayout;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;

import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;


@RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED)
public class RecentsActivityTest {

    @Test
    public void testRecentsActivityCreates() {
        ActivityController<RecentsActivity> controller =
                Robolectric.buildActivity(RecentsActivity.class);

        RecentsActivity launcher = controller.setup().get();
        doLayout(launcher);

        // TODO: Ensure that LauncherAppState is not created
    }

    @Test
    public void testRecets_showCurrentTask() {
        ActivityController<RecentsActivity> controller =
                Robolectric.buildActivity(RecentsActivity.class);

        RecentsActivity activity = controller.setup().get();
        doLayout(activity);

        FallbackRecentsView frv = activity.getOverviewPanel();
        frv.showCurrentTask(22);
        doLayout(activity);

        ThumbnailData thumbnailData = new ThumbnailData();
        ReflectionHelpers.setField(thumbnailData, "thumbnail",
                Bitmap.createBitmap(300, 500, Config.ARGB_8888));
        frv.switchToScreenshot(thumbnailData, () -> { });
        ShadowLooper.idleMainLooper();
    }
}
+13 −13
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import android.view.MotionEvent;
import android.widget.TextView;

import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +44,7 @@ public class Snackbar extends AbstractFloatingView {
    private static final long HIDE_DURATION_MS = 180;
    private static final int TIMEOUT_DURATION_MS = 4000;

    private final Launcher mLauncher;
    private final BaseDraggingActivity mActivity;
    private Runnable mOnDismissed;

    public Snackbar(Context context, AttributeSet attrs) {
@@ -53,25 +53,25 @@ public class Snackbar extends AbstractFloatingView {

    public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mLauncher = Launcher.getLauncher(context);
        mActivity = BaseDraggingActivity.fromContext(context);
        inflate(context, R.layout.snackbar, this);
    }

    public static void show(Launcher launcher, int labelStringResId, int actionStringResId,
            Runnable onDismissed, Runnable onActionClicked) {
        closeOpenViews(launcher, true, TYPE_SNACKBAR);
        Snackbar snackbar = new Snackbar(launcher, null);
    public static void show(BaseDraggingActivity activity, int labelStringResId,
            int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
        closeOpenViews(activity, true, TYPE_SNACKBAR);
        Snackbar snackbar = new Snackbar(activity, null);
        // Set some properties here since inflated xml only contains the children.
        snackbar.setOrientation(HORIZONTAL);
        snackbar.setGravity(Gravity.CENTER_VERTICAL);
        Resources res = launcher.getResources();
        Resources res = activity.getResources();
        snackbar.setElevation(res.getDimension(R.dimen.snackbar_elevation));
        int padding = res.getDimensionPixelSize(R.dimen.snackbar_padding);
        snackbar.setPadding(padding, padding, padding, padding);
        snackbar.setBackgroundResource(R.drawable.round_rect_primary);

        snackbar.mIsOpen = true;
        DragLayer dragLayer = launcher.getDragLayer();
        BaseDragLayer dragLayer = activity.getDragLayer();
        dragLayer.addView(snackbar);

        DragLayer.LayoutParams params = (DragLayer.LayoutParams) snackbar.getLayoutParams();
@@ -80,7 +80,7 @@ public class Snackbar extends AbstractFloatingView {
        int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right);
        int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right);
        int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom);
        Rect insets = launcher.getDeviceProfile().getInsets();
        Rect insets = activity.getDeviceProfile().getInsets();
        int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right;
        int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right;
        params.width = minWidth;
@@ -135,7 +135,7 @@ public class Snackbar extends AbstractFloatingView {
                .setDuration(SHOW_DURATION_MS)
                .setInterpolator(Interpolators.ACCEL_DEACCEL)
                .start();
        int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(launcher,
        int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(activity,
                TIMEOUT_DURATION_MS, FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS);
        snackbar.postDelayed(() -> snackbar.close(true), timeout);
    }
@@ -160,7 +160,7 @@ public class Snackbar extends AbstractFloatingView {
    }

    private void onClosed() {
        mLauncher.getDragLayer().removeView(this);
        mActivity.getDragLayer().removeView(this);
        if (mOnDismissed != null) {
            mOnDismissed.run();
        }
@@ -179,7 +179,7 @@ public class Snackbar extends AbstractFloatingView {
    @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            DragLayer dl = mLauncher.getDragLayer();
            BaseDragLayer dl = mActivity.getDragLayer();
            if (!dl.isEventOverView(this, ev)) {
                close(true);
            }