Home | History | Annotate | Download | only in content_shell
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.content_shell;
      6 
      7 import android.content.Context;
      8 import android.graphics.drawable.ClipDrawable;
      9 import android.text.TextUtils;
     10 import android.util.AttributeSet;
     11 import android.view.KeyEvent;
     12 import android.view.View;
     13 import android.view.ViewGroup;
     14 import android.view.inputmethod.EditorInfo;
     15 import android.view.inputmethod.InputMethodManager;
     16 import android.widget.EditText;
     17 import android.widget.FrameLayout;
     18 import android.widget.ImageButton;
     19 import android.widget.LinearLayout;
     20 import android.widget.TextView;
     21 import android.widget.TextView.OnEditorActionListener;
     22 
     23 import org.chromium.base.CalledByNative;
     24 import org.chromium.base.JNINamespace;
     25 import org.chromium.content.browser.ContentView;
     26 import org.chromium.content.browser.ContentViewClient;
     27 import org.chromium.content.browser.ContentViewCore;
     28 import org.chromium.content.browser.ContentViewRenderView;
     29 import org.chromium.content.browser.LoadUrlParams;
     30 import org.chromium.ui.base.WindowAndroid;
     31 
     32 /**
     33  * Container for the various UI components that make up a shell window.
     34  */
     35 @JNINamespace("content")
     36 public class Shell extends LinearLayout {
     37 
     38     private static final long COMPLETED_PROGRESS_TIMEOUT_MS = 200;
     39 
     40     private final Runnable mClearProgressRunnable = new Runnable() {
     41         @Override
     42         public void run() {
     43             mProgressDrawable.setLevel(0);
     44         }
     45     };
     46 
     47     private ContentViewCore mContentViewCore;
     48     private ContentViewClient mContentViewClient;
     49     private EditText mUrlTextView;
     50     private ImageButton mPrevButton;
     51     private ImageButton mNextButton;
     52 
     53     private ClipDrawable mProgressDrawable;
     54 
     55     private long mNativeShell;
     56     private ContentViewRenderView mContentViewRenderView;
     57     private WindowAndroid mWindow;
     58 
     59     private boolean mLoading = false;
     60 
     61     /**
     62      * Constructor for inflating via XML.
     63      */
     64     public Shell(Context context, AttributeSet attrs) {
     65         super(context, attrs);
     66     }
     67 
     68     /**
     69      * Set the SurfaceView being renderered to as soon as it is available.
     70      */
     71     public void setContentViewRenderView(ContentViewRenderView contentViewRenderView) {
     72         FrameLayout contentViewHolder = (FrameLayout) findViewById(R.id.contentview_holder);
     73         if (contentViewRenderView == null) {
     74             if (mContentViewRenderView != null) {
     75                 contentViewHolder.removeView(mContentViewRenderView);
     76             }
     77         } else {
     78             contentViewHolder.addView(contentViewRenderView,
     79                     new FrameLayout.LayoutParams(
     80                             FrameLayout.LayoutParams.MATCH_PARENT,
     81                             FrameLayout.LayoutParams.MATCH_PARENT));
     82         }
     83         mContentViewRenderView = contentViewRenderView;
     84     }
     85 
     86     /**
     87      * Initializes the Shell for use.
     88      *
     89      * @param nativeShell The pointer to the native Shell object.
     90      * @param window The owning window for this shell.
     91      * @param client The {@link ContentViewClient} to be bound to any current or new
     92      *               {@link ContentViewCore}s associated with this shell.
     93      */
     94     public void initialize(long nativeShell, WindowAndroid window, ContentViewClient client) {
     95         mNativeShell = nativeShell;
     96         mWindow = window;
     97         mContentViewClient = client;
     98     }
     99 
    100     /**
    101      * Closes the shell and cleans up the native instance, which will handle destroying all
    102      * dependencies.
    103      */
    104     public void close() {
    105         if (mNativeShell == 0) return;
    106         nativeCloseShell(mNativeShell);
    107     }
    108 
    109     @CalledByNative
    110     private void onNativeDestroyed() {
    111         mWindow = null;
    112         mNativeShell = 0;
    113         mContentViewCore.destroy();
    114     }
    115 
    116     /**
    117      * @return Whether the Shell has been destroyed.
    118      * @see #onNativeDestroyed()
    119      */
    120     public boolean isDestroyed() {
    121         return mNativeShell == 0;
    122     }
    123 
    124     /**
    125      * @return Whether or not the Shell is loading content.
    126      */
    127     public boolean isLoading() {
    128         return mLoading;
    129     }
    130 
    131     @Override
    132     protected void onFinishInflate() {
    133         super.onFinishInflate();
    134 
    135         mProgressDrawable = (ClipDrawable) findViewById(R.id.toolbar).getBackground();
    136         initializeUrlField();
    137         initializeNavigationButtons();
    138     }
    139 
    140     private void initializeUrlField() {
    141         mUrlTextView = (EditText) findViewById(R.id.url);
    142         mUrlTextView.setOnEditorActionListener(new OnEditorActionListener() {
    143             @Override
    144             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    145                 if ((actionId != EditorInfo.IME_ACTION_GO) && (event == null ||
    146                         event.getKeyCode() != KeyEvent.KEYCODE_ENTER ||
    147                         event.getAction() != KeyEvent.ACTION_DOWN)) {
    148                     return false;
    149                 }
    150                 loadUrl(mUrlTextView.getText().toString());
    151                 setKeyboardVisibilityForUrl(false);
    152                 mContentViewCore.getContainerView().requestFocus();
    153                 return true;
    154             }
    155         });
    156         mUrlTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
    157             @Override
    158             public void onFocusChange(View v, boolean hasFocus) {
    159                 setKeyboardVisibilityForUrl(hasFocus);
    160                 mNextButton.setVisibility(hasFocus ? GONE : VISIBLE);
    161                 mPrevButton.setVisibility(hasFocus ? GONE : VISIBLE);
    162                 if (!hasFocus) {
    163                     mUrlTextView.setText(mContentViewCore.getUrl());
    164                 }
    165             }
    166         });
    167     }
    168 
    169     /**
    170      * Loads an URL.  This will perform minimal amounts of sanitizing of the URL to attempt to
    171      * make it valid.
    172      *
    173      * @param url The URL to be loaded by the shell.
    174      */
    175     public void loadUrl(String url) {
    176         if (url == null) return;
    177 
    178         if (TextUtils.equals(url, mContentViewCore.getUrl())) {
    179             mContentViewCore.reload(true);
    180         } else {
    181             mContentViewCore.loadUrl(new LoadUrlParams(sanitizeUrl(url)));
    182         }
    183         mUrlTextView.clearFocus();
    184         // TODO(aurimas): Remove this when crbug.com/174541 is fixed.
    185         mContentViewCore.getContainerView().clearFocus();
    186         mContentViewCore.getContainerView().requestFocus();
    187     }
    188 
    189     /**
    190      * Given an URL, this performs minimal sanitizing to ensure it will be valid.
    191      * @param url The url to be sanitized.
    192      * @return The sanitized URL.
    193      */
    194     public static String sanitizeUrl(String url) {
    195         if (url == null) return url;
    196         if (url.startsWith("www.") || url.indexOf(":") == -1) url = "http://" + url;
    197         return url;
    198     }
    199 
    200     private void initializeNavigationButtons() {
    201         mPrevButton = (ImageButton) findViewById(R.id.prev);
    202         mPrevButton.setOnClickListener(new OnClickListener() {
    203             @Override
    204             public void onClick(View v) {
    205                 if (mContentViewCore.canGoBack()) mContentViewCore.goBack();
    206             }
    207         });
    208 
    209         mNextButton = (ImageButton) findViewById(R.id.next);
    210         mNextButton.setOnClickListener(new OnClickListener() {
    211             @Override
    212             public void onClick(View v) {
    213                 if (mContentViewCore.canGoForward()) mContentViewCore.goForward();
    214             }
    215         });
    216     }
    217 
    218     @SuppressWarnings("unused")
    219     @CalledByNative
    220     private void onUpdateUrl(String url) {
    221         mUrlTextView.setText(url);
    222     }
    223 
    224     @SuppressWarnings("unused")
    225     @CalledByNative
    226     private void onLoadProgressChanged(double progress) {
    227         removeCallbacks(mClearProgressRunnable);
    228         mProgressDrawable.setLevel((int) (10000.0 * progress));
    229         if (progress == 1.0) postDelayed(mClearProgressRunnable, COMPLETED_PROGRESS_TIMEOUT_MS);
    230     }
    231 
    232     @CalledByNative
    233     private void toggleFullscreenModeForTab(boolean enterFullscreen) {
    234     }
    235 
    236     @CalledByNative
    237     private boolean isFullscreenForTabOrPending() {
    238         return false;
    239     }
    240 
    241     @SuppressWarnings("unused")
    242     @CalledByNative
    243     private void setIsLoading(boolean loading) {
    244         mLoading = loading;
    245     }
    246 
    247     /**
    248      * Initializes the ContentView based on the native tab contents pointer passed in.
    249      * @param nativeWebContents The pointer to the native tab contents object.
    250      */
    251     @SuppressWarnings("unused")
    252     @CalledByNative
    253     private void initFromNativeTabContents(long nativeWebContents) {
    254         Context context = getContext();
    255         mContentViewCore = new ContentViewCore(context);
    256         ContentView cv = ContentView.newInstance(context, mContentViewCore);
    257         mContentViewCore.initialize(cv, cv, nativeWebContents, mWindow);
    258         mContentViewCore.setContentViewClient(mContentViewClient);
    259 
    260         if (getParent() != null) mContentViewCore.onShow();
    261         if (mContentViewCore.getUrl() != null) mUrlTextView.setText(mContentViewCore.getUrl());
    262         ((FrameLayout) findViewById(R.id.contentview_holder)).addView(cv,
    263                 new FrameLayout.LayoutParams(
    264                         FrameLayout.LayoutParams.MATCH_PARENT,
    265                         FrameLayout.LayoutParams.MATCH_PARENT));
    266         cv.requestFocus();
    267         mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
    268     }
    269 
    270     /**
    271      * Enable/Disable navigation(Prev/Next) button if navigation is allowed/disallowed
    272      * in respective direction.
    273      * @param controlId Id of button to update
    274      * @param enabled enable/disable value
    275      */
    276     @CalledByNative
    277     private void enableUiControl(int controlId, boolean enabled) {
    278         if (controlId == 0) mPrevButton.setEnabled(enabled);
    279         else if (controlId == 1) mNextButton.setEnabled(enabled);
    280     }
    281 
    282     /**
    283      * @return The {@link ViewGroup} currently shown by this Shell.
    284      */
    285     public ViewGroup getContentView() {
    286         return mContentViewCore.getContainerView();
    287     }
    288 
    289     /**
    290      * @return The {@link ContentViewCore} currently managing the view shown by this Shell.
    291      */
    292     public ContentViewCore getContentViewCore() {
    293         return mContentViewCore;
    294     }
    295 
    296     private void setKeyboardVisibilityForUrl(boolean visible) {
    297         InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
    298                 Context.INPUT_METHOD_SERVICE);
    299         if (visible) {
    300             imm.showSoftInput(mUrlTextView, InputMethodManager.SHOW_IMPLICIT);
    301         } else {
    302             imm.hideSoftInputFromWindow(mUrlTextView.getWindowToken(), 0);
    303         }
    304     }
    305 
    306     private static native void nativeCloseShell(long shellPtr);
    307 }
    308