Home | History | Annotate | Download | only in browser
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.browser;
     18 
     19 import android.content.Context;
     20 import android.text.Editable;
     21 import android.text.Selection;
     22 import android.text.Spannable;
     23 import android.text.TextWatcher;
     24 import android.view.Gravity;
     25 import android.view.KeyEvent;
     26 import android.view.LayoutInflater;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import android.view.animation.AnimationUtils;
     30 import android.view.inputmethod.InputMethodManager;
     31 import android.webkit.WebView;
     32 import android.widget.EditText;
     33 import android.widget.LinearLayout;
     34 import android.widget.TextView;
     35 
     36 /* package */ class FindDialog extends WebDialog implements TextWatcher {
     37     private TextView        mMatches;
     38 
     39     // Views with which the user can interact.
     40     private EditText        mEditText;
     41     private View            mNextButton;
     42     private View            mPrevButton;
     43     private View            mMatchesView;
     44 
     45     // When the dialog is opened up with old text, enter needs to be pressed
     46     // (or the text needs to be changed) before WebView.findAll can be called.
     47     // Once it has been called, enter should move to the next match.
     48     private boolean         mMatchesFound;
     49     private int             mNumberOfMatches;
     50 
     51     private View.OnClickListener mFindListener = new View.OnClickListener() {
     52         public void onClick(View v) {
     53             findNext();
     54         }
     55     };
     56 
     57     private View.OnClickListener mFindPreviousListener  =
     58             new View.OnClickListener() {
     59         public void onClick(View v) {
     60             if (mWebView == null) {
     61                 throw new AssertionError("No WebView for FindDialog::onClick");
     62             }
     63             mWebView.findNext(false);
     64             updateMatchesString();
     65             hideSoftInput();
     66         }
     67     };
     68 
     69     private void disableButtons() {
     70         mPrevButton.setEnabled(false);
     71         mNextButton.setEnabled(false);
     72         mPrevButton.setFocusable(false);
     73         mNextButton.setFocusable(false);
     74     }
     75 
     76     /* package */ FindDialog(BrowserActivity context) {
     77         super(context);
     78 
     79         LayoutInflater factory = LayoutInflater.from(context);
     80         factory.inflate(R.layout.browser_find, this);
     81 
     82         addCancel();
     83         mEditText = (EditText) findViewById(R.id.edit);
     84 
     85         View button = findViewById(R.id.next);
     86         button.setOnClickListener(mFindListener);
     87         mNextButton = button;
     88 
     89         button = findViewById(R.id.previous);
     90         button.setOnClickListener(mFindPreviousListener);
     91         mPrevButton = button;
     92 
     93         mMatches = (TextView) findViewById(R.id.matches);
     94         mMatchesView = findViewById(R.id.matches_view);
     95         disableButtons();
     96 
     97     }
     98 
     99     /**
    100      * Called by BrowserActivity.closeDialog.  Start the animation to hide
    101      * the dialog, inform the WebView that the dialog is being dismissed,
    102      * and hide the soft keyboard.
    103      */
    104     public void dismiss() {
    105         super.dismiss();
    106         mWebView.notifyFindDialogDismissed();
    107         hideSoftInput();
    108     }
    109 
    110     @Override
    111     public boolean dispatchKeyEventPreIme(KeyEvent event) {
    112         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
    113             KeyEvent.DispatcherState state = getKeyDispatcherState();
    114             if (state != null) {
    115                 int action = event.getAction();
    116                 if (KeyEvent.ACTION_DOWN == action
    117                         && event.getRepeatCount() == 0) {
    118                     state.startTracking(event, this);
    119                     return true;
    120                 } else if (KeyEvent.ACTION_UP == action
    121                         && !event.isCanceled() && state.isTracking(event)) {
    122                     mBrowserActivity.closeDialogs();
    123                     return true;
    124                 }
    125             }
    126         }
    127         return super.dispatchKeyEventPreIme(event);
    128     }
    129 
    130     @Override
    131     public boolean dispatchKeyEvent(KeyEvent event) {
    132         int keyCode = event.getKeyCode();
    133         if (event.getAction() == KeyEvent.ACTION_UP) {
    134             if (keyCode == KeyEvent.KEYCODE_ENTER
    135                     && mEditText.hasFocus()) {
    136                 if (mMatchesFound) {
    137                     findNext();
    138                 } else {
    139                     findAll();
    140                     // Set the selection to the end.
    141                     Spannable span = (Spannable) mEditText.getText();
    142                     Selection.setSelection(span, span.length());
    143                 }
    144                 return true;
    145             }
    146         }
    147         return super.dispatchKeyEvent(event);
    148     }
    149 
    150     private void findNext() {
    151         if (mWebView == null) {
    152             throw new AssertionError("No WebView for FindDialog::findNext");
    153         }
    154         mWebView.findNext(true);
    155         updateMatchesString();
    156         hideSoftInput();
    157     }
    158 
    159     public void show() {
    160         super.show();
    161         // In case the matches view is showing from a previous search
    162         mMatchesView.setVisibility(View.INVISIBLE);
    163         mMatchesFound = false;
    164         // This text is only here to ensure that mMatches has a height.
    165         mMatches.setText("0");
    166         mEditText.requestFocus();
    167         Spannable span = (Spannable) mEditText.getText();
    168         int length = span.length();
    169         Selection.setSelection(span, 0, length);
    170         span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
    171         disableButtons();
    172         InputMethodManager imm = (InputMethodManager)
    173                 mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
    174         imm.showSoftInput(mEditText, 0);
    175     }
    176 
    177     // TextWatcher methods
    178     public void beforeTextChanged(CharSequence s,
    179                                   int start,
    180                                   int count,
    181                                   int after) {
    182     }
    183 
    184     public void onTextChanged(CharSequence s,
    185                               int start,
    186                               int before,
    187                               int count) {
    188         findAll();
    189     }
    190 
    191     private void findAll() {
    192         if (mWebView == null) {
    193             throw new AssertionError(
    194                     "No WebView for FindDialog::findAll");
    195         }
    196         CharSequence find = mEditText.getText();
    197         if (0 == find.length()) {
    198             disableButtons();
    199             mWebView.clearMatches();
    200             mMatchesView.setVisibility(View.INVISIBLE);
    201         } else {
    202             mMatchesView.setVisibility(View.VISIBLE);
    203             int found = mWebView.findAll(find.toString());
    204             mMatchesFound = true;
    205             setMatchesFound(found);
    206             if (found < 2) {
    207                 disableButtons();
    208                 if (found == 0) {
    209                     // Cannot use getQuantityString, which ignores the "zero"
    210                     // quantity.
    211                     // FIXME: is this fix is beyond the scope
    212                     // of adding touch selection to gingerbread?
    213                     // mMatches.setText(mBrowserActivity.getResources().getString(
    214                     //        R.string.no_matches));
    215                 }
    216             } else {
    217                 mPrevButton.setFocusable(true);
    218                 mNextButton.setFocusable(true);
    219                 mPrevButton.setEnabled(true);
    220                 mNextButton.setEnabled(true);
    221             }
    222         }
    223     }
    224 
    225     private void setMatchesFound(int found) {
    226         mNumberOfMatches = found;
    227         updateMatchesString();
    228     }
    229 
    230     public void setText(String text) {
    231         mEditText.setText(text);
    232         findAll();
    233     }
    234 
    235     private void updateMatchesString() {
    236         // Note: updateMatchesString is only called by methods that have already
    237         // checked mWebView for null.
    238         String template = mBrowserActivity.getResources().
    239                 getQuantityString(R.plurals.matches_found, mNumberOfMatches,
    240                 mWebView.findIndex() + 1, mNumberOfMatches);
    241 
    242         mMatches.setText(template);
    243     }
    244 
    245     public void afterTextChanged(Editable s) {
    246     }
    247 }
    248