blob: e450a9988c8e9d6972c0a017f2091d84045626f0 [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.KeyEvent;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.ViewGroup;
28import android.widget.AdapterView;
29import android.widget.BaseAdapter;
Leon Scrogginsa3315562009-09-18 14:21:08 -040030import android.widget.ImageView;
Leon Scroggins0a64ba52009-09-08 15:35:33 -040031import android.widget.LinearLayout;
32import android.widget.ListView;
33import android.widget.TextView;
34
35public class ActiveTabsPage extends LinearLayout {
Leon Scroggins70a153b2010-05-10 17:27:26 -040036 private static final String LOGTAG = "TabPicker";
Leon Scroggins0a64ba52009-09-08 15:35:33 -040037 private final BrowserActivity mBrowserActivity;
38 private final LayoutInflater mFactory;
39 private final TabControl mControl;
40 private final TabsListAdapter mAdapter;
41 private final ListView mListView;
42
43 public ActiveTabsPage(BrowserActivity context, TabControl control) {
44 super(context);
45 mBrowserActivity = context;
46 mControl = control;
47 mFactory = LayoutInflater.from(context);
48 mFactory.inflate(R.layout.active_tabs, this);
49 mListView = (ListView) findViewById(R.id.list);
50 mAdapter = new TabsListAdapter();
51 mListView.setAdapter(mAdapter);
52 mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
53 public void onItemClick(AdapterView<?> parent, View view,
54 int position, long id) {
Grace Kloba22ac16e2009-10-07 18:00:23 -070055 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -070056 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -040057 }
58 boolean needToAttach = false;
Elliott Slaughterf0f03952010-07-14 18:10:36 -070059 if (position == -2) {
Leon Scroggins0a64ba52009-09-08 15:35:33 -040060 // Create a new tab
61 mBrowserActivity.openTabToHomePage();
Elliott Slaughterf0f03952010-07-14 18:10:36 -070062 } else if (position == -1) {
63 // Create a new incognito tab
64 mBrowserActivity.openIncognitoTab();
Leon Scroggins0a64ba52009-09-08 15:35:33 -040065 } else {
66 // Open the corresponding tab
67 // If the tab is the current one, switchToTab will
68 // do nothing and return, so we need to make sure
69 // it gets attached back to its mContentView in
70 // removeActiveTabPage
71 needToAttach = !mBrowserActivity.switchToTab(position);
72 }
73 mBrowserActivity.removeActiveTabPage(needToAttach);
74 }
75 });
76 }
77
Leon Scrogginsa3315562009-09-18 14:21:08 -040078 /**
79 * Special class to hold the close drawable. Its sole purpose is to allow
80 * the parent to be pressed without being pressed itself. This way the line
81 * of a tab can be pressed, but the close button itself is not.
82 */
83 private static class CloseHolder extends ImageView {
84 public CloseHolder(Context context, AttributeSet attrs) {
85 super(context, attrs);
86 }
87
88 @Override
89 public void setPressed(boolean pressed) {
90 // If the parent is pressed, do not set to pressed.
91 if (pressed && ((View) getParent()).isPressed()) {
92 return;
93 }
94 super.setPressed(pressed);
95 }
96 }
97
Leon Scroggins0a64ba52009-09-08 15:35:33 -040098 private class TabsListAdapter extends BaseAdapter {
Patrick Scott49b11f92009-12-14 09:32:13 -050099 private boolean mNotified = true;
100 private int mReturnedCount;
101 private Handler mHandler = new Handler();
102
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400103 public int getCount() {
104 int count = mControl.getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700105 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700106 count += 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400107 }
Patrick Scott49b11f92009-12-14 09:32:13 -0500108 // XXX: This is a workaround to be more like a real adapter. Most
109 // adapters call notifyDataSetChanged() whenever the internal data
110 // has changed. Since TabControl is our internal data, we don't
111 // know when that changes.
112 //
113 // Keep track of the last count we returned and whether we called
114 // notifyDataSetChanged(). If we did not initiate a data set
115 // change, and the count is different, send the notify and return
116 // the old count.
117 if (!mNotified && count != mReturnedCount) {
118 notifyChange();
119 return mReturnedCount;
120 }
121 mReturnedCount = count;
122 mNotified = false;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400123 return count;
124 }
125 public Object getItem(int position) {
126 return null;
127 }
128 public long getItemId(int position) {
129 return position;
130 }
Patrick Scott555c5802009-09-23 08:08:17 -0400131 public int getViewTypeCount() {
132 return 2;
133 }
134 public int getItemViewType(int position) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700135 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700136 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400137 }
Patrick Scott555c5802009-09-23 08:08:17 -0400138 // Do not recycle the "add new tab" item.
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700139 return position < 0 ? IGNORE_ITEM_VIEW_TYPE : 1;
Patrick Scott555c5802009-09-23 08:08:17 -0400140 }
141 public View getView(int position, View convertView, ViewGroup parent) {
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400142 final int tabCount = mControl.getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700143 if (mControl.canCreateNewTab()) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700144 position -= 2;
Leon Scroggins0a64ba52009-09-08 15:35:33 -0400145 }
Patrick Scott555c5802009-09-23 08:08:17 -0400146
147 if (convertView == null) {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700148 if (position == -2) {
149 convertView = mFactory.inflate(R.layout.tab_view_add_tab, null);
150 } else if (position == -1) {
151 convertView = mFactory.inflate(R.layout.tab_view_add_incognito_tab, null);
152 } else {
153 convertView = mFactory.inflate(R.layout.tab_view, null);
154 }
Patrick Scott555c5802009-09-23 08:08:17 -0400155 }
156
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700157 if (position >= 0) {
Patrick Scott555c5802009-09-23 08:08:17 -0400158 TextView title =
159 (TextView) convertView.findViewById(R.id.title);
160 TextView url = (TextView) convertView.findViewById(R.id.url);
161 ImageView favicon =
162 (ImageView) convertView.findViewById(R.id.favicon);
163 View close = convertView.findViewById(R.id.close);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700164 Tab tab = mControl.getTab(position);
Leon Scroggins70a153b2010-05-10 17:27:26 -0400165 if (tab.getWebView() == null) {
166 // This means that populatePickerData will have to use the
167 // saved state.
168 Log.w(LOGTAG, "Tab " + position + " has a null WebView and "
169 + (tab.getSavedState() == null ? "null" : "non-null")
170 + " saved state ");
171 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700172 tab.populatePickerData();
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) {
189 mBrowserActivity.closeTab(
190 mControl.getTab(closePosition));
191 if (tabCount == 1) {
192 mBrowserActivity.openTabToHomePage();
193 mBrowserActivity.removeActiveTabPage(false);
194 } 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}