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

Commit fe026bdd authored by Leon Scroggins's avatar Leon Scroggins
Browse files

Move Find on page and Select ActionModes to framework.

Bug: 2938052

Requires a change to packages/apps/Browser

Change-Id: I1bb1a47610b06c4bb02ef08647c02cc1dcaddb15
parent e1ab2228
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -15782,6 +15782,23 @@
>
</field>
</class>
<class name="R.menu"
 extends="java.lang.Object"
 abstract="false"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="R.menu"
 type="android.R.menu"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</constructor>
</class>
<class name="R.plurals"
 extends="java.lang.Object"
 abstract="false"
@@ -215998,6 +216015,19 @@
<parameter name="client" type="android.webkit.WebViewClient">
</parameter>
</method>
<method name="showFindDialog"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="text" type="java.lang.String">
</parameter>
</method>
<method name="stopLoading"
 return="void"
 abstract="false"
+4 −1
Original line number Diff line number Diff line
@@ -209,7 +209,10 @@ public class Browser {
        send.putExtra(Intent.EXTRA_TEXT, stringToSend);

        try {
            c.startActivity(Intent.createChooser(send, chooserDialogTitle));
            Intent i = Intent.createChooser(send, chooserDialogTitle);
            // In case this is called from outside an Activity
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            c.startActivity(i);
        } catch(android.content.ActivityNotFoundException ex) {
            // if no app handles it, do nothing
        }
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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 android.webkit;

import android.content.Context;
import android.content.res.Resources;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.TextView;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
        View.OnLongClickListener {
    private View mCustomView;
    private EditText mEditText;
    private TextView mMatches;
    private WebView mWebView;
    private InputMethodManager mInput;
    private Resources mResources;
    private boolean mMatchesFound;
    private int mNumberOfMatches;
    private View mTitleBar;

    FindActionModeCallback(Context context) {
        mCustomView = LayoutInflater.from(context).inflate(
                com.android.internal.R.layout.webview_find, null);
        mEditText = (EditText) mCustomView.findViewById(
                com.android.internal.R.id.edit);
        // Override long click so that select ActionMode is not opened, which
        // would exit find ActionMode.
        mEditText.setOnLongClickListener(this);
        setText("");
        mMatches = (TextView) mCustomView.findViewById(
                com.android.internal.R.id.matches);
        mInput = (InputMethodManager)
                context.getSystemService(Context.INPUT_METHOD_SERVICE);
        mResources = context.getResources();
    }

    void setTitleBar(View v) { mTitleBar = v; }

    /*
     * Place text in the text field so it can be searched for.  Need to press
     * the find next or find previous button to find all of the matches.
     */
    void setText(String text) {
        mEditText.setText(text);
        Spannable span = (Spannable) mEditText.getText();
        int length = span.length();
        // Ideally, we would like to set the selection to the whole field,
        // but this brings up the Text selection CAB, which dismisses this
        // one.
        Selection.setSelection(span, length, length);
        // Necessary each time we set the text, so that this will watch
        // changes to it.
        span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
        mMatchesFound = false;
    }

    /*
     * Set the WebView to search.  Must be non null, and set before calling
     * startActionMode.
     */
    void setWebView(WebView webView) {
        if (null == webView) {
            throw new AssertionError("WebView supplied to "
                    + "FindActionModeCallback cannot be null");
        }
        mWebView = webView;
    }

    /*
     * Move the highlight to the next match.
     * @param next If true, find the next match further down in the document.
     *             If false, find the previous match, up in the document.
     */
    private void findNext(boolean next) {
        if (mWebView == null) {
            throw new AssertionError(
                    "No WebView for FindActionModeCallback::findNext");
        }
        mWebView.findNext(next);
    }

    /*
     * Highlight all the instances of the string from mEditText in mWebView.
     */
    void findAll() {
        if (mWebView == null) {
            throw new AssertionError(
                    "No WebView for FindActionModeCallback::findAll");
        }
        CharSequence find = mEditText.getText();
        if (0 == find.length()) {
            mWebView.clearMatches();
            mMatches.setVisibility(View.GONE);
            mMatchesFound = false;
        } else {
            mMatchesFound = true;
            mMatches.setVisibility(View.VISIBLE);
            mNumberOfMatches = mWebView.findAll(find.toString());
            if (0 == mNumberOfMatches) {
                mMatches.setText(mResources.getString(
                        com.android.internal.R.string.no_matches));
            } else {
                updateMatchesString();
            }
        }
    }

    /*
     * Update the string which tells the user how many matches were found, and
     * which match is currently highlighted.
     */
    private void updateMatchesString() {
        String template = mResources.getQuantityString(
                com.android.internal.R.plurals.matches_found, mNumberOfMatches,
                mWebView.findIndex() + 1, mNumberOfMatches);

        mMatches.setText(template);
    }

    // OnLongClickListener implementation

    @Override
    public boolean onLongClick(View v) { return true; }

    // ActionMode.Callback implementation

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mode.setCustomView(mCustomView);
        mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find,
                menu);
        Editable edit = mEditText.getText();
        Selection.setSelection(edit, edit.length());
        mMatches.setVisibility(View.GONE);
        mMatchesFound = false;
        mMatches.setText("0");
        mEditText.requestFocus();
        mInput.showSoftInput(mEditText, 0);
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar);
        mWebView.notifyFindDialogDismissed();
        mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        if (!mMatchesFound) {
            findAll();
            return true;
        }
        switch(item.getItemId()) {
            case com.android.internal.R.id.find_prev:
                findNext(false);
                break;
            case com.android.internal.R.id.find_next:
                findNext(true);
                break;
            default:
                return false;
        }
        updateMatchesString();
        return true;
    }

    // TextWatcher implementation

    @Override
    public void beforeTextChanged(CharSequence s,
                                  int start,
                                  int count,
                                  int after) {
        // Does nothing.  Needed to implement TextWatcher.
    }

    @Override
    public void onTextChanged(CharSequence s,
                              int start,
                              int before,
                              int count) {
        findAll();
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Does nothing.  Needed to implement TextWatcher.
    }

}
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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 android.webkit;

