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

Commit 8443c5e8 authored by Austin Kolander's avatar Austin Kolander
Browse files

Added support for custom text selection.

Created a class to handle selection of all text in a textview
or select part of the textview.

Bug: 64082214
Test: InspectorTextSelectorTest
Change-Id: Id19333de77781711756343fa27a4f51b6d65f254
parent 7e4b4c5f
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.inspector;

import static com.android.internal.util.Preconditions.checkArgument;

import android.text.Spannable;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

/**
 * Selects all or part of a textview.
 */
 public final class HeaderTextSelector implements ActionMode.Callback {

    private final TextView mText;
    private final Selector mSelector;

    public HeaderTextSelector(TextView text, Selector selector) {
        checkArgument(text != null);
        checkArgument(selector != null);
        mText = text;
        mSelector = selector;
    }

    // An action mode is created when the user selects text. This method is called where
    // we force it to select only the filename in the header. Meaning the name of the file would
    // be selected but the extension would not.
    @Override
    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
        CharSequence value = mText.getText();
        if (value instanceof Spannable) {
            mSelector.select((Spannable) value, 0, getLengthOfFilename(value));
        }
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
        return true;
    }

    @Override
    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
        return false;
    }

    @Override
    public void onDestroyActionMode(ActionMode actionMode) {}

    /**
     * Gets the length of the inspector header for selection.
     *
     * Example:
     * filename.txt returns the end index needed to select "filename".
     *
     * @return the index of the last character in the filename
     */
    private static int getLengthOfFilename(CharSequence text) {
        String title = text.toString();
        if (title != null) {
            int index = title.indexOf('.');
            if (index > 0) {
                return index;
            }
        }

        return text.length();
    }

    public interface Selector {
        void select(Spannable text, int start, int stop);
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -77,6 +79,12 @@ public final class HeaderView extends RelativeLayout implements HeaderDisplay {
    public void accept(DocumentInfo info, String displayName) {
        loadHeaderImage(info);
        mTitle.setText(displayName);
        mTitle.setCustomSelectionActionModeCallback(
                new HeaderTextSelector(mTitle, this::selectText));
    }

    private void selectText(Spannable text, int start, int stop) {
        Selection.setSelection(text, start, stop);
    }

    private void loadHeaderImage(DocumentInfo doc) {
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.inspector;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import android.test.suitebuilder.annotation.SmallTest;
import android.text.Spannable;
import android.text.SpannableString;
import android.widget.TextView;
import com.android.documentsui.inspector.HeaderTextSelector.Selector;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class HeaderTextSelectorTest {

    private Context mContext;
    private TestTextView mTestTextView;
    private TestSelector mTestSelector;
    private HeaderTextSelector mSelector;

    @Before
    public void setUp() throws Exception {
        mContext = InstrumentationRegistry.getTargetContext();
        mTestTextView = new TestTextView(mContext);
        mTestSelector = new TestSelector();
        mSelector = new HeaderTextSelector(mTestTextView, mTestSelector);
    }

    @Test
    public void testSimpleFileName() throws Exception {
        CharSequence fileName = "filename";
        String extension = ".txt";
        String testSequence = fileName + extension;

        mTestTextView.setText(testSequence);
        mSelector.onCreateActionMode(null, null);
        mTestSelector.assertCalled();

        CharSequence selectedSequence =
                testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
        assertEquals(selectedSequence, fileName);
    }


    @Test
    public void testLotsOfPeriodsInFileName() throws Exception {
        CharSequence fileName = "filename";
        String extension = ".jpg.zip.pdf.txt";
        String testSequence = fileName + extension;

        mTestTextView.setText(testSequence);
        mSelector.onCreateActionMode(null, null);
        mTestSelector.assertCalled();

        CharSequence selectedSequence =
            testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
        assertEquals(selectedSequence, fileName);
    }

    @Test
    public void testNoPeriodsInFileName() throws Exception {
        String testSequence = "filename";

        mTestTextView.setText(testSequence);
        mSelector.onCreateActionMode(null, null);
        mTestSelector.assertCalled();

        CharSequence selectedSequence =
            testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
        assertEquals(selectedSequence, testSequence);
    }

    private static class TestTextView extends TextView {

        public TestTextView(Context context) {
            super(context);
        }

        private String textViewString;

        public void setText(String text) {
            textViewString = text;
        }

        @Override
        public CharSequence getText() {
            return new SpannableString(textViewString);
        }
    }

    private static class TestSelector implements Selector {

        private boolean mCalled;
        private int mStart;
        private int mStop;

        public TestSelector() {
            mCalled = false;
            mStart = -1;
            mStop = -1;
        }

        @Override
        public void select(Spannable text, int start, int stop) {
            mCalled = true;
            mStart = start;
            mStop = stop;
        }

        public void assertCalled() {
            assertTrue(mCalled);
        }
    }
}
 No newline at end of file