blob: d34d18d57489d61340fd992b3f7b2855235582d9 [file] [log] [blame]
Leon Scroggins571b3762010-05-26 10:25:01 -04001/*
2 * Copyright (C) 2010 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
17package com.android.browser;
18
Michael Kolb11d19782011-03-20 10:17:40 -070019import com.android.browser.UI.DropdownChangeListener;
John Reck92026732011-02-15 10:12:30 -080020import com.android.browser.UrlInputView.UrlInputListener;
Michael Kolb11d19782011-03-20 10:17:40 -070021import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
John Reck92026732011-02-15 10:12:30 -080022
23import android.app.SearchManager;
Leon Scroggins571b3762010-05-26 10:25:01 -040024import android.content.Context;
John Reck92026732011-02-15 10:12:30 -080025import android.content.Intent;
Leon Scroggins571b3762010-05-26 10:25:01 -040026import android.graphics.Bitmap;
27import android.graphics.Color;
28import android.graphics.drawable.BitmapDrawable;
29import android.graphics.drawable.Drawable;
30import android.graphics.drawable.LayerDrawable;
31import android.graphics.drawable.PaintDrawable;
John Reck92026732011-02-15 10:12:30 -080032import android.os.Bundle;
33import android.speech.RecognizerResultsIntent;
Michael Kolb11d19782011-03-20 10:17:40 -070034import android.text.TextUtils;
35import android.view.ContextThemeWrapper;
Michael Kolb7cdc4902011-02-03 17:54:40 -080036import android.view.Gravity;
Michael Kolb11d19782011-03-20 10:17:40 -070037import android.view.KeyEvent;
38import android.view.LayoutInflater;
Leon Scroggins571b3762010-05-26 10:25:01 -040039import android.view.View;
Michael Kolb11d19782011-03-20 10:17:40 -070040import android.view.View.OnClickListener;
41import android.view.View.OnFocusChangeListener;
42import android.view.animation.Animation;
43import android.view.animation.Animation.AnimationListener;
44import android.view.animation.AnimationUtils;
45import android.webkit.WebView;
Michael Kolb7cdc4902011-02-03 17:54:40 -080046import android.widget.AbsoluteLayout;
Michael Kolb11d19782011-03-20 10:17:40 -070047import android.widget.ArrayAdapter;
48import android.widget.Button;
49import android.widget.ImageButton;
Leon Scroggins571b3762010-05-26 10:25:01 -040050import android.widget.ImageView;
Michael Kolb11d19782011-03-20 10:17:40 -070051import android.widget.ProgressBar;
52import android.widget.RelativeLayout;
53import android.widget.Spinner;
54import android.widget.TextView;
55
56import java.util.List;
Leon Scroggins571b3762010-05-26 10:25:01 -040057
58/**
59 * Base class for a title bar used by the browser.
60 */
Michael Kolb11d19782011-03-20 10:17:40 -070061public class TitleBarBase extends RelativeLayout
62 implements OnClickListener, OnFocusChangeListener, UrlInputListener,
63 TextChangeWatcher, DeviceAccountLogin.AutoLoginCallback {
John Reck94b7e042011-02-15 15:02:33 -080064
65 protected static final int PROGRESS_MAX = 100;
66
Leon Scroggins571b3762010-05-26 10:25:01 -040067 // These need to be set by the subclass.
68 protected ImageView mFavicon;
69 protected ImageView mLockIcon;
70
Michael Kolbfe251992010-07-08 15:41:55 -070071 protected Drawable mGenericFavicon;
John Reck92026732011-02-15 10:12:30 -080072 protected UiController mUiController;
73 protected BaseUi mBaseUi;
Michael Kolb11d19782011-03-20 10:17:40 -070074
John Reck92026732011-02-15 10:12:30 -080075 protected UrlInputView mUrlInput;
76 protected boolean mInVoiceMode;
Leon Scroggins571b3762010-05-26 10:25:01 -040077
Michael Kolb11d19782011-03-20 10:17:40 -070078 // Auto-login UI
79 protected View mAutoLogin;
80 protected Spinner mAutoLoginAccount;
81 protected Button mAutoLoginLogin;
82 protected ProgressBar mAutoLoginProgress;
83 protected TextView mAutoLoginError;
84 protected ImageButton mAutoLoginCancel;
85 protected DeviceAccountLogin mAutoLoginHandler;
86 protected ArrayAdapter<String> mAccountsAdapter;
Michael Kolbfdb70242011-03-24 09:41:11 -070087 protected boolean mUseQuickControls;
Michael Kolb11d19782011-03-20 10:17:40 -070088
John Reck92026732011-02-15 10:12:30 -080089 public TitleBarBase(Context context, UiController controller, BaseUi ui) {
Leon Scroggins571b3762010-05-26 10:25:01 -040090 super(context, null);
John Reck92026732011-02-15 10:12:30 -080091 mUiController = controller;
92 mBaseUi = ui;
Leon Scroggins571b3762010-05-26 10:25:01 -040093 mGenericFavicon = context.getResources().getDrawable(
94 R.drawable.app_web_browser_sm);
95 }
96
Michael Kolb11d19782011-03-20 10:17:40 -070097 protected void initLayout(Context context, int layoutId) {
98 LayoutInflater factory = LayoutInflater.from(context);
99 factory.inflate(layoutId, this);
100
101 mUrlInput = (UrlInputView) findViewById(R.id.url);
102 mLockIcon = (ImageView) findViewById(R.id.lock);
103 mUrlInput.setUrlInputListener(this);
104 mUrlInput.setController(mUiController);
105 mUrlInput.setOnFocusChangeListener(this);
106 mUrlInput.setSelectAllOnFocus(true);
107 mUrlInput.addQueryTextWatcher(this);
108 mAutoLogin = findViewById(R.id.autologin);
109 mAutoLoginAccount = (Spinner) findViewById(R.id.autologin_account);
110 mAutoLoginLogin = (Button) findViewById(R.id.autologin_login);
111 mAutoLoginLogin.setOnClickListener(this);
112 mAutoLoginProgress = (ProgressBar) findViewById(R.id.autologin_progress);
113 mAutoLoginError = (TextView) findViewById(R.id.autologin_error);
114 mAutoLoginCancel = (ImageButton) mAutoLogin.findViewById(R.id.autologin_close);
115 mAutoLoginCancel.setOnClickListener(this);
116 }
117
118 protected void setupUrlInput() {
119 }
120
Michael Kolbfdb70242011-03-24 09:41:11 -0700121 protected void setUseQuickControls(boolean use) {
122 mUseQuickControls = use;
123 }
124
Leon Scroggins571b3762010-05-26 10:25:01 -0400125 /* package */ void setProgress(int newProgress) {}
Leon Scroggins571b3762010-05-26 10:25:01 -0400126
127 /* package */ void setLock(Drawable d) {
128 assert mLockIcon != null;
129 if (null == d) {
130 mLockIcon.setVisibility(View.GONE);
131 } else {
132 mLockIcon.setImageDrawable(d);
133 mLockIcon.setVisibility(View.VISIBLE);
134 }
135 }
136
137 /* package */ void setFavicon(Bitmap icon) {
138 assert mFavicon != null;
139 Drawable[] array = new Drawable[3];
140 array[0] = new PaintDrawable(Color.BLACK);
141 PaintDrawable p = new PaintDrawable(Color.WHITE);
142 array[1] = p;
143 if (icon == null) {
144 array[2] = mGenericFavicon;
145 } else {
146 array[2] = new BitmapDrawable(icon);
147 }
148 LayerDrawable d = new LayerDrawable(array);
149 d.setLayerInset(1, 1, 1, 1, 1);
150 d.setLayerInset(2, 2, 2, 2, 2);
151 mFavicon.setImageDrawable(d);
152 }
153
Michael Kolb7cdc4902011-02-03 17:54:40 -0800154 void setTitleGravity(int gravity) {
155 int newTop = 0;
156 if (gravity != Gravity.NO_GRAVITY) {
157 View parent = (View) getParent();
158 if (parent != null) {
159 if (gravity == Gravity.TOP) {
160 newTop = parent.getScrollY();
161 } else if (gravity == Gravity.BOTTOM) {
162 newTop = parent.getScrollY() + parent.getHeight() - getHeight();
163 }
164 }
165 }
166 AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) getLayoutParams();
167 if (lp != null) {
168 lp.y = newTop;
169 setLayoutParams(lp);
170 }
171 }
172
Michael Kolb29ccf8a2011-02-23 16:13:24 -0800173 public int getEmbeddedHeight() {
174 return getHeight();
175 }
176
Michael Kolb11d19782011-03-20 10:17:40 -0700177 protected void updateAutoLogin(Tab tab, boolean animate) {
178 DeviceAccountLogin login = tab.getDeviceAccountLogin();
179 if (login != null) {
180 mAutoLoginHandler = login;
181 ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext,
182 android.R.style.Theme_Holo_Light);
183 mAccountsAdapter = new ArrayAdapter<String>(wrapper,
184 android.R.layout.simple_spinner_item, login.getAccountNames());
185 mAccountsAdapter.setDropDownViewResource(
186 android.R.layout.simple_spinner_dropdown_item);
187 mAutoLoginAccount.setAdapter(mAccountsAdapter);
188 mAutoLoginAccount.setSelection(0);
189 mAutoLoginAccount.setEnabled(true);
190 mAutoLoginLogin.setEnabled(true);
191 mAutoLoginProgress.setVisibility(View.GONE);
192 mAutoLoginError.setVisibility(View.GONE);
193 switch (login.getState()) {
194 case DeviceAccountLogin.PROCESSING:
195 mAutoLoginAccount.setEnabled(false);
196 mAutoLoginLogin.setEnabled(false);
197 mAutoLoginProgress.setVisibility(View.VISIBLE);
198 break;
199 case DeviceAccountLogin.FAILED:
200 mAutoLoginProgress.setVisibility(View.GONE);
201 mAutoLoginError.setVisibility(View.VISIBLE);
202 break;
203 case DeviceAccountLogin.INITIAL:
204 break;
205 default:
206 throw new IllegalStateException();
207 }
208 showAutoLogin(animate);
Michael Kolb43909f22011-03-23 13:18:36 -0700209 } else {
210 hideAutoLogin(animate);
Michael Kolb11d19782011-03-20 10:17:40 -0700211 }
212 }
213
214 protected void showAutoLogin(boolean animate) {
215 mAutoLogin.setVisibility(View.VISIBLE);
216 if (animate) {
217 mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
218 getContext(), R.anim.autologin_enter));
219 }
220 }
221
222 protected void hideAutoLogin(boolean animate) {
223 mAutoLoginHandler = null;
224 if (animate) {
225 Animation anim = AnimationUtils.loadAnimation(
226 getContext(), R.anim.autologin_exit);
227 anim.setAnimationListener(new AnimationListener() {
228 @Override public void onAnimationEnd(Animation a) {
229 mAutoLogin.setVisibility(View.GONE);
230 mBaseUi.refreshWebView();
231 }
232 @Override public void onAnimationStart(Animation a) {}
233 @Override public void onAnimationRepeat(Animation a) {}
234 });
235 mAutoLogin.startAnimation(anim);
236 } else if (mAutoLogin.getAnimation() == null) {
237 mAutoLogin.setVisibility(View.GONE);
238 mBaseUi.refreshWebView();
239 }
240 }
241
242 @Override
243 public void loginFailed() {
244 mAutoLoginAccount.setEnabled(true);
245 mAutoLoginLogin.setEnabled(true);
246 mAutoLoginProgress.setVisibility(View.GONE);
247 mAutoLoginError.setVisibility(View.VISIBLE);
248 }
249
250
251 protected boolean inAutoLogin() {
252 return mAutoLoginHandler != null;
253 }
254
255 @Override
256 public void onClick(View v) {
257 if (mAutoLoginCancel == v) {
258 if (mAutoLoginHandler != null) {
259 mAutoLoginHandler.cancel();
260 mAutoLoginHandler = null;
261 }
262 hideAutoLogin(true);
263 } else if (mAutoLoginLogin == v) {
264 if (mAutoLoginHandler != null) {
265 mAutoLoginAccount.setEnabled(false);
266 mAutoLoginLogin.setEnabled(false);
267 mAutoLoginProgress.setVisibility(View.VISIBLE);
268 mAutoLoginError.setVisibility(View.GONE);
269 mAutoLoginHandler.login(
270 mAutoLoginAccount.getSelectedItemPosition(), this);
271 }
272 }
273 }
274
275 @Override
276 public void onFocusChange(View view, boolean hasFocus) {
277 // if losing focus and not in touch mode, leave as is
278 if (hasFocus || view.isInTouchMode() || mUrlInput.needsUpdate()) {
279 setFocusState(hasFocus);
280 }
281 if (hasFocus) {
282 mUrlInput.forceIme();
283 if (mInVoiceMode) {
284 mUrlInput.forceFilter();
285 }
286 } else if (!mUrlInput.needsUpdate()) {
287 mUrlInput.dismissDropDown();
288 mUrlInput.hideIME();
289 if (mUrlInput.getText().length() == 0) {
290 Tab currentTab = mUiController.getTabControl().getCurrentTab();
291 if (currentTab != null) {
292 mUrlInput.setText(currentTab.getUrl(), false);
293 }
294 }
295 }
296 mUrlInput.clearNeedsUpdate();
297 }
298
299 protected void setFocusState(boolean focus) {
300 if (focus) {
301 updateSearchMode(false);
302 }
303 }
304
305 protected void updateSearchMode(boolean userEdited) {
306 setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText()));
307 }
308
309 protected void setSearchMode(boolean voiceSearchEnabled) {}
310
311 boolean isEditingUrl() {
312 return mUrlInput.hasFocus();
313 }
314
315 void stopEditingUrl() {
316 mUrlInput.clearFocus();
317 }
318
319 void setDisplayTitle(String title) {
320 if (!isEditingUrl()) {
321 mUrlInput.setText(title, false);
322 }
323 }
324
325 // UrlInput text watcher
326
327 @Override
328 public void onTextChanged(String newText) {
329 if (mUrlInput.hasFocus()) {
330 // check if input field is empty and adjust voice search state
331 updateSearchMode(true);
332 // clear voice mode when user types
333 setInVoiceMode(false, null);
334 }
335 }
336
337 // voicesearch
338
339 public void setInVoiceMode(boolean voicemode, List<String> voiceResults) {
340 mInVoiceMode = voicemode;
341 mUrlInput.setVoiceResults(voiceResults);
342 }
343
344 void setIncognitoMode(boolean incognito) {
345 mUrlInput.setIncognitoMode(incognito);
346 }
347
348 void clearCompletions() {
349 mUrlInput.setSuggestedText(null);
350 }
351
John Reck92026732011-02-15 10:12:30 -0800352 // UrlInputListener implementation
353
354 /**
355 * callback from suggestion dropdown
356 * user selected a suggestion
357 */
358 @Override
359 public void onAction(String text, String extra, String source) {
360 mUiController.getCurrentTopWebView().requestFocus();
361 mBaseUi.hideTitleBar();
362 Intent i = new Intent();
363 String action = null;
364 if (UrlInputView.VOICE.equals(source)) {
365 action = RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS;
366 source = null;
367 } else {
368 action = Intent.ACTION_SEARCH;
369 }
370 i.setAction(action);
371 i.putExtra(SearchManager.QUERY, text);
372 if (extra != null) {
373 i.putExtra(SearchManager.EXTRA_DATA_KEY, extra);
374 }
375 if (source != null) {
376 Bundle appData = new Bundle();
377 appData.putString(com.android.common.Search.SOURCE, source);
378 i.putExtra(SearchManager.APP_DATA, appData);
379 }
380 mUiController.handleNewIntent(i);
381 setDisplayTitle(text);
382 }
383
384 @Override
385 public void onDismiss() {
386 final Tab currentTab = mBaseUi.getActiveTab();
387 mBaseUi.hideTitleBar();
388 post(new Runnable() {
389 public void run() {
390 clearFocus();
391 if ((currentTab != null) && !mInVoiceMode) {
392 setDisplayTitle(currentTab.getUrl());
393 }
394 }
395 });
396 }
397
398 /**
399 * callback from the suggestion dropdown
400 * copy text to input field and stay in edit mode
401 */
402 @Override
403 public void onCopySuggestion(String text) {
404 mUrlInput.setText(text, true);
405 if (text != null) {
406 mUrlInput.setSelection(text.length());
407 }
408 }
409
John Reck94b7e042011-02-15 15:02:33 -0800410 public void setCurrentUrlIsBookmark(boolean isBookmark) {
411 }
412
Michael Kolb11d19782011-03-20 10:17:40 -0700413 @Override
414 public boolean dispatchKeyEventPreIme(KeyEvent evt) {
415 if (evt.getKeyCode() == KeyEvent.KEYCODE_BACK) {
416 // catch back key in order to do slightly more cleanup than usual
417 mUrlInput.clearFocus();
418 return true;
419 }
420 return super.dispatchKeyEventPreIme(evt);
421 }
422
423 protected WebView getCurrentWebView() {
424 Tab t = mBaseUi.getActiveTab();
425 if (t != null) {
426 return t.getWebView();
427 } else {
428 return null;
429 }
430 }
431
432 void registerDropdownChangeListener(DropdownChangeListener d) {
433 mUrlInput.registerDropdownChangeListener(d);
434 }
435
Michael Kolbfdb70242011-03-24 09:41:11 -0700436 /**
437 * called from the Ui when the user wants to edit
438 * @param clearInput clear the input field
439 */
440 void startEditingUrl(boolean clearInput) {};
441
Leon Scroggins571b3762010-05-26 10:25:01 -0400442}