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

Commit 101189e3 authored by Bill Lin's avatar Bill Lin
Browse files

Fix long press and selection(drag) then NPE crash

RecyclerView may return null view holder after calling
findViewHolderForAdapterPosition(position)

Fixes: 131079926
Test: atest FingerSelectionUiTest#testFingerSelection_outOfRange
Test: atest DocumentsUIGoogleTests
Change-Id: I5b73e8b9c399a64704c3808126bde717d1cab051
parent 3b30dc16
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -16,15 +16,16 @@
package com.android.documentsui.dirlist;

import static androidx.core.util.Preconditions.checkArgument;

import static com.android.documentsui.base.DocumentInfo.getCursorInt;
import static com.android.documentsui.base.DocumentInfo.getCursorString;

import android.database.Cursor;
import android.provider.DocumentsContract.Document;
import android.util.Log;

import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;

import com.android.documentsui.ActivityConfig;
import com.android.documentsui.Model;
@@ -89,9 +90,13 @@ final class DocsSelectionPredicate extends SelectionPredicate<String> {

        // The band selection model only operates on documents and directories.
        // Exclude other types of adapter items like whitespace and dividers.
        RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(position);
        final RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(position);
        if (vh == null) {
            return false;
        } else {
            return ModelBackedDocumentsAdapter.isContentType(vh.getItemViewType());
        }
    }

    @Override
    public boolean canSelectMultiple() {
+26 −9
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ public class GestureBot extends Bots.BaseBot {
    private static final int STEPS_INBETWEEN_POINTS = 2;
    // Inserted after each motion event injection.
    private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;
    private static final int LONG_PRESS_EVENT_INJECTION_DELAY_MILIS = 1000;
    private final String mDirContainerId;
    private final String mDirListId;
    private final UiAutomation mAutomation;
@@ -82,10 +83,21 @@ public class GestureBot extends Bots.BaseBot {
        bandSelection(start, end, BAND_SELECTION_DEFAULT_STEPS);
    }

    public void fingerSelection(Point start, Point end) throws Exception {
        fingerSelection(start, end, BAND_SELECTION_DEFAULT_STEPS);
    }

    public void bandSelection(Point start, Point end, int steps) throws Exception {
        int toolType = Configurator.getInstance().getToolType();
        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
        swipe(start.x, start.y, end.x, end.y, steps, MotionEvent.BUTTON_PRIMARY);
        swipe(start.x, start.y, end.x, end.y, steps, MotionEvent.BUTTON_PRIMARY, false);
        Configurator.getInstance().setToolType(toolType);
    }

    private void fingerSelection(Point start, Point end, int steps) throws Exception {
        int toolType = Configurator.getInstance().getToolType();
        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
        swipe(start.x, start.y, end.x, end.y, steps, MotionEvent.BUTTON_PRIMARY, true);
        Configurator.getInstance().setToolType(toolType);
    }

@@ -100,20 +112,25 @@ public class GestureBot extends Bots.BaseBot {
        return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
    }

    private void swipe(int downX, int downY, int upX, int upY, int steps, int button) {
    private void swipe(int downX, int downY, int upX, int upY, int steps, int button,
            boolean fingerSelection) {
        int swipeSteps = steps;
        double xStep = 0;
        double yStep = 0;

        // avoid a divide by zero
        if(swipeSteps == 0)
        if (swipeSteps == 0) {
            swipeSteps = 1;
        }

        xStep = ((double) (upX - downX)) / swipeSteps;
        yStep = ((double) (upY - downY)) / swipeSteps;

        // first touch starts exactly at the point requested
        touchDown(downX, downY, button);
        if (fingerSelection) {
            SystemClock.sleep(LONG_PRESS_EVENT_INJECTION_DELAY_MILIS);
        }
        for (int i = 1; i < swipeSteps; i++) {
            touchMove(downX + (int) (xStep * i), downY + (int) (yStep * i), button);
            // set some known constant delay between steps as without it this
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.documentsui;

import android.graphics.Point;
import android.graphics.Rect;

import androidx.test.filters.LargeTest;

import com.android.documentsui.files.FilesActivity;

@LargeTest
public class FingerSelectionUiTest extends ActivityTest<FilesActivity> {

    public FingerSelectionUiTest() {
        super(FilesActivity.class);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        initTestFiles();
        bots.roots.closeDrawer();
    }

    public void testFingerSelection_outOfRange() throws Exception {
        bots.main.switchToGridMode();
        Rect dirListBounds = bots.directory.findDocumentsList().getBounds();
        Rect firstDoc = bots.directory.findDocument(fileName1).getBounds();
        // Start from list right bottom.
        Point start = new Point(firstDoc.centerX(), firstDoc.centerY());
        // End is center of file1
        Point end = new Point(dirListBounds.right, dirListBounds.bottom);
        bots.gesture.fingerSelection(start, end);

        bots.directory.assertSelection(3);
    }
}