import android.provider.Browser;
import android.webkit.WebView;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

class SelectActionModeCallback implements ActionMode.Callback {
    private WebView mWebView;
    private View mTitleBar;
    private ActionMode mActionMode;

    void setWebView(WebView webView) {
        mWebView = webView;
    }

    void setTitleBar(View v) { mTitleBar = v; }

    void finish() {
        mActionMode.finish();
    }

    // ActionMode.Callback implementation

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy,
                menu);
        mode.setTitle(com.android.internal.R.string.textSelectionCABTitle);
        mActionMode = mode;
        return true;
    }

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

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch(item.getItemId()) {
            case android.R.id.copy:
                mWebView.copySelection();
                mode.finish();
                break;

            case com.android.internal.R.id.share:
                String selection = mWebView.getSelection();
                Browser.sendString(mWebView.getContext(), selection);
                mode.finish();
                break;

            case com.android.internal.R.id.select_all:
                mWebView.selectAll();
                break;

            case com.android.internal.R.id.find:
                String sel= mWebView.getSelection();
                mode.finish();
                mWebView.showFindDialog(sel);
                break;

            default:
                return false;
        }
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar);
        mWebView.selectionDone();
    }
}
+0 −17
Original line number Diff line number Diff line
@@ -323,23 +323,6 @@ public class WebChromeClient {
        uploadFile.onReceiveValue(null);
    }

    /**
     * Tell the client that the selection has been initiated.
     * @hide
     */
    public void onSelectionStart(WebView view) {
        // By default we cancel the selection again, thus disabling
        // text selection unless the chrome client supports it.
        view.notifySelectDialogDismissed();
    }

    /**
     * Tell the client that the selection has been copied or canceled.
     * @hide
     */
    public void onSelectionDone(WebView view) {
    }

    /**
     * Tell the client that the page being viewed is web app capable,
     * i.e. has specified the fullscreen-web-app-capable meta tag.
Loading