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

Commit f87c1fbb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added support for custom text selection."

parents 93d9f19e 8443c5e8
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