blob: 98667c344042fc55683474cc3c9eddd7385747f1 [file] [log] [blame]
Leon Scroggins81db3662009-06-04 17:45:11 -04001/*
2 * Copyright (C) 2009 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
19import android.content.Context;
Leon Scroggins11e71b12010-01-25 10:40:38 -050020import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.content.pm.ResolveInfo;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040023import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.Color;
Leon Scroggins1f005d32009-08-10 17:36:42 -040026import android.graphics.Rect;
Leon Scroggins62e8f942009-09-03 15:08:54 -040027import android.graphics.drawable.Animatable;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040028import android.graphics.drawable.BitmapDrawable;
Leon Scroggins81db3662009-06-04 17:45:11 -040029import android.graphics.drawable.Drawable;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040030import android.graphics.drawable.LayerDrawable;
31import android.graphics.drawable.PaintDrawable;
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040032import android.os.Handler;
33import android.os.Message;
Leon Scroggins11e71b12010-01-25 10:40:38 -050034import android.speech.RecognizerIntent;
Leon Scrogginsf48d44e2010-02-05 16:41:49 -050035import android.text.SpannableString;
36import android.text.Spanned;
Leon Scroggins76e16862010-02-08 14:39:34 -050037import android.text.TextUtils;
Leon Scrogginsf48d44e2010-02-05 16:41:49 -050038import android.text.style.ImageSpan;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040039import android.util.TypedValue;
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040040import android.view.ContextMenu;
Leon Scrogginse4b3bda2009-06-09 15:46:41 -040041import android.view.LayoutInflater;
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040042import android.view.MenuInflater;
Leon Scroggins68579392009-09-15 15:31:54 -040043import android.view.MotionEvent;
Leon Scrogginse4b3bda2009-06-09 15:46:41 -040044import android.view.View;
Leon Scroggins68579392009-09-15 15:31:54 -040045import android.view.ViewConfiguration;
Leon Scroggins81db3662009-06-04 17:45:11 -040046import android.widget.ImageView;
47import android.widget.LinearLayout;
48import android.widget.ProgressBar;
49import android.widget.TextView;
Leon Scroggins81db3662009-06-04 17:45:11 -040050
Leon Scroggins1fe13a52010-02-09 15:31:26 -050051import com.android.common.speech.LoggingEvents;
52
Leon Scroggins1f005d32009-08-10 17:36:42 -040053/**
54 * This class represents a title bar for a particular "tab" or "window" in the
55 * browser.
56 */
Leon Scrogginse4b3bda2009-06-09 15:46:41 -040057public class TitleBar extends LinearLayout {
Leon Scroggins81db3662009-06-04 17:45:11 -040058 private TextView mTitle;
Leon Scroggins1f005d32009-08-10 17:36:42 -040059 private Drawable mCloseDrawable;
60 private ImageView mRtButton;
Leon Scroggins62e8f942009-09-03 15:08:54 -040061 private Drawable mCircularProgress;
Leon Scroggins81db3662009-06-04 17:45:11 -040062 private ProgressBar mHorizontalProgress;
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -040063 private ImageView mFavicon;
Leon Scroggins62e8f942009-09-03 15:08:54 -040064 private ImageView mLockIcon;
Leon Scrogginsa81a7642009-08-31 17:05:41 -040065 private Drawable mStopDrawable;
66 private Drawable mBookmarkDrawable;
Leon Scroggins11e71b12010-01-25 10:40:38 -050067 private Drawable mVoiceDrawable;
Leon Scroggins81db3662009-06-04 17:45:11 -040068 private boolean mInLoad;
Leon Scrogginsa81a7642009-08-31 17:05:41 -040069 private BrowserActivity mBrowserActivity;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040070 private Drawable mGenericFavicon;
71 private int mIconDimension;
Leon Scroggins68579392009-09-15 15:31:54 -040072 private View mTitleBg;
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040073 private MyHandler mHandler;
Leon Scroggins11e71b12010-01-25 10:40:38 -050074 private Intent mVoiceSearchIntent;
75 private boolean mInVoiceMode;
Leon Scroggins58d56c62010-01-28 15:12:40 -050076 private Drawable mVoiceModeBackground;
77 private Drawable mNormalBackground;
Leon Scrogginsf48d44e2010-02-05 16:41:49 -050078 private ImageSpan mArcsSpan;
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040079
80 private static int LONG_PRESS = 1;
Leon Scroggins81db3662009-06-04 17:45:11 -040081
Leon Scroggins68579392009-09-15 15:31:54 -040082 public TitleBar(BrowserActivity context) {
Leon Scroggins1f005d32009-08-10 17:36:42 -040083 super(context, null);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -040084 mHandler = new MyHandler();
Leon Scroggins81db3662009-06-04 17:45:11 -040085 LayoutInflater factory = LayoutInflater.from(context);
86 factory.inflate(R.layout.title_bar, this);
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040087 mBrowserActivity = context;
Leon Scroggins81db3662009-06-04 17:45:11 -040088
89 mTitle = (TextView) findViewById(R.id.title);
Leon Scrogginsa81a7642009-08-31 17:05:41 -040090 mTitle.setCompoundDrawablePadding(5);
Leon Scroggins81db3662009-06-04 17:45:11 -040091
Leon Scroggins68579392009-09-15 15:31:54 -040092 mTitleBg = findViewById(R.id.title_bg);
Leon Scroggins62e8f942009-09-03 15:08:54 -040093 mLockIcon = (ImageView) findViewById(R.id.lock);
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -040094 mFavicon = (ImageView) findViewById(R.id.favicon);
Leon Scroggins62e8f942009-09-03 15:08:54 -040095
Leon Scrogginsa81a7642009-08-31 17:05:41 -040096 mRtButton = (ImageView) findViewById(R.id.rt_btn);
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040097 Resources resources = context.getResources();
98 mCircularProgress = (Drawable) resources.getDrawable(
Leon Scroggins62e8f942009-09-03 15:08:54 -040099 com.android.internal.R.drawable.search_spinner);
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400100 mIconDimension = (int) TypedValue.applyDimension(
101 TypedValue.COMPLEX_UNIT_DIP, 20f,
102 resources.getDisplayMetrics());
103 mCircularProgress.setBounds(0, 0, mIconDimension, mIconDimension);
Leon Scroggins81db3662009-06-04 17:45:11 -0400104 mHorizontalProgress = (ProgressBar) findViewById(
105 R.id.progress_horizontal);
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400106 mGenericFavicon = context.getResources().getDrawable(
107 R.drawable.app_web_browser_sm);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500108 mVoiceSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
109 mVoiceSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
110 RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
111 PackageManager pm = context.getPackageManager();
112 ResolveInfo ri = pm.resolveActivity(mVoiceSearchIntent,
113 PackageManager.MATCH_DEFAULT_ONLY);
114 if (ri == null) {
115 mVoiceSearchIntent = null;
116 } else {
117 mVoiceDrawable = resources.getDrawable(
118 android.R.drawable.ic_btn_speak_now);
119 }
120 mStopDrawable = resources.getDrawable(R.drawable.ic_btn_stop_v2);
121 mBookmarkDrawable = mRtButton.getDrawable();
Leon Scroggins58d56c62010-01-28 15:12:40 -0500122 mVoiceModeBackground = resources.getDrawable(
Leon Scrogginsf48d44e2010-02-05 16:41:49 -0500123 R.drawable.title_voice);
Leon Scroggins58d56c62010-01-28 15:12:40 -0500124 mNormalBackground = mTitleBg.getBackground();
Leon Scrogginsf48d44e2010-02-05 16:41:49 -0500125 mArcsSpan = new ImageSpan(context, R.drawable.arcs,
126 ImageSpan.ALIGN_BASELINE);
Leon Scrogginse4b3bda2009-06-09 15:46:41 -0400127 }
128
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400129 private class MyHandler extends Handler {
130 public void handleMessage(Message msg) {
131 if (msg.what == LONG_PRESS) {
132 // Prevent the normal action from happening by setting the title
133 // bar's state to false.
134 mTitleBg.setPressed(false);
135 // Need to call a special method on BrowserActivity for when the
136 // fake title bar is up, because its ViewGroup does not show a
137 // context menu.
138 mBrowserActivity.showTitleBarContextMenu();
139 }
140 }
141 };
142
143 @Override
Leon Scroggins4e9f89b2010-02-22 16:54:14 -0500144 public void createContextMenu(ContextMenu menu) {
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400145 MenuInflater inflater = mBrowserActivity.getMenuInflater();
146 inflater.inflate(R.menu.title_context, menu);
Leon Scroggins4e9f89b2010-02-22 16:54:14 -0500147 mBrowserActivity.onCreateContextMenu(menu, this, null);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400148 }
149
Leon Scroggins68579392009-09-15 15:31:54 -0400150 @Override
151 public boolean onTouchEvent(MotionEvent event) {
152 switch (event.getAction()) {
153 case MotionEvent.ACTION_DOWN:
154 // Make all touches hit either the textfield or the button,
155 // depending on which side of the right edge of the textfield
156 // they hit.
157 if ((int) event.getX() > mTitleBg.getRight()) {
158 mRtButton.setPressed(true);
159 } else {
160 mTitleBg.setPressed(true);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400161 mHandler.sendMessageDelayed(mHandler.obtainMessage(
162 LONG_PRESS),
163 ViewConfiguration.getLongPressTimeout());
Leon Scroggins68579392009-09-15 15:31:54 -0400164 }
165 break;
166 case MotionEvent.ACTION_MOVE:
167 int slop = ViewConfiguration.get(mBrowserActivity)
168 .getScaledTouchSlop();
169 if ((int) event.getY() > getHeight() + slop) {
170 // We only trigger the actions in ACTION_UP if one or the
171 // other is pressed. Since the user moved off the title
172 // bar, mark both as not pressed.
173 mTitleBg.setPressed(false);
174 mRtButton.setPressed(false);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400175 mHandler.removeMessages(LONG_PRESS);
Leon Scroggins68579392009-09-15 15:31:54 -0400176 break;
177 }
178 int x = (int) event.getX();
179 int titleRight = mTitleBg.getRight();
180 if (mTitleBg.isPressed() && x > titleRight + slop) {
181 mTitleBg.setPressed(false);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400182 mHandler.removeMessages(LONG_PRESS);
Leon Scroggins68579392009-09-15 15:31:54 -0400183 } else if (mRtButton.isPressed() && x < titleRight - slop) {
184 mRtButton.setPressed(false);
185 }
186 break;
187 case MotionEvent.ACTION_CANCEL:
188 mRtButton.setPressed(false);
189 mTitleBg.setPressed(false);
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400190 mHandler.removeMessages(LONG_PRESS);
Leon Scroggins68579392009-09-15 15:31:54 -0400191 break;
192 case MotionEvent.ACTION_UP:
193 if (mRtButton.isPressed()) {
Leon Scroggins11e71b12010-01-25 10:40:38 -0500194 if (mInVoiceMode) {
Leon Scroggins1fe13a52010-02-09 15:31:26 -0500195 if (mBrowserActivity.getTabControl().getCurrentTab()
196 .voiceSearchSourceIsGoogle()) {
197 Intent i = new Intent(
198 LoggingEvents.ACTION_LOG_EVENT);
199 i.putExtra(LoggingEvents.EXTRA_EVENT,
200 LoggingEvents.VoiceSearch.RETRY);
201 mBrowserActivity.sendBroadcast(i);
202 }
Leon Scroggins11e71b12010-01-25 10:40:38 -0500203 mBrowserActivity.startActivity(mVoiceSearchIntent);
204 } else if (mInLoad) {
Leon Scroggins68579392009-09-15 15:31:54 -0400205 mBrowserActivity.stopLoading();
206 } else {
207 mBrowserActivity.bookmarksOrHistoryPicker(false);
208 }
209 mRtButton.setPressed(false);
210 } else if (mTitleBg.isPressed()) {
Leon Scrogginsc6fa1102009-09-21 10:40:01 -0400211 mHandler.removeMessages(LONG_PRESS);
Leon Scroggins58d56c62010-01-28 15:12:40 -0500212 if (mInVoiceMode) {
Leon Scroggins1fe13a52010-02-09 15:31:26 -0500213 if (mBrowserActivity.getTabControl().getCurrentTab()
214 .voiceSearchSourceIsGoogle()) {
215 Intent i = new Intent(
216 LoggingEvents.ACTION_LOG_EVENT);
217 i.putExtra(LoggingEvents.EXTRA_EVENT,
218 LoggingEvents.VoiceSearch.N_BEST_REVEAL);
219 mBrowserActivity.sendBroadcast(i);
220 }
Leon Scroggins58d56c62010-01-28 15:12:40 -0500221 mBrowserActivity.showVoiceSearchResults(
Leon Scrogginsea754072010-02-08 14:08:30 -0500222 mTitle.getText().toString().trim());
Leon Scroggins58d56c62010-01-28 15:12:40 -0500223 } else {
Leon Scroggins8ad29922010-02-16 12:33:55 -0500224 mBrowserActivity.editUrl();
Leon Scroggins58d56c62010-01-28 15:12:40 -0500225 }
Leon Scroggins68579392009-09-15 15:31:54 -0400226 mTitleBg.setPressed(false);
227 }
228 break;
229 default:
230 break;
231 }
232 return true;
Leon Scroggins81db3662009-06-04 17:45:11 -0400233 }
234
Leon Scroggins1f005d32009-08-10 17:36:42 -0400235 /**
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400236 * Set a new Bitmap for the Favicon.
Leon Scroggins1f005d32009-08-10 17:36:42 -0400237 */
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400238 /* package */ void setFavicon(Bitmap icon) {
239 Drawable[] array = new Drawable[3];
240 array[0] = new PaintDrawable(Color.BLACK);
241 PaintDrawable p = new PaintDrawable(Color.WHITE);
242 array[1] = p;
243 if (icon == null) {
244 array[2] = mGenericFavicon;
245 } else {
246 array[2] = new BitmapDrawable(icon);
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400247 }
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400248 LayerDrawable d = new LayerDrawable(array);
249 d.setLayerInset(1, 1, 1, 1, 1);
250 d.setLayerInset(2, 2, 2, 2, 2);
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -0400251 mFavicon.setImageDrawable(d);
Leon Scroggins81db3662009-06-04 17:45:11 -0400252 }
253
Leon Scroggins1f005d32009-08-10 17:36:42 -0400254 /**
Leon Scroggins11e71b12010-01-25 10:40:38 -0500255 * Change the TitleBar to or from voice mode. If there is no package to
256 * handle voice search, the TitleBar cannot be set to voice mode.
257 */
258 /* package */ void setInVoiceMode(boolean inVoiceMode) {
259 if (mInVoiceMode == inVoiceMode) return;
260 mInVoiceMode = inVoiceMode && mVoiceSearchIntent != null;
Leon Scroggins58d56c62010-01-28 15:12:40 -0500261 Drawable rightButtonDrawable, titleDrawable;
Leon Scroggins11e71b12010-01-25 10:40:38 -0500262 if (mInVoiceMode) {
Leon Scroggins58d56c62010-01-28 15:12:40 -0500263 rightButtonDrawable = mVoiceDrawable;
264 titleDrawable = mVoiceModeBackground;
Leon Scroggins76e16862010-02-08 14:39:34 -0500265 mTitle.setEllipsize(null);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500266 } else {
Leon Scroggins58d56c62010-01-28 15:12:40 -0500267 titleDrawable = mNormalBackground;
268 if (mInLoad) {
269 rightButtonDrawable = mStopDrawable;
270 } else {
271 rightButtonDrawable = mBookmarkDrawable;
272 }
Leon Scroggins76e16862010-02-08 14:39:34 -0500273 mTitle.setEllipsize(TextUtils.TruncateAt.END);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500274 }
Leon Scrogginsf48d44e2010-02-05 16:41:49 -0500275 mTitle.setSingleLine(!mInVoiceMode);
Leon Scroggins58d56c62010-01-28 15:12:40 -0500276 mTitleBg.setBackgroundDrawable(titleDrawable);
277 mRtButton.setImageDrawable(rightButtonDrawable);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500278 }
279
280 /**
Leon Scroggins1f005d32009-08-10 17:36:42 -0400281 * Set the Drawable for the lock icon, or null to hide it.
282 */
Leon Scroggins81db3662009-06-04 17:45:11 -0400283 /* package */ void setLock(Drawable d) {
Leon Scroggins62e8f942009-09-03 15:08:54 -0400284 if (null == d) {
285 mLockIcon.setVisibility(View.GONE);
286 } else {
287 mLockIcon.setImageDrawable(d);
288 mLockIcon.setVisibility(View.VISIBLE);
Leon Scroggins81db3662009-06-04 17:45:11 -0400289 }
290 }
291
Leon Scroggins1f005d32009-08-10 17:36:42 -0400292 /**
293 * Update the progress, from 0 to 100.
294 */
Leon Scroggins81db3662009-06-04 17:45:11 -0400295 /* package */ void setProgress(int newProgress) {
Nicolas Roard1382b492009-09-16 21:50:06 +0100296 if (newProgress >= mHorizontalProgress.getMax()) {
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -0400297 mTitle.setCompoundDrawables(null, null, null, null);
Leon Scroggins62e8f942009-09-03 15:08:54 -0400298 ((Animatable) mCircularProgress).stop();
299 mHorizontalProgress.setVisibility(View.INVISIBLE);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500300 if (!mInVoiceMode) {
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400301 mRtButton.setImageDrawable(mBookmarkDrawable);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400302 }
Leon Scroggins81db3662009-06-04 17:45:11 -0400303 mInLoad = false;
304 } else {
Leon Scroggins81db3662009-06-04 17:45:11 -0400305 mHorizontalProgress.setProgress(newProgress);
Nicolas Roard1382b492009-09-16 21:50:06 +0100306 if (!mInLoad && getWindowToken() != null) {
307 // checking the window token lets us be sure that we
308 // are attached to a window before starting the animation,
309 // preventing a potential race condition
310 // (fix for bug http://b/2115736)
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -0400311 mTitle.setCompoundDrawables(null, null, mCircularProgress,
Leon Scroggins62e8f942009-09-03 15:08:54 -0400312 null);
313 ((Animatable) mCircularProgress).start();
314 mHorizontalProgress.setVisibility(View.VISIBLE);
Leon Scroggins11e71b12010-01-25 10:40:38 -0500315 if (!mInVoiceMode) {
Leon Scroggins62e8f942009-09-03 15:08:54 -0400316 mRtButton.setImageDrawable(mStopDrawable);
317 }
318 mInLoad = true;
Leon Scrogginse4b3bda2009-06-09 15:46:41 -0400319 }
Leon Scroggins81db3662009-06-04 17:45:11 -0400320 }
321 }
322
Leon Scroggins1f005d32009-08-10 17:36:42 -0400323 /**
Leon Scroggins58d56c62010-01-28 15:12:40 -0500324 * Update the text displayed in the title bar.
325 * @param title String to display. If null, the loading string will be
326 * shown.
Leon Scroggins1f005d32009-08-10 17:36:42 -0400327 */
Leon Scroggins58d56c62010-01-28 15:12:40 -0500328 /* package */ void setDisplayTitle(String title) {
329 if (title == null) {
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400330 mTitle.setText(R.string.title_bar_loading);
Leon Scrogginsd7c3dd52009-07-20 13:38:47 -0400331 } else {
Leon Scrogginsf48d44e2010-02-05 16:41:49 -0500332 if (mInVoiceMode) {
333 // Add two spaces. The second one will be replaced with an
334 // image, and the first one will put space between it and the
335 // text
336 SpannableString spannable = new SpannableString(title + " ");
337 int end = spannable.length();
338 spannable.setSpan(mArcsSpan, end - 1, end,
339 Spanned.SPAN_MARK_POINT);
340 mTitle.setText(spannable);
341 } else {
342 mTitle.setText(title);
343 }
Leon Scrogginsd7c3dd52009-07-20 13:38:47 -0400344 }
Leon Scroggins81db3662009-06-04 17:45:11 -0400345 }
346
347 /* package */ void setToTabPicker() {
348 mTitle.setText(R.string.tab_picker_title);
349 setFavicon(null);
350 setLock(null);
Leon Scroggins81db3662009-06-04 17:45:11 -0400351 mHorizontalProgress.setVisibility(View.GONE);
Leon Scroggins81db3662009-06-04 17:45:11 -0400352 }
353}