1 | // Copyright (c) 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.inputmethod.EditorInfo; |
14 | import android.view.inputmethod.InputMethodManager; |
15 | import android.widget.EditText; |
16 | import android.widget.FrameLayout; |
17 | import android.widget.ImageButton; |
18 | import android.widget.LinearLayout; |
19 | import android.widget.TextView; |
20 | import android.widget.TextView.OnEditorActionListener; |
21 | |
22 | import org.chromium.base.CalledByNative; |
23 | import org.chromium.base.JNINamespace; |
24 | import org.chromium.content.browser.ContentView; |
25 | import org.chromium.content.browser.ContentViewRenderView; |
26 | import org.chromium.content.browser.LoadUrlParams; |
27 | import org.chromium.ui.WindowAndroid; |
28 | |
29 | /** |
30 | * Container for the various UI components that make up a shell window. |
31 | */ |
32 | @JNINamespace("content") |
33 | public class Shell extends LinearLayout { |
34 | |
35 | private static final long COMPLETED_PROGRESS_TIMEOUT_MS = 200; |
36 | |
37 | private Runnable mClearProgressRunnable = new Runnable() { |
38 | @Override |
39 | public void run() { |
40 | mProgressDrawable.setLevel(0); |
41 | } |
42 | }; |
43 | |
44 | // TODO(jrg): a mContentView.destroy() call is needed, both upstream and downstream. |
45 | private ContentView mContentView; |
46 | private EditText mUrlTextView; |
47 | private ImageButton mPrevButton; |
48 | private ImageButton mNextButton; |
49 | |
50 | private ClipDrawable mProgressDrawable; |
51 | |
52 | private ContentViewRenderView mContentViewRenderView; |
53 | private WindowAndroid mWindow; |
54 | |
55 | private boolean mLoading = false; |
56 | |
57 | /** |
58 | * Constructor for inflating via XML. |
59 | */ |
60 | public Shell(Context context, AttributeSet attrs) { |
61 | super(context, attrs); |
62 | } |
63 | |
64 | /** |
65 | * Set the SurfaceView being renderered to as soon as it is available. |
66 | */ |
67 | public void setContentViewRenderView(ContentViewRenderView contentViewRenderView) { |
68 | FrameLayout contentViewHolder = (FrameLayout) findViewById(R.id.contentview_holder); |
69 | if (contentViewRenderView == null) { |
70 | if (mContentViewRenderView != null) { |
71 | contentViewHolder.removeView(mContentViewRenderView); |
72 | } |
73 | } else { |
74 | contentViewHolder.addView(contentViewRenderView, |
75 | new FrameLayout.LayoutParams( |
76 | FrameLayout.LayoutParams.MATCH_PARENT, |
77 | FrameLayout.LayoutParams.MATCH_PARENT)); |
78 | } |
79 | mContentViewRenderView = contentViewRenderView; |
80 | } |
81 | |
82 | /** |
83 | * @param window The owning window for this shell. |
84 | */ |
85 | public void setWindow(WindowAndroid window) { |
86 | mWindow = window; |
87 | } |
88 | |
89 | /** |
90 | * @return Whether or not the Shell is loading content. |
91 | */ |
92 | public boolean isLoading() { |
93 | return mLoading; |
94 | } |
95 | |
96 | @Override |
97 | protected void onFinishInflate() { |
98 | super.onFinishInflate(); |
99 | |
100 | mProgressDrawable = (ClipDrawable) findViewById(R.id.toolbar).getBackground(); |
101 | initializeUrlField(); |
102 | initializeNavigationButtons(); |
103 | } |
104 | |
105 | private void initializeUrlField() { |
106 | mUrlTextView = (EditText) findViewById(R.id.url); |
107 | mUrlTextView.setOnEditorActionListener(new OnEditorActionListener() { |
108 | @Override |
109 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { |
110 | if ((actionId != EditorInfo.IME_ACTION_GO) && (event == null || |
111 | event.getKeyCode() != KeyEvent.KEYCODE_ENTER || |
112 | event.getAction() != KeyEvent.ACTION_DOWN)) { |
113 | return false; |
114 | } |
115 | loadUrl(mUrlTextView.getText().toString()); |
116 | setKeyboardVisibilityForUrl(false); |
117 | mContentView.requestFocus(); |
118 | return true; |
119 | } |
120 | }); |
121 | mUrlTextView.setOnFocusChangeListener(new OnFocusChangeListener() { |
122 | @Override |
123 | public void onFocusChange(View v, boolean hasFocus) { |
124 | setKeyboardVisibilityForUrl(hasFocus); |
125 | mNextButton.setVisibility(hasFocus ? GONE : VISIBLE); |
126 | mPrevButton.setVisibility(hasFocus ? GONE : VISIBLE); |
127 | if (!hasFocus) { |
128 | mUrlTextView.setText(mContentView.getUrl()); |
129 | } |
130 | } |
131 | }); |
132 | } |
133 | |
134 | /** |
135 | * Loads an URL. This will perform minimal amounts of sanitizing of the URL to attempt to |
136 | * make it valid. |
137 | * |
138 | * @param url The URL to be loaded by the shell. |
139 | */ |
140 | public void loadUrl(String url) { |
141 | if (url == null) return; |
142 | |
143 | if (TextUtils.equals(url, mContentView.getUrl())) { |
144 | mContentView.reload(); |
145 | } else { |
146 | mContentView.loadUrl(new LoadUrlParams(sanitizeUrl(url))); |
147 | } |
148 | mUrlTextView.clearFocus(); |
149 | // TODO(aurimas): Remove this when crbug.com/174541 is fixed. |
150 | mContentView.clearFocus(); |
151 | mContentView.requestFocus(); |
152 | } |
153 | |
154 | /** |
155 | * Given an URL, this performs minimal sanitizing to ensure it will be valid. |
156 | * @param url The url to be sanitized. |
157 | * @return The sanitized URL. |
158 | */ |
159 | public static String sanitizeUrl(String url) { |
160 | if (url == null) return url; |
161 | if (url.startsWith("www.") || url.indexOf(":") == -1) url = "http://" + url; |
162 | return url; |
163 | } |
164 | |
165 | private void initializeNavigationButtons() { |
166 | mPrevButton = (ImageButton) findViewById(R.id.prev); |
167 | mPrevButton.setOnClickListener(new OnClickListener() { |
168 | @Override |
169 | public void onClick(View v) { |
170 | if (mContentView.canGoBack()) mContentView.goBack(); |
171 | } |
172 | }); |
173 | |
174 | mNextButton = (ImageButton) findViewById(R.id.next); |
175 | mNextButton.setOnClickListener(new OnClickListener() { |
176 | @Override |
177 | public void onClick(View v) { |
178 | if (mContentView.canGoForward()) mContentView.goForward(); |
179 | } |
180 | }); |
181 | } |
182 | |
183 | @SuppressWarnings("unused") |
184 | @CalledByNative |
185 | private void onUpdateUrl(String url) { |
186 | mUrlTextView.setText(url); |
187 | } |
188 | |
189 | @SuppressWarnings("unused") |
190 | @CalledByNative |
191 | private void onLoadProgressChanged(double progress) { |
192 | removeCallbacks(mClearProgressRunnable); |
193 | mProgressDrawable.setLevel((int) (10000.0 * progress)); |
194 | if (progress == 1.0) postDelayed(mClearProgressRunnable, COMPLETED_PROGRESS_TIMEOUT_MS); |
195 | } |
196 | |
197 | @CalledByNative |
198 | private void toggleFullscreenModeForTab(boolean enterFullscreen) { |
199 | } |
200 | |
201 | @CalledByNative |
202 | private boolean isFullscreenForTabOrPending() { |
203 | return false; |
204 | } |
205 | |
206 | @SuppressWarnings("unused") |
207 | @CalledByNative |
208 | private void setIsLoading(boolean loading) { |
209 | mLoading = loading; |
210 | } |
211 | |
212 | /** |
213 | * Initializes the ContentView based on the native tab contents pointer passed in. |
214 | * @param nativeTabContents The pointer to the native tab contents object. |
215 | */ |
216 | @SuppressWarnings("unused") |
217 | @CalledByNative |
218 | private void initFromNativeTabContents(int nativeTabContents) { |
219 | mContentView = ContentView.newInstance(getContext(), nativeTabContents, mWindow); |
220 | if (mContentView.getUrl() != null) mUrlTextView.setText(mContentView.getUrl()); |
221 | ((FrameLayout) findViewById(R.id.contentview_holder)).addView(mContentView, |
222 | new FrameLayout.LayoutParams( |
223 | FrameLayout.LayoutParams.MATCH_PARENT, |
224 | FrameLayout.LayoutParams.MATCH_PARENT)); |
225 | mContentView.requestFocus(); |
226 | mContentViewRenderView.setCurrentContentView(mContentView); |
227 | } |
228 | |
229 | /** |
230 | * @return The {@link ContentView} currently shown by this Shell. |
231 | */ |
232 | public ContentView getContentView() { |
233 | return mContentView; |
234 | } |
235 | |
236 | private void setKeyboardVisibilityForUrl(boolean visible) { |
237 | InputMethodManager imm = (InputMethodManager) getContext().getSystemService( |
238 | Context.INPUT_METHOD_SERVICE); |
239 | if (visible) { |
240 | imm.showSoftInput(mUrlTextView, InputMethodManager.SHOW_IMPLICIT); |
241 | } else { |
242 | imm.hideSoftInputFromWindow(mUrlTextView.getWindowToken(), 0); |
243 | } |
244 | } |
245 | } |