1 /* 2 * Copyright (C) 2008 Esmertec AG. 3 * Copyright (C) 2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.im.app; 19 20 import static android.provider.Contacts.ContactMethods.CONTENT_EMAIL_URI; 21 import android.app.Activity; 22 import android.content.ContentResolver; 23 import android.content.ContentUris; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.database.Cursor; 27 import android.database.DatabaseUtils; 28 import android.net.Uri; 29 import android.os.Bundle; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.provider.Contacts.ContactMethods; 33 import android.text.Editable; 34 import android.text.TextUtils; 35 import android.text.TextWatcher; 36 import android.text.util.Rfc822Token; 37 import android.text.util.Rfc822Tokenizer; 38 import android.util.Log; 39 import android.view.View; 40 import android.widget.Button; 41 import android.widget.MultiAutoCompleteTextView; 42 import android.widget.ResourceCursorAdapter; 43 import android.widget.SimpleCursorAdapter; 44 import android.widget.Spinner; 45 import android.widget.TextView; 46 import com.android.im.IContactList; 47 import com.android.im.IContactListManager; 48 import com.android.im.IImConnection; 49 import com.android.im.R; 50 import com.android.im.engine.ImErrorInfo; 51 import com.android.im.plugin.BrandingResourceIDs; 52 import com.android.im.plugin.ImpsConfigNames; 53 import com.android.im.provider.Imps; 54 import com.android.im.service.ImServiceConstants; 55 56 import java.util.List; 57 58 public class AddContactActivity extends Activity { 59 60 private static final String[] CONTACT_LIST_PROJECTION = { 61 Imps.ContactList._ID, 62 Imps.ContactList.NAME, 63 }; 64 private static final int CONTACT_LIST_NAME_COLUMN = 1; 65 66 private MultiAutoCompleteTextView mAddressList; 67 private Spinner mListSpinner; 68 Button mInviteButton; 69 ImApp mApp; 70 SimpleAlertHandler mHandler; 71 72 private long mProviderId; 73 private long mAccountId; 74 private String mDefaultDomain; 75 76 @Override 77 protected void onCreate(Bundle savedInstanceState) { 78 super.onCreate(savedInstanceState); 79 80 mApp = ImApp.getApplication(this); 81 mHandler = new SimpleAlertHandler(this); 82 resolveIntent(getIntent()); 83 84 setContentView(R.layout.add_contact_activity); 85 86 BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); 87 setTitle(brandingRes.getString(BrandingResourceIDs.STRING_ADD_CONTACT_TITLE)); 88 89 TextView label = (TextView) findViewById(R.id.input_contact_label); 90 label.setText(brandingRes.getString(BrandingResourceIDs.STRING_LABEL_INPUT_CONTACT)); 91 92 mAddressList = (MultiAutoCompleteTextView) findViewById(R.id.email); 93 mAddressList.setAdapter(new EmailAddressAdapter(this)); 94 mAddressList.setTokenizer(new Rfc822Tokenizer()); 95 mAddressList.addTextChangedListener(mTextWatcher); 96 97 mListSpinner = (Spinner) findViewById(R.id.choose_list); 98 99 Cursor c = queryContactLists(); 100 int initSelection = searchInitListPos(c, getIntent().getStringExtra( 101 ImServiceConstants.EXTRA_INTENT_LIST_NAME)); 102 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, 103 android.R.layout.simple_spinner_item, 104 c, 105 new String[] {Imps.ContactList.NAME}, 106 new int[] {android.R.id.text1}); 107 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 108 mListSpinner.setAdapter(adapter); 109 mListSpinner.setSelection(initSelection); 110 111 mInviteButton = (Button) findViewById(R.id.invite); 112 mInviteButton.setText(brandingRes.getString( 113 BrandingResourceIDs.STRING_BUTTON_ADD_CONTACT)); 114 mInviteButton.setOnClickListener(mButtonHandler); 115 mInviteButton.setEnabled(false); 116 } 117 118 private Cursor queryContactLists() { 119 Uri uri = Imps.ContactList.CONTENT_URI; 120 uri = ContentUris.withAppendedId(uri, mProviderId); 121 uri = ContentUris.withAppendedId(uri, mAccountId); 122 Cursor c = managedQuery(uri, CONTACT_LIST_PROJECTION, null, null); 123 return c; 124 } 125 126 private int searchInitListPos(Cursor c, String listName) { 127 if (TextUtils.isEmpty(listName)) { 128 return 0; 129 } 130 c.moveToPosition(-1); 131 while (c.moveToNext()) { 132 if (listName.equals(c.getString(CONTACT_LIST_NAME_COLUMN))) { 133 return c.getPosition(); 134 } 135 } 136 return 0; 137 } 138 139 private void resolveIntent(Intent intent) { 140 mProviderId = intent.getLongExtra( 141 ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, -1); 142 mAccountId = intent.getLongExtra( 143 ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, -1); 144 mDefaultDomain = Imps.ProviderSettings.getStringValue(getContentResolver(), 145 mProviderId, ImpsConfigNames.DEFAULT_DOMAIN); 146 } 147 148 void inviteBuddies() { 149 Rfc822Token[] recipients = Rfc822Tokenizer.tokenize(mAddressList.getText()); 150 try { 151 IImConnection conn = mApp.getConnection(mProviderId); 152 IContactList list = getContactList(conn); 153 if (list == null) { 154 Log.e(ImApp.LOG_TAG, "<AddContactActivity> can't find given contact list:" 155 + getSelectedListName()); 156 finish(); 157 } else { 158 boolean fail = false; 159 for (Rfc822Token recipient : recipients) { 160 String username = recipient.getAddress(); 161 if (mDefaultDomain != null && username.indexOf('@') == -1) { 162 username = username + "@" + mDefaultDomain; 163 } 164 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)){ 165 log("addContact:" + username); 166 } 167 int res = list.addContact(username); 168 if (res != ImErrorInfo.NO_ERROR) { 169 fail = true; 170 mHandler.showAlert(R.string.error, 171 ErrorResUtils.getErrorRes(getResources(), res, username)); 172 } 173 } 174 // close the screen if there's no error. 175 if (!fail) { 176 finish(); 177 } 178 } 179 } catch (RemoteException ex) { 180 Log.e(ImApp.LOG_TAG, "<AddContactActivity> inviteBuddies: caught " + ex); 181 } 182 } 183 184 private IContactList getContactList(IImConnection conn) { 185 if (conn == null) { 186 return null; 187 } 188 189 try { 190 IContactListManager contactListMgr = conn.getContactListManager(); 191 String listName = getSelectedListName(); 192 if (!TextUtils.isEmpty(listName)) { 193 return contactListMgr.getContactList(listName); 194 } else { 195 // Use the default list 196 List<IBinder> lists = contactListMgr.getContactLists(); 197 for (IBinder binder : lists) { 198 IContactList list = IContactList.Stub.asInterface(binder); 199 if (list.isDefault()) { 200 return list; 201 } 202 } 203 // No default list, use the first one as default list 204 if (!lists.isEmpty()) { 205 return IContactList.Stub.asInterface(lists.get(0)); 206 } 207 return null; 208 } 209 } catch (RemoteException e) { 210 // If the service has died, there is no list for now. 211 return null; 212 } 213 } 214 215 private String getSelectedListName() { 216 Cursor c = (Cursor) mListSpinner.getSelectedItem(); 217 return (c == null) ? null : c.getString(CONTACT_LIST_NAME_COLUMN); 218 } 219 220 private View.OnClickListener mButtonHandler = new View.OnClickListener() { 221 public void onClick(View v) { 222 mApp.callWhenServiceConnected(mHandler, new Runnable() { 223 public void run() { 224 inviteBuddies(); 225 } 226 }); 227 } 228 }; 229 230 private TextWatcher mTextWatcher = new TextWatcher() { 231 public void afterTextChanged(Editable s) { 232 mInviteButton.setEnabled(s.length() != 0); 233 } 234 235 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 236 // noop 237 } 238 239 public void onTextChanged(CharSequence s, int start, int before, int count) { 240 // noop 241 } 242 }; 243 244 private static void log(String msg) { 245 Log.d(ImApp.LOG_TAG, "<AddContactActivity> " + msg); 246 } 247 248 static class EmailAddressAdapter extends ResourceCursorAdapter { 249 public static final int DATA_INDEX = 1; 250 251 private static final String SORT_ORDER = "people.name, contact_methods.data"; 252 private ContentResolver mContentResolver; 253 254 private static final String[] PROJECTION = { 255 ContactMethods._ID, // 0 256 ContactMethods.DATA // 1 257 }; 258 259 public EmailAddressAdapter(Context context) { 260 super(context, android.R.layout.simple_dropdown_item_1line, null); 261 mContentResolver = context.getContentResolver(); 262 } 263 264 @Override 265 public final String convertToString(Cursor cursor) { 266 return cursor.getString(DATA_INDEX); 267 } 268 269 @Override 270 public final void bindView(View view, Context context, Cursor cursor) { 271 ((TextView) view).setText(cursor.getString(DATA_INDEX)); 272 } 273 274 @Override 275 public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 276 String where = null; 277 278 if (constraint != null) { 279 String filter = DatabaseUtils.sqlEscapeString(constraint.toString() + '%'); 280 281 StringBuilder s = new StringBuilder(); 282 s.append("(people.name LIKE "); 283 s.append(filter); 284 s.append(") OR (contact_methods.data LIKE "); 285 s.append(filter); 286 s.append(")"); 287 288 where = s.toString(); 289 } 290 291 return mContentResolver.query(CONTENT_EMAIL_URI, PROJECTION, where, null, SORT_ORDER); 292 } 293 } 294 } 295