• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
Shell(Context context, AttributeSet attrs)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      */
setContentViewRenderView(ContentViewRenderView contentViewRenderView)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      */
initialize(long nativeShell, WindowAndroid window, ContentViewClient client)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      */
close()104     public void close() {
105         if (mNativeShell == 0) return;
106         nativeCloseShell(mNativeShell);
107     }
108 
109     @CalledByNative
onNativeDestroyed()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      */
isDestroyed()120     public boolean isDestroyed() {
121         return mNativeShell == 0;
122     }
123 
124     /**
125      * @return Whether or not the Shell is loading content.
126      */
isLoading()127     public boolean isLoading() {
128         return mLoading;
129     }
130 
131     @Override
onFinishInflate()132     protected void onFinishInflate() {
133         super.onFinishInflate();
134 
135         mProgressDrawable = (ClipDrawable) findViewById(R.id.toolbar).getBackground();
136         initializeUrlField();
137         initializeNavigationButtons();
138     }
139 
initializeUrlField()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      */
loadUrl(String url)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      */
sanitizeUrl(String url)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 
initializeNavigationButtons()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
onUpdateUrl(String url)220     private void onUpdateUrl(String url) {
221         mUrlTextView.setText(url);
222     }
223 
224     @SuppressWarnings("unused")
225     @CalledByNative
onLoadProgressChanged(double progress)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
toggleFullscreenModeForTab(boolean enterFullscreen)233     private void toggleFullscreenModeForTab(boolean enterFullscreen) {
234     }
235 
236     @CalledByNative
isFullscreenForTabOrPending()237     private boolean isFullscreenForTabOrPending() {
238         return false;
239     }
240 
241     @SuppressWarnings("unused")
242     @CalledByNative
setIsLoading(boolean loading)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
initFromNativeTabContents(long nativeWebContents)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
enableUiControl(int controlId, boolean enabled)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      */
getContentView()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      */
getContentViewCore()292     public ContentViewCore getContentViewCore() {
293         return mContentViewCore;
294     }
295 
setKeyboardVisibilityForUrl(boolean visible)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 
nativeCloseShell(long shellPtr)306     private static native void nativeCloseShell(long shellPtr);
307 }
308