blob: f5b207c0d1ee6129533b92bfc7dd7ae9e48ee999 [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
19import com.android.contacts.ScrollingTabWidget.OnTabSelectionChangedListener;
Evan Millar5f4af702009-08-11 11:12:00 -070020import com.android.contacts.model.ContactsSource;
21import com.android.contacts.model.Sources;
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -070022import com.android.contacts.util.NotifyingAsyncQueryHandler;
Evan Millar1ea3bf72009-07-30 13:46:19 -070023import com.android.internal.widget.ContactHeaderWidget;
Evan Millar7911ff52009-07-21 15:55:18 -070024
25import android.app.Activity;
26import android.content.ContentUris;
Evan Millar7911ff52009-07-21 15:55:18 -070027import android.content.Context;
Evan Millar5f4af702009-08-11 11:12:00 -070028import android.content.Entity;
29import android.content.EntityIterator;
Evan Millar7911ff52009-07-21 15:55:18 -070030import android.content.Intent;
Evan Millar5f4af702009-08-11 11:12:00 -070031import android.content.pm.PackageManager;
Evan Millar7911ff52009-07-21 15:55:18 -070032import android.database.Cursor;
Evan Millar7911ff52009-07-21 15:55:18 -070033import android.graphics.drawable.Drawable;
34import android.net.Uri;
35import android.os.Bundle;
Evan Millar5f4af702009-08-11 11:12:00 -070036import android.os.RemoteException;
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -070037import android.provider.ContactsContract;
Jeff Sharkey0b4ad002009-08-23 14:16:27 -070038import android.provider.ContactsContract.Contacts;
Evan Millar7911ff52009-07-21 15:55:18 -070039import android.provider.ContactsContract.RawContacts;
Evan Millar7911ff52009-07-21 15:55:18 -070040import android.util.Log;
41import android.util.SparseArray;
42import android.view.LayoutInflater;
43import android.view.View;
Jeff Sharkey14f61ab2009-08-05 21:02:37 -070044import android.view.ViewGroup;
Evan Millar7911ff52009-07-21 15:55:18 -070045import android.view.Window;
Evan Millar7911ff52009-07-21 15:55:18 -070046import android.widget.ImageView;
47import android.widget.TextView;
48
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -070049import java.util.ArrayList;
50
Evan Millar7911ff52009-07-21 15:55:18 -070051/**
52 * The base Activity class for viewing and editing a contact.
53 */
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070054public abstract class BaseContactCardActivity extends Activity implements
55 NotifyingAsyncQueryHandler.AsyncQueryListener, OnTabSelectionChangedListener {
Evan Millar7911ff52009-07-21 15:55:18 -070056
57 private static final String TAG = "BaseContactCardActivity";
58
59 private SparseArray<Long> mTabRawContactIdMap;
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -070060 protected Uri mOriginalUri;
Evan Millar7911ff52009-07-21 15:55:18 -070061 protected Uri mUri;
Evan Millar7911ff52009-07-21 15:55:18 -070062 protected ScrollingTabWidget mTabWidget;
Evan Millar1ea3bf72009-07-30 13:46:19 -070063 protected ContactHeaderWidget mContactHeaderWidget;
Evan Millar7911ff52009-07-21 15:55:18 -070064 private NotifyingAsyncQueryHandler mHandler;
Evan Millar7911ff52009-07-21 15:55:18 -070065
66 protected LayoutInflater mInflater;
67
68 //Projection used for the query that determines which tabs to add.
69 protected static final String[] TAB_PROJECTION = new String[] {
70 RawContacts._ID,
71 RawContacts.ACCOUNT_NAME,
72 RawContacts.ACCOUNT_TYPE
73 };
74 protected static final int TAB_CONTACT_ID_COLUMN_INDEX = 0;
75 protected static final int TAB_ACCOUNT_NAME_COLUMN_INDEX = 1;
76 protected static final int TAB_ACCOUNT_TYPE_COLUMN_INDEX = 2;
77
Evan Millar8a79cee2009-08-19 17:20:49 -070078 protected static final String SELECTED_RAW_CONTACT_ID_KEY = "selectedRawContact";
Evan Millardb5d88c2009-08-28 09:31:57 -070079 protected Long mSelectedRawContactId = null;
Evan Millar8a79cee2009-08-19 17:20:49 -070080
Evan Millar1ea3bf72009-07-30 13:46:19 -070081 private static final int TOKEN_TABS = 0;
Evan Millar7911ff52009-07-21 15:55:18 -070082
83 @Override
84 protected void onCreate(Bundle icicle) {
85 super.onCreate(icicle);
86
87 mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
88
89 final Intent intent = getIntent();
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -070090 resolveContactUriFromIntent(intent);
Evan Millar7911ff52009-07-21 15:55:18 -070091
92 requestWindowFeature(Window.FEATURE_NO_TITLE);
93 setContentView(R.layout.contact_card_layout);
94
Evan Millar1ea3bf72009-07-30 13:46:19 -070095 mContactHeaderWidget = (ContactHeaderWidget) findViewById(R.id.contact_header_widget);
96 mContactHeaderWidget.showStar(true);
97 mContactHeaderWidget.bindFromContactId(ContentUris.parseId(mUri));
Jeff Sharkey0b4ad002009-08-23 14:16:27 -070098 mContactHeaderWidget.setExcludeMimes(new String[] {
99 Contacts.CONTENT_ITEM_TYPE
100 });
Evan Millar7911ff52009-07-21 15:55:18 -0700101
Jeff Sharkey0b4ad002009-08-23 14:16:27 -0700102 mTabWidget = (ScrollingTabWidget) findViewById(R.id.tab_widget);
Evan Millar7911ff52009-07-21 15:55:18 -0700103 mTabWidget.setTabSelectionListener(this);
Evan Millar5f4af702009-08-11 11:12:00 -0700104 mTabWidget.setVisibility(View.INVISIBLE);
Jeff Sharkey0b4ad002009-08-23 14:16:27 -0700105
Evan Millar7911ff52009-07-21 15:55:18 -0700106 mTabRawContactIdMap = new SparseArray<Long>();
107
Evan Millar7911ff52009-07-21 15:55:18 -0700108 mHandler = new NotifyingAsyncQueryHandler(this, this);
109
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700110 // TODO: turn this into async call instead of blocking ui
Evan Millar5f4af702009-08-11 11:12:00 -0700111 asyncSetupTabs();
112 }
113
Evan Millar8a79cee2009-08-19 17:20:49 -0700114
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -0700115 private void resolveContactUriFromIntent(final Intent intent) {
116 mOriginalUri = intent.getData();
117 mUri = ContactsContract.Contacts.lookupContact(getContentResolver(), mOriginalUri);
118 }
119
Evan Millar8a79cee2009-08-19 17:20:49 -0700120 @Override
121 protected void onRestoreInstanceState(Bundle savedInstanceState) {
122 super.onRestoreInstanceState(savedInstanceState);
123 mSelectedRawContactId = savedInstanceState.getLong(SELECTED_RAW_CONTACT_ID_KEY);
124 }
125
126 @Override
127 protected void onSaveInstanceState(Bundle outState) {
128 super.onSaveInstanceState(outState);
129 outState.putLong(SELECTED_RAW_CONTACT_ID_KEY, mSelectedRawContactId);
130 }
131
Evan Millar5f4af702009-08-11 11:12:00 -0700132 private void asyncSetupTabs() {
Dmitri Plotnikov8832a642009-08-06 17:24:34 -0700133 long contactId = ContentUris.parseId(mUri);
Evan Millar5f4af702009-08-11 11:12:00 -0700134 mHandler.startQueryEntities(TOKEN_TABS, null,
135 RawContacts.CONTENT_URI, RawContacts.CONTACT_ID + "=" + contactId, null, null);
Evan Millar7911ff52009-07-21 15:55:18 -0700136 }
137
138 /**
Evan Millar8a79cee2009-08-19 17:20:49 -0700139 * Return the RawContact id associated with the tab at an index.
Evan Millar7911ff52009-07-21 15:55:18 -0700140 *
141 * @param index The index of the tab in question.
142 * @return The contactId associated with the tab at the specified index.
143 */
144 protected long getTabRawContactId(int index) {
145 return mTabRawContactIdMap.get(index);
146 }
147
Evan Millar8a79cee2009-08-19 17:20:49 -0700148 /**
149 * Return the tab index associated with the RawContact id.
150 *
151 * @param index The index of the tab in question.
152 * @return The contactId associated with the tab at the specified index.
153 */
154 protected int getTabIndexForRawContactId(long rawContactId) {
155 int numTabs = mTabRawContactIdMap.size();
156 for (int i=0; i < numTabs; i++) {
157 if (mTabRawContactIdMap.get(i) == rawContactId) {
158 return i;
159 }
160 }
161 return -1;
162 }
163
Evan Millar7911ff52009-07-21 15:55:18 -0700164 /** {@inheritDoc} */
Evan Millar5f4af702009-08-11 11:12:00 -0700165 public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
Evan Millar7911ff52009-07-21 15:55:18 -0700166 try{
Evan Millar1ea3bf72009-07-30 13:46:19 -0700167 if (token == TOKEN_TABS) {
Evan Millar7911ff52009-07-21 15:55:18 -0700168 clearCurrentTabs();
Evan Millar5f4af702009-08-11 11:12:00 -0700169 bindTabs(readEntities(iterator));
Evan Millar7911ff52009-07-21 15:55:18 -0700170 }
171 } finally {
Evan Millar5f4af702009-08-11 11:12:00 -0700172 if (iterator != null) {
173 iterator.close();
Evan Millar1ea3bf72009-07-30 13:46:19 -0700174 }
Evan Millar7911ff52009-07-21 15:55:18 -0700175 }
176 }
177
Evan Millar5f4af702009-08-11 11:12:00 -0700178 /** {@inheritDoc} */
179 public void onQueryComplete(int token, Object cookie, Cursor cursor) {
180 // Emtpy
181 }
182
183 private ArrayList<Entity> readEntities(EntityIterator iterator) {
184 ArrayList<Entity> entities = new ArrayList<Entity>();
185 try {
186 while (iterator.hasNext()) {
187 entities.add(iterator.next());
188 }
189 } catch (RemoteException e) {
190 }
191
192 return entities;
193 }
194
Evan Millar7911ff52009-07-21 15:55:18 -0700195 /**
196 * Adds a tab for each {@link RawContact} associated with this contact.
197 * Override this method if you want to additional tabs and/or different
198 * tabs for your activity.
199 *
Evan Millar5f4af702009-08-11 11:12:00 -0700200 * @param entities An {@link ArrayList} of {@link Entity}s of all the RawContacts
201 * associated with the contact being displayed.
Evan Millar7911ff52009-07-21 15:55:18 -0700202 */
Evan Millar5f4af702009-08-11 11:12:00 -0700203 protected void bindTabs(ArrayList<Entity> entities) {
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700204 final Sources sources = Sources.getInstance(this);
205
Evan Millar5f4af702009-08-11 11:12:00 -0700206 for (Entity entity : entities) {
207 final String accountType = entity.getEntityValues().
208 getAsString(RawContacts.ACCOUNT_TYPE);
209 final Long rawContactId = entity.getEntityValues().
210 getAsLong(RawContacts._ID);
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700211
212 // TODO: ensure inflation on background task so we don't block UI thread here
213 final ContactsSource source = sources.getInflatedSource(accountType,
214 ContactsSource.LEVEL_SUMMARY);
Evan Millar56d2caa2009-08-20 20:30:12 -0700215 addTab(rawContactId, createTabIndicatorView(mTabWidget.getTabParent(), source));
Evan Millar7911ff52009-07-21 15:55:18 -0700216 }
Evan Millar8a79cee2009-08-19 17:20:49 -0700217
218 selectInitialTab();
Evan Millar5f4af702009-08-11 11:12:00 -0700219 mTabWidget.setVisibility(View.VISIBLE);
220 mTabWidget.postInvalidate();
Evan Millar7911ff52009-07-21 15:55:18 -0700221 }
222
Evan Millar7911ff52009-07-21 15:55:18 -0700223 /**
224 * Add a tab to be displayed in the {@link ScrollingTabWidget}.
225 *
226 * @param contactId The contact id associated with the tab.
227 * @param view A view to use as the tab indicator.
228 */
Evan Millar5f4af702009-08-11 11:12:00 -0700229 protected void addTab(long rawContactId, View view) {
230 mTabRawContactIdMap.put(mTabWidget.getTabCount(), rawContactId);
Evan Millar7911ff52009-07-21 15:55:18 -0700231 mTabWidget.addTab(view);
232 }
233
234
235 protected void clearCurrentTabs() {
236 mTabRawContactIdMap.clear();
237 mTabWidget.removeAllTabs();
238 }
239
Evan Millar8a79cee2009-08-19 17:20:49 -0700240 protected void selectInitialTab() {
Evan Millardb5d88c2009-08-28 09:31:57 -0700241 int selectedTabIndex = 0;
Evan Millar8a79cee2009-08-19 17:20:49 -0700242
Evan Millardb5d88c2009-08-28 09:31:57 -0700243 if (mSelectedRawContactId != null) {
244 selectedTabIndex = getTabIndexForRawContactId(mSelectedRawContactId);
245 if (selectedTabIndex == -1) {
246 // If there was no matching tab, just select the first;
247 selectedTabIndex = 0;
248 }
249 }
250
251 mTabWidget.setCurrentTab(selectedTabIndex);
252 onTabSelectionChanged(selectedTabIndex, false);
Evan Millar7911ff52009-07-21 15:55:18 -0700253 }
254
255 @Override
256 public void onNewIntent(Intent newIntent) {
257 setIntent(newIntent);
Dmitri Plotnikov3d53ce22009-09-02 08:44:32 -0700258 resolveContactUriFromIntent(newIntent);
Evan Millardb5d88c2009-08-28 09:31:57 -0700259 selectInitialTab();
Evan Millar7911ff52009-07-21 15:55:18 -0700260 }
261
262 /**
263 * Utility for creating a standard tab indicator view.
264 *
Evan Millar5f4af702009-08-11 11:12:00 -0700265 * @param parent The parent ViewGroup to attach the new view to.
Evan Millar7911ff52009-07-21 15:55:18 -0700266 * @param label The label to display in the tab indicator. If null, not label will be displayed.
267 * @param icon The icon to display. If null, no icon will be displayed.
268 * @return The tab indicator View.
269 */
Jeff Sharkey14f61ab2009-08-05 21:02:37 -0700270 public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
271 final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
272 Context.LAYOUT_INFLATER_SERVICE);
273 final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
Evan Millar74660912009-08-19 17:36:33 -0700274 tabIndicator.getBackground().setDither(true);
Evan Millar7911ff52009-07-21 15:55:18 -0700275
276 final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
277 tv.setText(label);
278
279 final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
280 iconView.setImageDrawable(icon);
281
282 return tabIndicator;
283 }
284
Evan Millar5f4af702009-08-11 11:12:00 -0700285 /**
286 * Utility for creating a standard tab indicator view.
287 *
288 * @param context The label to display in the tab indicator. If null, not label will be displayed.
289 * @param parent The parent ViewGroup to attach the new view to.
290 * @param source The {@link ContactsSource} to build the tab view from.
291 * @return The tab indicator View.
292 */
293 public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
294 Drawable icon = null;
295 if (source != null) {
296 final String packageName = source.resPackageName;
297 if (source.iconRes > 0) {
298 try {
299 final Context authContext = parent.getContext().
300 createPackageContext(packageName, 0);
301 icon = authContext.getResources().getDrawable(source.iconRes);
302
303 } catch (PackageManager.NameNotFoundException e) {
304 Log.d(TAG, "error getting the Package Context for " + packageName, e);
305 }
306 }
307 }
308 return createTabIndicatorView(parent, null, icon);
309 }
Evan Millar7911ff52009-07-21 15:55:18 -0700310}