blob: f123c89e1d4455b0874a64de990f29ce62183a65 [file] [log] [blame]
Evan Millar7911ff52009-07-21 15:55:18 -07001/*
Evan Millar5f4af702009-08-11 11:12:00 -07002 * Copyright (C) 2009 The Android Open Source Project
Evan Millar7911ff52009-07-21 15:55:18 -07003 *
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.contacts;
18
Evan Millar5f4af702009-08-11 11:12:00 -070019import java.util.ArrayList;
20
Evan Millar7911ff52009-07-21 15:55:18 -070021import com.android.contacts.ScrollingTabWidget.OnTabSelectionChangedListener;
Evan Millar5f4af702009-08-11 11:12:00 -070022import com.android.contacts.model.ContactsSource;
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070023import com.android.contacts.util.NotifyingAsyncQueryHandler;
Evan Millar5f4af702009-08-11 11:12:00 -070024import com.android.contacts.model.Sources;
Evan Millar1ea3bf72009-07-30 13:46:19 -070025import com.android.internal.widget.ContactHeaderWidget;
Evan Millar7911ff52009-07-21 15:55:18 -070026
27import android.app.Activity;
28import android.content.ContentUris;
Evan Millar7911ff52009-07-21 15:55:18 -070029import android.content.Context;
Evan Millar5f4af702009-08-11 11:12:00 -070030import android.content.Entity;
31import android.content.EntityIterator;
Evan Millar7911ff52009-07-21 15:55:18 -070032import android.content.Intent;
Evan Millar5f4af702009-08-11 11:12:00 -070033import android.content.pm.PackageManager;
Evan Millar7911ff52009-07-21 15:55:18 -070034import android.database.Cursor;
Evan Millar7911ff52009-07-21 15:55:18 -070035import android.graphics.drawable.Drawable;
36import android.net.Uri;
37import android.os.Bundle;
Evan Millar5f4af702009-08-11 11:12:00 -070038import android.os.RemoteException;
Jeff Sharkey0b4ad002009-08-23 14:16:27 -070039import android.provider.ContactsContract.Contacts;
Evan Millar7911ff52009-07-21 15:55:18 -070040import android.provider.ContactsContract.RawContacts;
Evan Millar7911ff52009-07-21 15:55:18 -070041import android.util.Log;
42import android.util.SparseArray;
43import android.view.LayoutInflater;
44import android.view.View;
Jeff Sharkey14f61ab2009-08-05 21:02:37 -070045import android.view.ViewGroup;
Evan Millar7911ff52009-07-21 15:55:18 -070046import android.view.Window;
Evan Millar7911ff52009-07-21 15:55:18 -070047import android.widget.ImageView;
48import android.widget.TextView;
49
50/**
51 * The base Activity class for viewing and editing a contact.
52 */
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070053public abstract class BaseContactCardActivity extends Activity implements
54 NotifyingAsyncQueryHandler.AsyncQueryListener, OnTabSelectionChangedListener {
Evan Millar7911ff52009-07-21 15:55:18 -070055
56 private static final String TAG = "BaseContactCardActivity";
57
58 private SparseArray<Long> mTabRawContactIdMap;
59 protected Uri mUri;
Evan Millar7911ff52009-07-21 15:55:18 -070060 protected ScrollingTabWidget mTabWidget;
Evan Millar1ea3bf72009-07-30 13:46:19 -070061 protected ContactHeaderWidget mContactHeaderWidget;
Evan Millar7911ff52009-07-21 15:55:18 -070062 private NotifyingAsyncQueryHandler mHandler;
Evan Millar7911ff52009-07-21 15:55:18 -070063
64 protected LayoutInflater mInflater;
65
66 //Projection used for the query that determines which tabs to add.
67 protected static final String[] TAB_PROJECTION = new String[] {
68 RawContacts._ID,
69 RawContacts.ACCOUNT_NAME,
70 RawContacts.ACCOUNT_TYPE
71 };
72 protected static final int TAB_CONTACT_ID_COLUMN_INDEX = 0;
73 protected static final int TAB_ACCOUNT_NAME_COLUMN_INDEX = 1;
74 protected static final int TAB_ACCOUNT_TYPE_COLUMN_INDEX = 2;
75
Evan Millar8a79cee2009-08-19 17:20:49 -070076 protected static final String SELECTED_RAW_CONTACT_ID_KEY = "selectedRawContact";
77 protected long mSelectedRawContactId;
78
Evan Millar1ea3bf72009-07-30 13:46:19 -070079 private static final int TOKEN_TABS = 0;
Evan Millar7911ff52009-07-21 15:55:18 -070080
81 @Override
82 protected void onCreate(Bundle icicle) {
83 super.onCreate(icicle);
84
85 mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
86
87 final Intent intent = getIntent();
88 mUri = intent.getData();
Evan Millar7911ff52009-07-21 15:55:18 -070089
90 requestWindowFeature(Window.FEATURE_NO_TITLE);
91 setContentView(R.layout.contact_card_layout);
92
Evan Millar1ea3bf72009-07-30 13:46:19 -070093 mContactHeaderWidget = (ContactHeaderWidget) findViewById(R.id.contact_header_widget);
94 mContactHeaderWidget.showStar(true);
95 mContactHeaderWidget.bindFromContactId(ContentUris.parseId(mUri));
Jeff Sharkey0b4ad002009-08-23 14:16:27 -070096 mContactHeaderWidget.setExcludeMimes(new String[] {
97 Contacts.CONTENT_ITEM_TYPE
98 });
Evan Millar7911ff52009-07-21 15:55:18 -070099
Jeff Sharkey0b4ad002009-08-23 14:16:27 -0700100 mTabWidget = (ScrollingTabWidget) findViewById(R.id.tab_widget);
Evan Millar7911ff52009-07-21 15:55:18 -0700101 mTabWidget.setTabSelectionListener(this);
Evan Millar5f4af702009-08-11 11:12:00 -0700102 mTabWidget.setVisibility(View.INVISIBLE);
Jeff Sharkey0b4ad002009-08-23 14:16:27 -0700103
Evan Millar7911ff52009-07-21 15:55:18 -0700104 mTabRawContactIdMap = new SparseArray<Long>();
105
Evan Millar7911ff52009-07-21 15:55:18 -0700106 mHandler = new NotifyingAsyncQueryHandler(this, this);
107
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700108 // TODO: turn this into async call instead of blocking ui
Evan Millar5f4af702009-08-11 11:12:00 -0700109 asyncSetupTabs();
110 }
111
Evan Millar8a79cee2009-08-19 17:20:49 -0700112
113 @Override
114 protected void onRestoreInstanceState(Bundle savedInstanceState) {
115 super.onRestoreInstanceState(savedInstanceState);
116 mSelectedRawContactId = savedInstanceState.getLong(SELECTED_RAW_CONTACT_ID_KEY);
117 }
118
119 @Override
120 protected void onSaveInstanceState(Bundle outState) {
121 super.onSaveInstanceState(outState);
122 outState.putLong(SELECTED_RAW_CONTACT_ID_KEY, mSelectedRawContactId);
123 }
124
Evan Millar5f4af702009-08-11 11:12:00 -0700125 private void asyncSetupTabs() {
Dmitri Plotnikov8832a642009-08-06 17:24:34 -0700126 long contactId = ContentUris.parseId(mUri);
Evan Millar5f4af702009-08-11 11:12:00 -0700127 mHandler.startQueryEntities(TOKEN_TABS, null,
128 RawContacts.CONTENT_URI, RawContacts.CONTACT_ID + "=" + contactId, null, null);
Evan Millar7911ff52009-07-21 15:55:18 -0700129 }
130
131 /**
Evan Millar8a79cee2009-08-19 17:20:49 -0700132 * Return the RawContact id associated with the tab at an index.
Evan Millar7911ff52009-07-21 15:55:18 -0700133 *
134 * @param index The index of the tab in question.
135 * @return The contactId associated with the tab at the specified index.
136 */
137 protected long getTabRawContactId(int index) {
138 return mTabRawContactIdMap.get(index);
139 }
140
Evan Millar8a79cee2009-08-19 17:20:49 -0700141 /**
142 * Return the tab index associated with the RawContact id.
143 *
144 * @param index The index of the tab in question.
145 * @return The contactId associated with the tab at the specified index.
146 */
147 protected int getTabIndexForRawContactId(long rawContactId) {
148 int numTabs = mTabRawContactIdMap.size();
149 for (int i=0; i < numTabs; i++) {
150 if (mTabRawContactIdMap.get(i) == rawContactId) {
151 return i;
152 }
153 }
154 return -1;
155 }
156
Evan Millar7911ff52009-07-21 15:55:18 -0700157 /** {@inheritDoc} */
Evan Millar5f4af702009-08-11 11:12:00 -0700158 public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
Evan Millar7911ff52009-07-21 15:55:18 -0700159 try{
Evan Millar1ea3bf72009-07-30 13:46:19 -0700160 if (token == TOKEN_TABS) {
Evan Millar7911ff52009-07-21 15:55:18 -0700161 clearCurrentTabs();
Evan Millar5f4af702009-08-11 11:12:00 -0700162 bindTabs(readEntities(iterator));
Evan Millar7911ff52009-07-21 15:55:18 -0700163 }
164 } finally {
Evan Millar5f4af702009-08-11 11:12:00 -0700165 if (iterator != null) {
166 iterator.close();
Evan Millar1ea3bf72009-07-30 13:46:19 -0700167 }
Evan Millar7911ff52009-07-21 15:55:18 -0700168 }
169 }
170
Evan Millar5f4af702009-08-11 11:12:00 -0700171 /** {@inheritDoc} */
172 public void onQueryComplete(int token, Object cookie, Cursor cursor) {
173 // Emtpy
174 }
175
176 private ArrayList<Entity> readEntities(EntityIterator iterator) {
177 ArrayList<Entity> entities = new ArrayList<Entity>();
178 try {
179 while (iterator.hasNext()) {
180 entities.add(iterator.next());
181 }
182 } catch (RemoteException e) {
183 }
184
185 return entities;
186 }
187
Evan Millar7911ff52009-07-21 15:55:18 -0700188 /**
189 * Adds a tab for each {@link RawContact} associated with this contact.
190 * Override this method if you want to additional tabs and/or different
191 * tabs for your activity.
192 *
Evan Millar5f4af702009-08-11 11:12:00 -0700193 * @param entities An {@link ArrayList} of {@link Entity}s of all the RawContacts
194 * associated with the contact being displayed.
Evan Millar7911ff52009-07-21 15:55:18 -0700195 */
Evan Millar5f4af702009-08-11 11:12:00 -0700196 protected void bindTabs(ArrayList<Entity> entities) {
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700197 final Sources sources = Sources.getInstance(this);
198
Evan Millar5f4af702009-08-11 11:12:00 -0700199 for (Entity entity : entities) {
200 final String accountType = entity.getEntityValues().
201 getAsString(RawContacts.ACCOUNT_TYPE);
202 final Long rawContactId = entity.getEntityValues().
203 getAsLong(RawContacts._ID);
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700204
205 // TODO: ensure inflation on background task so we don't block UI thread here
206 final ContactsSource source = sources.getInflatedSource(accountType,
207 ContactsSource.LEVEL_SUMMARY);
Evan Millar5f4af702009-08-11 11:12:00 -0700208 addTab(rawContactId, createTabIndicatorView(mTabWidget, source));
Evan Millar7911ff52009-07-21 15:55:18 -0700209 }
Evan Millar8a79cee2009-08-19 17:20:49 -0700210
211 selectInitialTab();
Evan Millar5f4af702009-08-11 11:12:00 -0700212 mTabWidget.setVisibility(View.VISIBLE);
213 mTabWidget.postInvalidate();
Evan Millar7911ff52009-07-21 15:55:18 -0700214 }
215
Evan Millar5f4af702009-08-11 11:12:00 -0700216
Evan Millar7911ff52009-07-21 15:55:18 -0700217 /**
218 * Add a tab to be displayed in the {@link ScrollingTabWidget}.
219 *
220 * @param contactId The contact id associated with the tab.
221 * @param label A label to display in the tab indicator.
222 * @param icon An icon to display in the tab indicator.
223 */
224 protected void addTab(long contactId, String label, Drawable icon) {
Jeff Sharkey14f61ab2009-08-05 21:02:37 -0700225 addTab(contactId, createTabIndicatorView(mTabWidget, label, icon));
Evan Millar7911ff52009-07-21 15:55:18 -0700226 }
227
228 /**
229 * Add a tab to be displayed in the {@link ScrollingTabWidget}.
230 *
231 * @param contactId The contact id associated with the tab.
232 * @param view A view to use as the tab indicator.
233 */
Evan Millar5f4af702009-08-11 11:12:00 -0700234 protected void addTab(long rawContactId, View view) {
235 mTabRawContactIdMap.put(mTabWidget.getTabCount(), rawContactId);
Evan Millar7911ff52009-07-21 15:55:18 -0700236 mTabWidget.addTab(view);
237 }
238
239
240 protected void clearCurrentTabs() {
241 mTabRawContactIdMap.clear();
242 mTabWidget.removeAllTabs();
243 }
244
Evan Millar8a79cee2009-08-19 17:20:49 -0700245 protected void selectInitialTab() {
246 int selectedTabIndex = -1;
247 if (mSelectedRawContactId > 0) {
248 selectedTabIndex = getTabIndexForRawContactId(mSelectedRawContactId);
249 }
250 if (selectedTabIndex >= 0) {
251 mTabWidget.setCurrentTab(selectedTabIndex);
252 } else {
253 selectDefaultTab();
254 }
255 }
256
Evan Millar7911ff52009-07-21 15:55:18 -0700257 /**
258 * Makes the default tab selection. This is called after the tabs have been
259 * bound for the first time, and whenever a new intent is received. Override
260 * this method if you want to customize the default tab behavior.
261 */
262 protected void selectDefaultTab() {
263 // Select the first tab.
264 mTabWidget.setCurrentTab(0);
265 }
266
267 @Override
268 public void onNewIntent(Intent newIntent) {
269 setIntent(newIntent);
270 selectDefaultTab();
271 mUri = newIntent.getData();
272 }
273
274 /**
275 * Utility for creating a standard tab indicator view.
276 *
Evan Millar5f4af702009-08-11 11:12:00 -0700277 * @param parent The parent ViewGroup to attach the new view to.
Evan Millar7911ff52009-07-21 15:55:18 -0700278 * @param label The label to display in the tab indicator. If null, not label will be displayed.
279 * @param icon The icon to display. If null, no icon will be displayed.
280 * @return The tab indicator View.
281 */
Jeff Sharkey14f61ab2009-08-05 21:02:37 -0700282 public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
283 final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
284 Context.LAYOUT_INFLATER_SERVICE);
285 final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
Evan Millar74660912009-08-19 17:36:33 -0700286 tabIndicator.getBackground().setDither(true);
Evan Millar7911ff52009-07-21 15:55:18 -0700287
288 final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
289 tv.setText(label);
290
291 final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
292 iconView.setImageDrawable(icon);
293
294 return tabIndicator;
295 }
296
Evan Millar5f4af702009-08-11 11:12:00 -0700297 /**
298 * Utility for creating a standard tab indicator view.
299 *
300 * @param context The label to display in the tab indicator. If null, not label will be displayed.
301 * @param parent The parent ViewGroup to attach the new view to.
302 * @param source The {@link ContactsSource} to build the tab view from.
303 * @return The tab indicator View.
304 */
305 public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
306 Drawable icon = null;
307 if (source != null) {
308 final String packageName = source.resPackageName;
309 if (source.iconRes > 0) {
310 try {
311 final Context authContext = parent.getContext().
312 createPackageContext(packageName, 0);
313 icon = authContext.getResources().getDrawable(source.iconRes);
314
315 } catch (PackageManager.NameNotFoundException e) {
316 Log.d(TAG, "error getting the Package Context for " + packageName, e);
317 }
318 }
319 }
320 return createTabIndicatorView(parent, null, icon);
321 }
Evan Millar7911ff52009-07-21 15:55:18 -0700322}