OSDN Git Service

auto import from //depot/cupcake/@132589
[android-x86/packages-apps-IM.git] / src / com / android / im / app / NewChatActivity.java
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.Dashboard.OnCancelListener;
28 import com.android.im.app.adapter.ChatListenerAdapter;
29 import com.android.im.plugin.BrandingResourceIDs;
30
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;
53
54 import java.util.ArrayList;
55 import java.util.HashMap;
56 import java.util.List;
57 import java.util.Map;
58
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";
63
64     private static final String[] CHAT_SWITCHER_PROJECTION = {
65             Im.Contacts._ID,
66             Im.Contacts.PROVIDER,
67             Im.Contacts.ACCOUNT,
68             Im.Contacts.USERNAME,
69             Im.Chats.GROUP_CHAT,
70     };
71
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;
77
78     private static final int REQUEST_PICK_CONTACTS = RESULT_FIRST_USER + 1;
79
80     ImApp mApp;
81
82     ChatView mChatView;
83     SimpleAlertHandler mHandler;
84
85     private AlertDialog mSmileyDialog;
86     private Dashboard mDashboard;
87
88     @Override
89     protected void onCreate(Bundle icicle) {
90         super.onCreate(icicle);
91
92         requestWindowFeature(Window.FEATURE_NO_TITLE);
93
94         setContentView(R.layout.chat_view);
95
96         mChatView = (ChatView) findViewById(R.id.chatView);
97         mHandler = mChatView.mHandler;
98
99         final Handler handler = new Handler();
100         mApp= ImApp.getApplication(this);
101         mApp.callWhenServiceConnected(handler, new Runnable() {
102             public void run() {
103                 resolveIntent(getIntent());
104             }
105         });
106     }
107
108     @Override
109     protected void onResume() {
110         super.onResume();
111         mChatView.onResume();
112     }
113
114     @Override
115     protected void onPause() {
116         mChatView.onPause();
117         super.onPause();
118     }
119
120     @Override
121     protected void onNewIntent(Intent intent) {
122         resolveIntent(intent);
123     }
124
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) {
130                 finish();
131             } else {
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
135                 //
136                 //   android.view.WindowManager$BadTokenException: Unable to add window --
137                 //           token null is not valid; is your activity running?
138                 //
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() {
142                     public void run() {
143                         mDashboard = Dashboard.openDashboard(NewChatActivity.this, accountId, null);
144                         mDashboard.setOnCancelListener(new OnCancelListener() {
145                             public void onCancel() {
146                                 finish();
147                             }
148                         });
149                     }
150                 }, 500);
151             }
152             return;
153         }
154
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)) {
159                 finish();
160             } else {
161                 mChatView.bindSubscription(providerId, from);
162             }
163         } else {
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));
170             }
171         }
172     }
173
174     @Override
175     public boolean onCreateOptionsMenu(Menu menu) {
176         MenuInflater inflater = getMenuInflater();
177         inflater.inflate(R.menu.chat_screen_menu, menu);
178
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));
193         return true;
194     }
195
196     @Override
197     public boolean onPrepareOptionsMenu(Menu menu) {
198         super.onPrepareOptionsMenu(menu);
199
200         //XXX hide the invite menu, group chat is not supported by the server.
201         menu.findItem(R.id.menu_invite_contact).setVisible(false);
202
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);
208             }
209         }
210         return true;
211     }
212
213     @Override
214     public boolean onOptionsItemSelected(MenuItem item) {
215         switch (item.getItemId()) {
216             case R.id.menu_view_friend_list:
217                 finish();
218                 showRosterScreen();
219                 return true;
220
221             case R.id.menu_insert_smiley:
222                 showSmileyDialog();
223                 return true;
224
225             case R.id.menu_end_conversation:
226                 mChatView.closeChatSession();
227                 return true;
228
229             case R.id.menu_switch_chats:
230                 Dashboard.openDashboard(this, mChatView.getAccountId(),
231                         mChatView.getUserName());
232                 return true;
233
234             case R.id.menu_invite_contact:
235                 startContactPicker();
236                 return true;
237
238             case R.id.menu_view_profile:
239                 mChatView.viewProfile();
240                 return true;
241
242             case R.id.menu_block_contact:
243                 mChatView.blockContact();
244                 return true;
245
246             case R.id.menu_prev_chat:
247                 switchChat(-1);
248                 return true;
249
250             case R.id.menu_next_chat:
251                 switchChat(1);
252                 return true;
253
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,
266                         null,
267                         null,
268                         null,
269                         null);
270                 int slot = item.getAlphabeticShortcut() - '0';
271                 if (Dashboard.quickSwitch(this, c, slot)) {
272                     finish();
273                 }
274                 c.close();
275                 return true;
276         }
277
278         return super.onOptionsItemSelected(item);
279     }
280
281     @Override
282     public boolean dispatchKeyEvent(KeyEvent event) {
283         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
284                 && event.getAction() == KeyEvent.ACTION_DOWN) {
285             mChatView.closeChatSessionIfInactive();
286         }
287         return super.dispatchKeyEvent(event);
288     }
289
290     /**
291      * Check whether we are asked to open Dashboard on startup.
292      */
293     private boolean requireOpenDashboardOnStart(Intent intent) {
294         return intent.getBooleanExtra(EXTRA_INTENT_SHOW_MULTIPLE, false);
295     }
296
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);
302     }
303
304     private void showSmileyDialog() {
305         if (mSmileyDialog == null) {
306             long providerId = mChatView.getProviderId();
307
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);
314
315             final int N = names.length;
316
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]) {
324                         added = true;
325                         break;
326                     }
327                 }
328                 if (!added) {
329                     HashMap<String, Object> entry = new HashMap<String, Object>();
330
331                     entry. put("icon", icons[i]);
332                     entry. put("name", names[i]);
333                     entry.put("text", texts[i]);
334
335                     entries.add(entry);
336                 }
337             }
338
339             final SimpleAdapter a = new SimpleAdapter(
340                     this,
341                     entries,
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);
350                         return true;
351                     }
352                     return false;
353                 }
354             };
355             a.setViewBinder(viewBinder);
356
357             AlertDialog.Builder b = new AlertDialog.Builder(this);
358
359             b.setTitle(brandingRes.getString(
360                     BrandingResourceIDs.STRING_MENU_INSERT_SMILEY));
361
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"));
367                 }
368             });
369
370             mSmileyDialog = b.create();
371         }
372
373         mSmileyDialog.show();
374     }
375
376     private void switchChat(int delta) {
377         Cursor c = getContentResolver().query(Im.Contacts.CONTENT_URI_CHAT_CONTACTS,
378                 CHAT_SWITCHER_PROJECTION, null, null, null);
379
380         try {
381             final int N = c.getCount();
382             if (N <= 1) {
383                 return;
384             }
385
386             int current = -1;
387             // find current position
388             for (int i = 0; i < N; i++) {
389                 c.moveToNext();
390                 long id = c.getLong(CHAT_SWITCHER_ID_COLUMN);
391                 if (id == mChatView.getChatId()) {
392                     current = i;
393                 }
394             }
395             if (current == -1) {
396                 return;
397             }
398
399             int newPosition = (current + delta) % N;
400             if (newPosition < 0) {
401                 newPosition += N;
402             }
403
404             c.moveToPosition(newPosition);
405
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,
411                     contact, chatId);
412
413             startActivity(intent);
414             finish();
415         } finally {
416             c.close();
417         }
418     }
419
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();
425
426         try {
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();
433         }
434     }
435
436     @Override
437     protected void onActivityResult(int requestCode, int resultCode,
438             Intent data) {
439         if (resultCode == RESULT_OK) {
440             if (requestCode == REQUEST_PICK_CONTACTS) {
441                 String username = data.getStringExtra(
442                         ContactsPickerActivity.EXTRA_RESULT_USERNAME);
443                 try {
444                     IChatSession chatSession = mChatView.getCurrentChatSession();
445                     if (chatSession.isGroupChatSession()) {
446                         chatSession.inviteContact(username);
447                         showInvitationHasSent(username);
448                     } else {
449                         chatSession.convertToGroupChat();
450                         new ContactInvitor(chatSession, username).start();
451                     }
452                 } catch (RemoteException e) {
453                     mHandler.showServiceErrorAlert();
454                 }
455             }
456         }
457     }
458
459     void showInvitationHasSent(String contact) {
460         Toast.makeText(NewChatActivity.this,
461                 getString(R.string.invitation_sent_prompt, contact),
462                 Toast.LENGTH_SHORT).show();
463     }
464
465     private class ContactInvitor extends ChatListenerAdapter {
466         private final IChatSession mChatSession;
467         String mContact;
468
469         public ContactInvitor(IChatSession session, String data) {
470             mChatSession = session;
471             mContact = data;
472         }
473
474         @Override
475         public void onConvertedToGroupChat(IChatSession ses) {
476             try {
477                 final long chatId = mChatSession.getId();
478                 mChatSession.inviteContact(mContact);
479                 mHandler.post(new Runnable(){
480                     public void run() {
481                         mChatView.bindChat(chatId);
482                         showInvitationHasSent(mContact);
483                     }
484                 });
485                 mChatSession.unregisterChatListener(this);
486             } catch (RemoteException e) {
487                 mHandler.showServiceErrorAlert();
488             }
489         }
490
491         public void start() throws RemoteException {
492             mChatSession.registerChatListener(this);
493         }
494     }
495 }