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.
5 package org.chromium.content_shell;
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;
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_public.browser.LoadUrlParams;
30 import org.chromium.content_public.browser.NavigationController;
31 import org.chromium.content_public.browser.WebContents;
32 import org.chromium.ui.base.WindowAndroid;
35 * Container for the various UI components that make up a shell window.
37 @JNINamespace("content")
38 public class Shell extends LinearLayout {
40 private static final long COMPLETED_PROGRESS_TIMEOUT_MS = 200;
42 private final Runnable mClearProgressRunnable = new Runnable() {
45 mProgressDrawable.setLevel(0);
49 private ContentViewCore mContentViewCore;
50 private WebContents mWebContents;
51 private NavigationController mNavigationController;
52 private ContentViewClient mContentViewClient;
53 private EditText mUrlTextView;
54 private ImageButton mPrevButton;
55 private ImageButton mNextButton;
56 private ImageButton mStopButton;
57 private ImageButton mReloadButton;
59 private ClipDrawable mProgressDrawable;
61 private long mNativeShell;
62 private ContentViewRenderView mContentViewRenderView;
63 private WindowAndroid mWindow;
65 private boolean mLoading = false;
66 private boolean mIsFullscreen = false;
69 * Constructor for inflating via XML.
71 public Shell(Context context, AttributeSet attrs) {
72 super(context, attrs);
76 * Set the SurfaceView being renderered to as soon as it is available.
78 public void setContentViewRenderView(ContentViewRenderView contentViewRenderView) {
79 FrameLayout contentViewHolder = (FrameLayout) findViewById(R.id.contentview_holder);
80 if (contentViewRenderView == null) {
81 if (mContentViewRenderView != null) {
82 contentViewHolder.removeView(mContentViewRenderView);
85 contentViewHolder.addView(contentViewRenderView,
86 new FrameLayout.LayoutParams(
87 FrameLayout.LayoutParams.MATCH_PARENT,
88 FrameLayout.LayoutParams.MATCH_PARENT));
90 mContentViewRenderView = contentViewRenderView;
94 * Initializes the Shell for use.
96 * @param nativeShell The pointer to the native Shell object.
97 * @param window The owning window for this shell.
98 * @param client The {@link ContentViewClient} to be bound to any current or new
99 * {@link ContentViewCore}s associated with this shell.
101 public void initialize(long nativeShell, WindowAndroid window, ContentViewClient client) {
102 mNativeShell = nativeShell;
104 mContentViewClient = client;
108 * Closes the shell and cleans up the native instance, which will handle destroying all
111 public void close() {
112 if (mNativeShell == 0) return;
113 nativeCloseShell(mNativeShell);
117 private void onNativeDestroyed() {
120 mContentViewCore.destroy();
124 * @return Whether the Shell has been destroyed.
125 * @see #onNativeDestroyed()
127 public boolean isDestroyed() {
128 return mNativeShell == 0;
132 * @return Whether or not the Shell is loading content.
134 public boolean isLoading() {
139 protected void onFinishInflate() {
140 super.onFinishInflate();
142 mProgressDrawable = (ClipDrawable) findViewById(R.id.toolbar).getBackground();
143 initializeUrlField();
144 initializeNavigationButtons();
147 private void initializeUrlField() {
148 mUrlTextView = (EditText) findViewById(R.id.url);
149 mUrlTextView.setOnEditorActionListener(new OnEditorActionListener() {
151 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
152 if ((actionId != EditorInfo.IME_ACTION_GO) && (event == null ||
153 event.getKeyCode() != KeyEvent.KEYCODE_ENTER ||
154 event.getAction() != KeyEvent.ACTION_DOWN)) {
157 loadUrl(mUrlTextView.getText().toString());
158 setKeyboardVisibilityForUrl(false);
159 mContentViewCore.getContainerView().requestFocus();
163 mUrlTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
165 public void onFocusChange(View v, boolean hasFocus) {
166 setKeyboardVisibilityForUrl(hasFocus);
167 mNextButton.setVisibility(hasFocus ? GONE : VISIBLE);
168 mPrevButton.setVisibility(hasFocus ? GONE : VISIBLE);
170 mUrlTextView.setText(mWebContents.getUrl());
174 mUrlTextView.setOnKeyListener(new OnKeyListener() {
176 public boolean onKey(View v, int keyCode, KeyEvent event) {
177 if (keyCode == KeyEvent.KEYCODE_BACK) {
178 mContentViewCore.getContainerView().requestFocus();
187 * Loads an URL. This will perform minimal amounts of sanitizing of the URL to attempt to
190 * @param url The URL to be loaded by the shell.
192 public void loadUrl(String url) {
193 if (url == null) return;
195 if (TextUtils.equals(url, mWebContents.getUrl())) {
196 mNavigationController.reload(true);
198 mNavigationController.loadUrl(new LoadUrlParams(sanitizeUrl(url)));
200 mUrlTextView.clearFocus();
201 // TODO(aurimas): Remove this when crbug.com/174541 is fixed.
202 mContentViewCore.getContainerView().clearFocus();
203 mContentViewCore.getContainerView().requestFocus();
207 * Given an URL, this performs minimal sanitizing to ensure it will be valid.
208 * @param url The url to be sanitized.
209 * @return The sanitized URL.
211 public static String sanitizeUrl(String url) {
212 if (url == null) return null;
213 if (url.startsWith("www.") || url.indexOf(":") == -1) url = "http://" + url;
217 private void initializeNavigationButtons() {
218 mPrevButton = (ImageButton) findViewById(R.id.prev);
219 mPrevButton.setOnClickListener(new OnClickListener() {
221 public void onClick(View v) {
222 if (mNavigationController.canGoBack()) mNavigationController.goBack();
226 mNextButton = (ImageButton) findViewById(R.id.next);
227 mNextButton.setOnClickListener(new OnClickListener() {
229 public void onClick(View v) {
230 if (mNavigationController.canGoForward()) mNavigationController.goForward();
233 mStopButton = (ImageButton) findViewById(R.id.stop);
234 mStopButton.setOnClickListener(new OnClickListener() {
236 public void onClick(View v) {
237 if (mLoading) mWebContents.stop();
240 mReloadButton = (ImageButton) findViewById(R.id.reload);
241 mReloadButton.setOnClickListener(new OnClickListener() {
243 public void onClick(View v) {
244 mNavigationController.reload(true);
249 @SuppressWarnings("unused")
251 private void onUpdateUrl(String url) {
252 mUrlTextView.setText(url);
255 @SuppressWarnings("unused")
257 private void onLoadProgressChanged(double progress) {
258 removeCallbacks(mClearProgressRunnable);
259 mProgressDrawable.setLevel((int) (10000.0 * progress));
260 if (progress == 1.0) postDelayed(mClearProgressRunnable, COMPLETED_PROGRESS_TIMEOUT_MS);
264 private void toggleFullscreenModeForTab(boolean enterFullscreen) {
265 mIsFullscreen = enterFullscreen;
266 LinearLayout toolBar = (LinearLayout) findViewById(R.id.toolbar);
267 toolBar.setVisibility(enterFullscreen ? GONE : VISIBLE);
271 private boolean isFullscreenForTabOrPending() {
272 return mIsFullscreen;
275 @SuppressWarnings("unused")
277 private void setIsLoading(boolean loading) {
282 * Initializes the ContentView based on the native tab contents pointer passed in.
283 * @param nativeWebContents The pointer to the native tab contents object.
285 @SuppressWarnings("unused")
287 private void initFromNativeTabContents(long nativeWebContents) {
288 Context context = getContext();
289 mContentViewCore = new ContentViewCore(context);
290 ContentView cv = ContentView.newInstance(context, mContentViewCore);
291 mContentViewCore.initialize(cv, cv, nativeWebContents, mWindow);
292 mContentViewCore.setContentViewClient(mContentViewClient);
293 mWebContents = mContentViewCore.getWebContents();
294 mNavigationController = mWebContents.getNavigationController();
295 if (getParent() != null) mContentViewCore.onShow();
296 if (mWebContents.getUrl() != null) {
297 mUrlTextView.setText(mWebContents.getUrl());
299 ((FrameLayout) findViewById(R.id.contentview_holder)).addView(cv,
300 new FrameLayout.LayoutParams(
301 FrameLayout.LayoutParams.MATCH_PARENT,
302 FrameLayout.LayoutParams.MATCH_PARENT));
304 mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
308 * Enable/Disable navigation(Prev/Next) button if navigation is allowed/disallowed
309 * in respective direction.
310 * @param controlId Id of button to update
311 * @param enabled enable/disable value
314 private void enableUiControl(int controlId, boolean enabled) {
315 if (controlId == 0) mPrevButton.setEnabled(enabled);
316 else if (controlId == 1) mNextButton.setEnabled(enabled);
317 else if (controlId == 2) {
318 mStopButton.setVisibility(enabled ? VISIBLE : GONE);
319 mReloadButton.setVisibility(enabled ? GONE : VISIBLE);
324 * @return The {@link ViewGroup} currently shown by this Shell.
326 public ViewGroup getContentView() {
327 return mContentViewCore.getContainerView();
331 * @return The {@link ContentViewCore} currently managing the view shown by this Shell.
333 public ContentViewCore getContentViewCore() {
334 return mContentViewCore;
338 * @return The {@link WebContents} currently managing the content shown by this Shell.
340 public WebContents getWebContents() {
344 private void setKeyboardVisibilityForUrl(boolean visible) {
345 InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
346 Context.INPUT_METHOD_SERVICE);
348 imm.showSoftInput(mUrlTextView, InputMethodManager.SHOW_IMPLICIT);
350 imm.hideSoftInputFromWindow(mUrlTextView.getWindowToken(), 0);
354 private static native void nativeCloseShell(long shellPtr);