2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.im.app;
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;
25 import com.android.im.IChatSession;
26 import com.android.im.R;
27 import com.android.im.app.Dashboard.OnCancelListener;
28 import com.android.im.app.adapter.ChatListenerAdapter;
29 import com.android.im.plugin.BrandingResourceIDs;
31 import android.app.Activity;
32 import android.app.AlertDialog;
33 import android.content.ContentResolver;
34 import android.content.ContentUris;
35 import android.content.DialogInterface;
36 import android.content.Intent;
37 import android.database.Cursor;
38 import android.graphics.drawable.Drawable;
39 import android.net.Uri;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.RemoteException;
43 import android.provider.Im;
44 import android.view.KeyEvent;
45 import android.view.Menu;
46 import android.view.MenuInflater;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.Window;
50 import android.widget.ImageView;
51 import android.widget.SimpleAdapter;
52 import android.widget.Toast;
54 import java.util.ArrayList;
55 import java.util.HashMap;
56 import java.util.List;
59 public class NewChatActivity extends Activity {
60 private static final String GTALK_PACKAGE_NAME_= "com.google.android.talk";
61 private static final String GTALK_CHAT_SCREEN_COMPONENT_NAME =
62 "com.google.android.talk.ChatScreen";
64 private static final String[] CHAT_SWITCHER_PROJECTION = {
72 private static final int CHAT_SWITCHER_ID_COLUMN = 0;
73 private static final int CHAT_SWITCHER_PROVIDER_COLUMN = 1;
74 private static final int CHAT_SWITCHER_ACCOUNT_COLUMN = 2;
75 private static final int CHAT_SWITCHER_USERNAME_COLUMN = 3;
76 private static final int CHAT_SWITCHER_GROUP_COLUMN = 4;
78 private static final int REQUEST_PICK_CONTACTS = RESULT_FIRST_USER + 1;
83 SimpleAlertHandler mHandler;
85 private AlertDialog mSmileyDialog;
86 private Dashboard mDashboard;
89 protected void onCreate(Bundle icicle) {
90 super.onCreate(icicle);
92 requestWindowFeature(Window.FEATURE_NO_TITLE);
94 setContentView(R.layout.chat_view);
96 mChatView = (ChatView) findViewById(R.id.chatView);
97 mHandler = mChatView.mHandler;
99 final Handler handler = new Handler();
100 mApp= ImApp.getApplication(this);
101 mApp.callWhenServiceConnected(handler, new Runnable() {
103 resolveIntent(getIntent());
109 protected void onResume() {
111 mChatView.onResume();
115 protected void onPause() {
121 protected void onNewIntent(Intent intent) {
122 resolveIntent(intent);
125 void resolveIntent(Intent intent) {
126 if (requireOpenDashboardOnStart(intent)) {
127 long providerId = intent.getLongExtra(EXTRA_INTENT_PROVIDER_ID, -1L);
128 final long accountId = intent.getLongExtra(EXTRA_INTENT_ACCOUNT_ID, -1L);
129 if (providerId == -1L || accountId == -1L) {
132 mApp.dismissNotifications(providerId);
133 // TODO: the delay runnable is a hack. If we don't put any delay, showing the
134 // Dashboard window will cause
136 // android.view.WindowManager$BadTokenException: Unable to add window --
137 // token null is not valid; is your activity running?
139 // exception. This problem should go away when the new chat switcher UI is
140 // implemented. The new chat switcher is just another view in the chat screen.
141 mHandler.postDelayed(new Runnable() {
143 mDashboard = Dashboard.openDashboard(NewChatActivity.this, accountId, null);
144 mDashboard.setOnCancelListener(new OnCancelListener() {
145 public void onCancel() {
155 if (ACTION_MANAGE_SUBSCRIPTION.equals(intent.getAction())) {
156 long providerId = intent.getLongExtra(EXTRA_INTENT_PROVIDER_ID, -1);
157 String from = intent.getStringExtra(EXTRA_INTENT_FROM_ADDRESS);
158 if ((providerId == -1) || (from == null)) {
161 mChatView.bindSubscription(providerId, from);
164 Uri data = intent.getData();
165 String type = getContentResolver().getType(data);
166 if (Im.Chats.CONTENT_ITEM_TYPE.equals(type)) {
167 mChatView.bindChat(ContentUris.parseId(data));
168 } else if (Im.Invitation.CONTENT_ITEM_TYPE.equals(type)) {
169 mChatView.bindInvitation(ContentUris.parseId(data));
175 public boolean onCreateOptionsMenu(Menu menu) {
176 MenuInflater inflater = getMenuInflater();
177 inflater.inflate(R.menu.chat_screen_menu, menu);
179 long providerId = mChatView.getProviderId();
180 BrandingResources brandingRes = mApp.getBrandingResource(providerId);
181 menu.findItem(R.id.menu_view_friend_list).setTitle(
182 brandingRes.getString(BrandingResourceIDs.STRING_MENU_CONTACT_LIST));
183 menu.findItem(R.id.menu_switch_chats).setTitle(
184 brandingRes.getString(BrandingResourceIDs.STRING_MENU_SWITCH_CHATS));
185 menu.findItem(R.id.menu_insert_smiley).setTitle(
186 brandingRes.getString(BrandingResourceIDs.STRING_MENU_INSERT_SMILEY));
187 menu.findItem(R.id.menu_end_conversation).setTitle(
188 brandingRes.getString(BrandingResourceIDs.STRING_MENU_END_CHAT));
189 menu.findItem(R.id.menu_view_profile).setTitle(
190 brandingRes.getString(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE));
191 menu.findItem(R.id.menu_block_contact).setTitle(
192 brandingRes.getString(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT));
197 public boolean onPrepareOptionsMenu(Menu menu) {
198 super.onPrepareOptionsMenu(menu);
200 //XXX hide the invite menu, group chat is not supported by the server.
201 menu.findItem(R.id.menu_invite_contact).setVisible(false);
203 //XXX HACK: Yahoo! doesn't allow to block a friend. We can only block a temporary contact.
204 ProviderDef provider = mApp.getProvider(mChatView.getProviderId());
205 if ((provider != null) && Im.ProviderNames.YAHOO.equals(provider.mName)) {
206 if (Im.Contacts.TYPE_TEMPORARY != mChatView.mType) {
207 menu.findItem(R.id.menu_block_contact).setVisible(false);
214 public boolean onOptionsItemSelected(MenuItem item) {
215 switch (item.getItemId()) {
216 case R.id.menu_view_friend_list:
221 case R.id.menu_insert_smiley:
225 case R.id.menu_end_conversation:
226 mChatView.closeChatSession();
229 case R.id.menu_switch_chats:
230 Dashboard.openDashboard(this, mChatView.getAccountId(),
231 mChatView.getUserName());
234 case R.id.menu_invite_contact:
235 startContactPicker();
238 case R.id.menu_view_profile:
239 mChatView.viewProfile();
242 case R.id.menu_block_contact:
243 mChatView.blockContact();
246 case R.id.menu_prev_chat:
250 case R.id.menu_next_chat:
254 case R.id.menu_quick_switch_0:
255 case R.id.menu_quick_switch_1:
256 case R.id.menu_quick_switch_2:
257 case R.id.menu_quick_switch_3:
258 case R.id.menu_quick_switch_4:
259 case R.id.menu_quick_switch_5:
260 case R.id.menu_quick_switch_6:
261 case R.id.menu_quick_switch_7:
262 case R.id.menu_quick_switch_8:
263 case R.id.menu_quick_switch_9:
264 ContentResolver cr = getContentResolver();
265 Cursor c = cr.query(Im.Contacts.CONTENT_URI_CHAT_CONTACTS,
270 int slot = item.getAlphabeticShortcut() - '0';
271 if (Dashboard.quickSwitch(this, c, slot)) {
278 return super.onOptionsItemSelected(item);
282 public boolean dispatchKeyEvent(KeyEvent event) {
283 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
284 && event.getAction() == KeyEvent.ACTION_DOWN) {
285 mChatView.closeChatSessionIfInactive();
287 return super.dispatchKeyEvent(event);
291 * Check whether we are asked to open Dashboard on startup.
293 private boolean requireOpenDashboardOnStart(Intent intent) {
294 return intent.getBooleanExtra(EXTRA_INTENT_SHOW_MULTIPLE, false);
297 private void showRosterScreen() {
298 Intent intent = new Intent(Intent.ACTION_VIEW);
299 intent.setClass(this, ContactListActivity.class);
300 intent.putExtra(EXTRA_INTENT_ACCOUNT_ID, mChatView.getAccountId());
301 startActivity(intent);
304 private void showSmileyDialog() {
305 if (mSmileyDialog == null) {
306 long providerId = mChatView.getProviderId();
308 final BrandingResources brandingRes = mApp.getBrandingResource(providerId);
309 int[] icons = brandingRes.getSmileyIcons();
310 String[] names = brandingRes.getStringArray(
311 BrandingResourceIDs.STRING_ARRAY_SMILEY_NAMES);
312 final String[] texts = brandingRes.getStringArray(
313 BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS);
315 final int N = names.length;
317 List<Map<String, ?>> entries = new ArrayList<Map<String, ?>>();
318 for (int i = 0; i < N; i++) {
319 // We might have different ASCII for the same icon, skip it if
320 // the icon is already added.
321 boolean added = false;
322 for (int j = 0; j < i; j++) {
323 if (icons[i] == icons[j]) {
329 HashMap<String, Object> entry = new HashMap<String, Object>();
331 entry. put("icon", icons[i]);
332 entry. put("name", names[i]);
333 entry.put("text", texts[i]);
339 final SimpleAdapter a = new SimpleAdapter(
342 R.layout.smiley_menu_item,
343 new String[] {"icon", "name", "text"},
344 new int[] {R.id.smiley_icon, R.id.smiley_name, R.id.smiley_text});
345 SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() {
346 public boolean setViewValue(View view, Object data, String textRepresentation) {
347 if (view instanceof ImageView) {
348 Drawable img = brandingRes.getSmileyIcon((Integer)data);
349 ((ImageView)view).setImageDrawable(img);
355 a.setViewBinder(viewBinder);
357 AlertDialog.Builder b = new AlertDialog.Builder(this);
359 b.setTitle(brandingRes.getString(
360 BrandingResourceIDs.STRING_MENU_INSERT_SMILEY));
362 b.setCancelable(true);
363 b.setAdapter(a, new DialogInterface.OnClickListener() {
364 public final void onClick(DialogInterface dialog, int which) {
365 HashMap<String, Object> item = (HashMap<String, Object>) a.getItem(which);
366 mChatView.insertSmiley((String)item.get("text"));
370 mSmileyDialog = b.create();
373 mSmileyDialog.show();
376 private void switchChat(int delta) {
377 Cursor c = getContentResolver().query(Im.Contacts.CONTENT_URI_CHAT_CONTACTS,
378 CHAT_SWITCHER_PROJECTION, null, null, null);
381 final int N = c.getCount();
387 // find current position
388 for (int i = 0; i < N; i++) {
390 long id = c.getLong(CHAT_SWITCHER_ID_COLUMN);
391 if (id == mChatView.getChatId()) {
399 int newPosition = (current + delta) % N;
400 if (newPosition < 0) {
404 c.moveToPosition(newPosition);
406 long providerId = c.getLong(CHAT_SWITCHER_PROVIDER_COLUMN);
407 long accountId = c.getLong(CHAT_SWITCHER_ACCOUNT_COLUMN);
408 String contact = c.getString(CHAT_SWITCHER_USERNAME_COLUMN);
409 long chatId = c.getLong(CHAT_SWITCHER_ID_COLUMN);
410 Intent intent = Dashboard.makeChatIntent(getContentResolver(), providerId, accountId,
413 startActivity(intent);
420 private void startContactPicker() {
421 Uri.Builder builder = Im.Contacts.CONTENT_URI_ONLINE_CONTACTS_BY.buildUpon();
422 ContentUris.appendId(builder, mChatView.getProviderId());
423 ContentUris.appendId(builder, mChatView.getAccountId());
424 Uri data = builder.build();
427 Intent i = new Intent(Intent.ACTION_PICK, data);
428 i.putExtra(ContactsPickerActivity.EXTRA_EXCLUDED_CONTACTS,
429 mChatView.getCurrentChatSession().getPariticipants());
430 startActivityForResult(i, REQUEST_PICK_CONTACTS);
431 } catch (RemoteException e) {
432 mHandler.showServiceErrorAlert();
437 protected void onActivityResult(int requestCode, int resultCode,
439 if (resultCode == RESULT_OK) {
440 if (requestCode == REQUEST_PICK_CONTACTS) {
441 String username = data.getStringExtra(
442 ContactsPickerActivity.EXTRA_RESULT_USERNAME);
444 IChatSession chatSession = mChatView.getCurrentChatSession();
445 if (chatSession.isGroupChatSession()) {
446 chatSession.inviteContact(username);
447 showInvitationHasSent(username);
449 chatSession.convertToGroupChat();
450 new ContactInvitor(chatSession, username).start();
452 } catch (RemoteException e) {
453 mHandler.showServiceErrorAlert();
459 void showInvitationHasSent(String contact) {
460 Toast.makeText(NewChatActivity.this,
461 getString(R.string.invitation_sent_prompt, contact),
462 Toast.LENGTH_SHORT).show();
465 private class ContactInvitor extends ChatListenerAdapter {
466 private final IChatSession mChatSession;
469 public ContactInvitor(IChatSession session, String data) {
470 mChatSession = session;
475 public void onConvertedToGroupChat(IChatSession ses) {
477 final long chatId = mChatSession.getId();
478 mChatSession.inviteContact(mContact);
479 mHandler.post(new Runnable(){
481 mChatView.bindChat(chatId);
482 showInvitationHasSent(mContact);
485 mChatSession.unregisterChatListener(this);
486 } catch (RemoteException e) {
487 mHandler.showServiceErrorAlert();
491 public void start() throws RemoteException {
492 mChatSession.registerChatListener(this);