blob: 664fd6862a22abdce9cf6adfcffbbc2d003598a6 [file] [log] [blame]
Leon Scroggins0a64ba52009-09-08 15:35:33 -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
Leon Scrogginsa3315562009-09-18 14:21:08 -040019import android.content.Context;
Patrick Scott555c5802009-09-23 08:08:17 -040020import android.graphics.Bitmap;
Patrick Scott49b11f92009-12-14 09:32:13 -050021import android.os.Handler;
Leon Scrogginsa3315562009-09-18 14:21:08 -040022import android.util.AttributeSet;
Leon Scroggins70a153b2010-05-10 17:27:26 -040023import android.util.Log;
Leon Scroggins0a64ba52009-09-08 15:35:33 -040024import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27import android.widget.AdapterView;
28import android.widget.BaseAdapter;
Leon Scrogginsa3315562009-09-18 14:21:08 -040029import android.widget.ImageView;
Leon Scroggins0a64ba52009-09-08 15:35:33 -040030import android.widget.LinearLayout;
31import android.widget.ListView;
32import android.widget.TextView;
33
34public class ActiveTabsPage extends LinearLayout {
Leon Scroggins0a64ba52009-09-08 15:35:33 -040035
Michael Kolb8233fac2010-10-26 16:08:53 -070036 private static final String LOGTAG = "TabPicker";
37
38 private final LayoutInflater mFactory;
39 private final UiController mUiController;
40 private final TabControl mControl;
41 private final TabsListAdapter mAdapter;
42 private final ListView mListView;
43
44 public ActiveTabsPage(Context context, UiController control) {
Leon Scroggins0a64ba52009-09-08 15:35:33 -040045 super(context);
Michael Kolb8233fac2010-10-26 16:08:53 -070046 mUiController = control;
47 mControl = control.getTabControl();
Leon Scroggins0a64ba52009-09-08 15:35:33 -040048 mFactory = LayoutInflater.from(context);
49 mFactory.inflate(R.layout.active_tabs, this);
50 mListView = (ListView) findViewById(R.id.list);
51 mAdapter = new TabsListAdapter();
52 mListView.setAdapter(mAdapter);
53 mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
54 public void onItemClick(AdapterView<?> parent, View view,
55 int position, long id) {
Grace Kloba22ac16e2009-10-07 18:00:23 -070056 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -070057 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -040058 }
59 boolean needToAttach = false;
Elliott Slaughterf0f03952010-07-14 18:10:36 -070060 if (position == -2) {
Leon Scroggins0a64ba52009-09-08 15:35:33 -040061 // Create a new tab
Michael Kolb8233fac2010-10-26 16:08:53 -070062 mUiController.openTabToHomePage();
Elliott Slaughterf0f03952010-07-14 18:10:36 -070063 } else if (position == -1) {
64 // Create a new incognito tab
Michael Kolb8233fac2010-10-26 16:08:53 -070065 mUiController.openIncognitoTab();
Leon Scroggins0a64ba52009-09-08 15:35:33 -040066 } else {
67 // Open the corresponding tab
68 // If the tab is the current one, switchToTab will
69 // do nothing and return, so we need to make sure
70 // it gets attached back to its mContentView in
71 // removeActiveTabPage
Michael Kolb8233fac2010-10-26 16:08:53 -070072 needToAttach = !mUiController.switchToTab(position);
Leon Scroggins0a64ba52009-09-08 15:35:33 -040073 }
Michael Kolb8233fac2010-10-26 16:08:53 -070074 mUiController.removeActiveTabsPage(needToAttach);
Leon Scroggins0a64ba52009-09-08 15:35:33 -040075 }
76 });
77 }
78
Leon Scrogginsa3315562009-09-18 14:21:08 -040079 /**
80 * Special class to hold the close drawable. Its sole purpose is to allow
81 * the parent to be pressed without being pressed itself. This way the line
82 * of a tab can be pressed, but the close button itself is not.
83 */
84 private static class CloseHolder extends ImageView {
85 public CloseHolder(Context context, AttributeSet attrs) {
86 super(context, attrs);
87 }
88
89 @Override
90 public void setPressed(boolean pressed) {
91 // If the parent is pressed, do not set to pressed.
92 if (pressed && ((View) getParent()).isPressed()) {
93 return;
94 }
95 super.setPressed(pressed);
96 }
97 }
98
Leon Scroggins0a64ba52009-09-08 15:35:33 -040099 private class TabsListAdapter extends BaseAdapter {
Patrick Scott49b11f92009-12-14 09:32:13 -0500100 private boolean mNotified = true;
101 private int mReturnedCount;
102 private Handler mHandler = new Handler();
103
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400104 public int getCount() {
105 int count = mControl.getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700106 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700107 count += 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400108 }
Patrick Scott49b11f92009-12-14 09:32:13 -0500109 // XXX: This is a workaround to be more like a real adapter. Most
110 // adapters call notifyDataSetChanged() whenever the internal data
111 // has changed. Since TabControl is our internal data, we don't
112 // know when that changes.
113 //
114 // Keep track of the last count we returned and whether we called
115 // notifyDataSetChanged(). If we did not initiate a data set
116 // change, and the count is different, send the notify and return
117 // the old count.
118 if (!mNotified && count != mReturnedCount) {
119 notifyChange();
120 return mReturnedCount;
121 }
122 mReturnedCount = count;
123 mNotified = false;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400124 return count;
125 }
126 public Object getItem(int position) {
127 return null;
128 }
129 public long getItemId(int position) {
130 return position;
131 }
Patrick Scott555c5802009-09-23 08:08:17 -0400132 public int getViewTypeCount() {
133 return 2;
134 }
135 public int getItemViewType(int position) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700136 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700137 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400138 }
Patrick Scott555c5802009-09-23 08:08:17 -0400139 // Do not recycle the "add new tab" item.
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700140 return position < 0 ? IGNORE_ITEM_VIEW_TYPE : 1;
Patrick Scott555c5802009-09-23 08:08:17 -0400141 }
142 public View getView(int position, View convertView, ViewGroup parent) {
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400143 final int tabCount = mControl.getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700144 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700145 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400146 }
Patrick Scott555c5802009-09-23 08:08:17 -0400147
148 if (convertView == null) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700149 if (position == -2) {
150 convertView = mFactory.inflate(R.layout.tab_view_add_tab, null);
151 } else if (position == -1) {
152 convertView = mFactory.inflate(R.layout.tab_view_add_incognito_tab, null);
153 } else {
154 convertView = mFactory.inflate(R.layout.tab_view, null);
155 }
Patrick Scott555c5802009-09-23 08:08:17 -0400156 }
157
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700158 if (position >= 0) {
Patrick Scott555c5802009-09-23 08:08:17 -0400159 TextView title =
160 (TextView) convertView.findViewById(R.id.title);
161 TextView url = (TextView) convertView.findViewById(R.id.url);
162 ImageView favicon =
163 (ImageView) convertView.findViewById(R.id.favicon);
164 View close = convertView.findViewById(R.id.close);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700165 Tab tab = mControl.getTab(position);
Leon Scroggins70a153b2010-05-10 17:27:26 -0400166 if (tab.getWebView() == null) {
167 // This means that populatePickerData will have to use the
168 // saved state.
169 Log.w(LOGTAG, "Tab " + position + " has a null WebView and "
170 + (tab.getSavedState() == null ? "null" : "non-null")
171 + " saved state ");
172 }
Leon Scroggins70a153b2010-05-10 17:27:26 -0400173 if (tab.getTitle() == null || tab.getTitle().length() == 0) {
174 Log.w(LOGTAG, "Tab " + position + " has no title. "
175 + "Check above in the Logs to see whether it has a "
176 + "null WebView or null WebHistoryItem");
177 }
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400178 title.setText(tab.getTitle());
179 url.setText(tab.getUrl());
Patrick Scott555c5802009-09-23 08:08:17 -0400180 Bitmap icon = tab.getFavicon();
181 if (icon != null) {
182 favicon.setImageBitmap(icon);
183 } else {
184 favicon.setImageResource(R.drawable.app_web_browser_sm);
185 }
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400186 final int closePosition = position;
187 close.setOnClickListener(new View.OnClickListener() {
188 public void onClick(View v) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700189 mUiController.closeTab(
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400190 mControl.getTab(closePosition));
191 if (tabCount == 1) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700192 mUiController.openTabToHomePage();
193 mUiController.removeActiveTabsPage(false);
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400194 } else {
Patrick Scott49b11f92009-12-14 09:32:13 -0500195 mNotified = true;
196 notifyDataSetChanged();
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400197 }
198 }
199 });
200 }
201 return convertView;
202 }
Patrick Scott49b11f92009-12-14 09:32:13 -0500203
204 void notifyChange() {
205 mHandler.post(new Runnable() {
206 public void run() {
207 mNotified = true;
208 notifyDataSetChanged();
209 }
210 });
211 }
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400212 }
213}