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"); you may not 6 * use this file except in compliance with the License. You may obtain a copy of 7 * 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, WITHOUT 13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 * License for the specific language governing permissions and limitations under 15 * the License. 16 */ 17 package com.android.im.app; 18 19 import static com.android.im.service.ImServiceConstants.ACTION_MANAGE_SUBSCRIPTION; 20 import static com.android.im.service.ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID; 21 import static com.android.im.service.ImServiceConstants.EXTRA_INTENT_FROM_ADDRESS; 22 import static com.android.im.service.ImServiceConstants.EXTRA_INTENT_PROVIDER_ID; 23 import static com.android.im.service.ImServiceConstants.EXTRA_INTENT_SHOW_MULTIPLE; 24 25 import com.android.im.IChatSession; 26 import com.android.im.R; 27 import com.android.im.app.adapter.ChatListenerAdapter; 28 import com.android.im.plugin.BrandingResourceIDs; 29 30 import android.app.Activity; 31 import android.app.AlertDialog; 32 import android.content.ContentResolver; 33 import android.content.ContentUris; 34 import android.content.DialogInterface; 35 import android.content.Intent; 36 import android.database.Cursor; 37 import android.graphics.drawable.Drawable; 38 import android.net.Uri; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.RemoteException; 42 import android.provider.Im; 43 import android.view.KeyEvent; 44 import android.view.LayoutInflater; 45 import android.view.Menu; 46 import android.view.MenuInflater; 47 import android.view.MenuItem; 48 import android.view.View; 49 import android.view.ViewGroup; 50 import android.view.Window; 51 import android.widget.ImageView; 52 import android.widget.SimpleAdapter; 53 import android.widget.Toast; 54 55 import java.util.ArrayList; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Map; 59 60 public class NewChatActivity extends Activity { 61 62 private static final int REQUEST_PICK_CONTACTS = RESULT_FIRST_USER + 1; 63 64 ImApp mApp; 65 66 ChatView mChatView; 67 SimpleAlertHandler mHandler; 68 69 private AlertDialog mSmileyDialog; 70 private ChatSwitcher mChatSwitcher; 71 72 private LayoutInflater mInflater; 73 74 @Override onCreate(Bundle icicle)75 protected void onCreate(Bundle icicle) { 76 super.onCreate(icicle); 77 78 requestWindowFeature(Window.FEATURE_NO_TITLE); 79 80 setContentView(R.layout.chat_view); 81 82 mChatView = (ChatView) findViewById(R.id.chatView); 83 mHandler = mChatView.mHandler; 84 mInflater = LayoutInflater.from(this); 85 86 mApp = ImApp.getApplication(this); 87 mChatSwitcher = new ChatSwitcher(this, mHandler, mApp, mInflater, null); 88 89 final Handler handler = new Handler(); 90 mApp.callWhenServiceConnected(handler, new Runnable() { 91 public void run() { 92 resolveIntent(getIntent()); 93 } 94 }); 95 } 96 97 @Override onResume()98 protected void onResume() { 99 super.onResume(); 100 mChatView.onResume(); 101 } 102 103 @Override onPause()104 protected void onPause() { 105 mChatView.onPause(); 106 super.onPause(); 107 } 108 109 @Override onNewIntent(Intent intent)110 protected void onNewIntent(Intent intent) { 111 resolveIntent(intent); 112 } 113 resolveIntent(Intent intent)114 void resolveIntent(Intent intent) { 115 if (requireOpenDashboardOnStart(intent)) { 116 long providerId = intent.getLongExtra(EXTRA_INTENT_PROVIDER_ID, -1L); 117 final long accountId = intent.getLongExtra(EXTRA_INTENT_ACCOUNT_ID, -1L); 118 if (providerId == -1L || accountId == -1L) { 119 finish(); 120 } else { 121 mChatSwitcher.open(); 122 } 123 return; 124 } 125 126 if (ACTION_MANAGE_SUBSCRIPTION.equals(intent.getAction())) { 127 long providerId = intent.getLongExtra(EXTRA_INTENT_PROVIDER_ID, -1); 128 String from = intent.getStringExtra(EXTRA_INTENT_FROM_ADDRESS); 129 if ((providerId == -1) || (from == null)) { 130 finish(); 131 } else { 132 mChatView.bindSubscription(providerId, from); 133 } 134 } else { 135 Uri data = intent.getData(); 136 String type = getContentResolver().getType(data); 137 if (Im.Chats.CONTENT_ITEM_TYPE.equals(type)) { 138 mChatView.bindChat(ContentUris.parseId(data)); 139 } else if (Im.Invitation.CONTENT_ITEM_TYPE.equals(type)) { 140 mChatView.bindInvitation(ContentUris.parseId(data)); 141 } 142 } 143 } 144 145 @Override onCreateOptionsMenu(Menu menu)146 public boolean onCreateOptionsMenu(Menu menu) { 147 MenuInflater inflater = getMenuInflater(); 148 inflater.inflate(R.menu.chat_screen_menu, menu); 149 150 long providerId = mChatView.getProviderId(); 151 BrandingResources brandingRes = mApp.getBrandingResource(providerId); 152 menu.findItem(R.id.menu_view_friend_list).setTitle( 153 brandingRes.getString(BrandingResourceIDs.STRING_MENU_CONTACT_LIST)); 154 menu.findItem(R.id.menu_switch_chats).setTitle( 155 brandingRes.getString(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS)); 156 menu.findItem(R.id.menu_insert_smiley).setTitle( 157 brandingRes.getString(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY)); 158 menu.findItem(R.id.menu_end_conversation).setTitle( 159 brandingRes.getString(BrandingResourceIDs.STRING_MENU_END_CHAT)); 160 menu.findItem(R.id.menu_view_profile).setTitle( 161 brandingRes.getString(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE)); 162 menu.findItem(R.id.menu_block_contact).setTitle( 163 brandingRes.getString(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT)); 164 return true; 165 } 166 167 @Override onPrepareOptionsMenu(Menu menu)168 public boolean onPrepareOptionsMenu(Menu menu) { 169 super.onPrepareOptionsMenu(menu); 170 171 //XXX hide the invite menu, group chat is not supported by the server. 172 menu.findItem(R.id.menu_invite_contact).setVisible(false); 173 174 //XXX HACK: Yahoo! doesn't allow to block a friend. We can only block a temporary contact. 175 ProviderDef provider = mApp.getProvider(mChatView.getProviderId()); 176 if ((provider != null) && Im.ProviderNames.YAHOO.equals(provider.mName)) { 177 if (Im.Contacts.TYPE_TEMPORARY != mChatView.mType) { 178 menu.findItem(R.id.menu_block_contact).setVisible(false); 179 } 180 } 181 return true; 182 } 183 184 @Override onOptionsItemSelected(MenuItem item)185 public boolean onOptionsItemSelected(MenuItem item) { 186 switch (item.getItemId()) { 187 case R.id.menu_view_friend_list: 188 finish(); 189 showRosterScreen(); 190 return true; 191 192 case R.id.menu_insert_smiley: 193 showSmileyDialog(); 194 return true; 195 196 case R.id.menu_end_conversation: 197 mChatView.closeChatSession(); 198 return true; 199 200 case R.id.menu_switch_chats: 201 if (mChatSwitcher.isOpen()) { 202 mChatSwitcher.close(); 203 } else { 204 mChatSwitcher.open(); 205 } 206 207 return true; 208 209 case R.id.menu_invite_contact: 210 startContactPicker(); 211 return true; 212 213 case R.id.menu_view_profile: 214 mChatView.viewProfile(); 215 return true; 216 217 case R.id.menu_block_contact: 218 mChatView.blockContact(); 219 return true; 220 221 case R.id.menu_prev_chat: 222 switchChat(-1); 223 return true; 224 225 case R.id.menu_next_chat: 226 switchChat(1); 227 return true; 228 229 case R.id.menu_quick_switch_0: 230 case R.id.menu_quick_switch_1: 231 case R.id.menu_quick_switch_2: 232 case R.id.menu_quick_switch_3: 233 case R.id.menu_quick_switch_4: 234 case R.id.menu_quick_switch_5: 235 case R.id.menu_quick_switch_6: 236 case R.id.menu_quick_switch_7: 237 case R.id.menu_quick_switch_8: 238 case R.id.menu_quick_switch_9: 239 mChatSwitcher.handleShortcut(item.getAlphabeticShortcut()); 240 return true; 241 } 242 243 return super.onOptionsItemSelected(item); 244 } 245 246 @Override dispatchKeyEvent(KeyEvent event)247 public boolean dispatchKeyEvent(KeyEvent event) { 248 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK 249 && event.getAction() == KeyEvent.ACTION_DOWN) { 250 mChatView.closeChatSessionIfInactive(); 251 } 252 return super.dispatchKeyEvent(event); 253 } 254 255 /** 256 * Check whether we are asked to open Dashboard on startup. 257 */ requireOpenDashboardOnStart(Intent intent)258 private boolean requireOpenDashboardOnStart(Intent intent) { 259 return intent.getBooleanExtra(EXTRA_INTENT_SHOW_MULTIPLE, false); 260 } 261 showRosterScreen()262 private void showRosterScreen() { 263 Intent intent = new Intent(Intent.ACTION_VIEW); 264 intent.setClass(this, ContactListActivity.class); 265 intent.putExtra(EXTRA_INTENT_ACCOUNT_ID, mChatView.getAccountId()); 266 startActivity(intent); 267 } 268 showSmileyDialog()269 private void showSmileyDialog() { 270 if (mSmileyDialog == null) { 271 long providerId = mChatView.getProviderId(); 272 273 final BrandingResources brandingRes = mApp.getBrandingResource(providerId); 274 int[] icons = brandingRes.getSmileyIcons(); 275 String[] names = brandingRes.getStringArray( 276 BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES); 277 final String[] texts = brandingRes.getStringArray( 278 BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS); 279 280 final int N = names.length; 281 282 List<Map<String, ?>> entries = new ArrayList<Map<String, ?>>(); 283 for (int i = 0; i < N; i++) { 284 // We might have different ASCII for the same icon, skip it if 285 // the icon is already added. 286 boolean added = false; 287 for (int j = 0; j < i; j++) { 288 if (icons[i] == icons[j]) { 289 added = true; 290 break; 291 } 292 } 293 if (!added) { 294 HashMap<String, Object> entry = new HashMap<String, Object>(); 295 296 entry. put("icon", icons[i]); 297 entry. put("name", names[i]); 298 entry.put("text", texts[i]); 299 300 entries.add(entry); 301 } 302 } 303 304 final SimpleAdapter a = new SimpleAdapter( 305 this, 306 entries, 307 R.layout.smiley_menu_item, 308 new String[] {"icon", "name", "text"}, 309 new int[] {R.id.smiley_icon, R.id.smiley_name, R.id.smiley_text}); 310 SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() { 311 public boolean setViewValue(View view, Object data, String textRepresentation) { 312 if (view instanceof ImageView) { 313 Drawable img = brandingRes.getSmileyIcon((Integer)data); 314 ((ImageView)view).setImageDrawable(img); 315 return true; 316 } 317 return false; 318 } 319 }; 320 a.setViewBinder(viewBinder); 321 322 AlertDialog.Builder b = new AlertDialog.Builder(this); 323 324 b.setTitle(brandingRes.getString( 325 BrandingResourceIDs.STRING_MENU_INSERT_SMILEY)); 326 327 b.setCancelable(true); 328 b.setAdapter(a, new DialogInterface.OnClickListener() { 329 public final void onClick(DialogInterface dialog, int which) { 330 HashMap<String, Object> item = (HashMap<String, Object>) a.getItem(which); 331 mChatView.insertSmiley((String)item.get("text")); 332 } 333 }); 334 335 mSmileyDialog = b.create(); 336 } 337 338 mSmileyDialog.show(); 339 } 340 switchChat(int delta)341 private void switchChat(int delta) { 342 long providerId = mChatView.getProviderId(); 343 long accountId = mChatView.getAccountId(); 344 String contact = mChatView.getUserName(); 345 346 mChatSwitcher.rotateChat(delta, contact, accountId, providerId); 347 } 348 startContactPicker()349 private void startContactPicker() { 350 Uri.Builder builder = Im.Contacts.CONTENT_URI_ONLINE_CONTACTS_BY.buildUpon(); 351 ContentUris.appendId(builder, mChatView.getProviderId()); 352 ContentUris.appendId(builder, mChatView.getAccountId()); 353 Uri data = builder.build(); 354 355 try { 356 Intent i = new Intent(Intent.ACTION_PICK, data); 357 i.putExtra(ContactsPickerActivity.EXTRA_EXCLUDED_CONTACTS, 358 mChatView.getCurrentChatSession().getPariticipants()); 359 startActivityForResult(i, REQUEST_PICK_CONTACTS); 360 } catch (RemoteException e) { 361 mHandler.showServiceErrorAlert(); 362 } 363 } 364 365 @Override onActivityResult(int requestCode, int resultCode, Intent data)366 protected void onActivityResult(int requestCode, int resultCode, 367 Intent data) { 368 if (resultCode == RESULT_OK) { 369 if (requestCode == REQUEST_PICK_CONTACTS) { 370 String username = data.getStringExtra( 371 ContactsPickerActivity.EXTRA_RESULT_USERNAME); 372 try { 373 IChatSession chatSession = mChatView.getCurrentChatSession(); 374 if (chatSession.isGroupChatSession()) { 375 chatSession.inviteContact(username); 376 showInvitationHasSent(username); 377 } else { 378 chatSession.convertToGroupChat(); 379 new ContactInvitor(chatSession, username).start(); 380 } 381 } catch (RemoteException e) { 382 mHandler.showServiceErrorAlert(); 383 } 384 } 385 } 386 } 387 showInvitationHasSent(String contact)388 void showInvitationHasSent(String contact) { 389 Toast.makeText(NewChatActivity.this, 390 getString(R.string.invitation_sent_prompt, contact), 391 Toast.LENGTH_SHORT).show(); 392 } 393 394 private class ContactInvitor extends ChatListenerAdapter { 395 private final IChatSession mChatSession; 396 String mContact; 397 ContactInvitor(IChatSession session, String data)398 public ContactInvitor(IChatSession session, String data) { 399 mChatSession = session; 400 mContact = data; 401 } 402 403 @Override onConvertedToGroupChat(IChatSession ses)404 public void onConvertedToGroupChat(IChatSession ses) { 405 try { 406 final long chatId = mChatSession.getId(); 407 mChatSession.inviteContact(mContact); 408 mHandler.post(new Runnable(){ 409 public void run() { 410 mChatView.bindChat(chatId); 411 showInvitationHasSent(mContact); 412 } 413 }); 414 mChatSession.unregisterChatListener(this); 415 } catch (RemoteException e) { 416 mHandler.showServiceErrorAlert(); 417 } 418 } 419 start()420 public void start() throws RemoteException { 421 mChatSession.registerChatListener(this); 422 } 423 } 424 } 425