• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.mms.ui;
19 
20 import com.android.mms.R;
21 import com.google.android.mms.util.SqliteWrapper;
22 import com.android.mms.transaction.MessagingNotification;
23 
24 import android.app.Activity;
25 import android.app.AlertDialog;
26 
27 import android.content.AsyncQueryHandler;
28 import android.content.ContentResolver;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.DialogInterface.OnClickListener;
32 import android.database.ContentObserver;
33 import android.database.Cursor;
34 import android.database.sqlite.SQLiteException;
35 import android.net.Uri;
36 import android.os.Bundle;
37 import android.os.Handler;
38 import android.provider.Telephony.Sms;
39 import android.provider.Telephony.Threads;
40 import android.telephony.SmsManager;
41 import android.util.Log;
42 import android.view.ContextMenu;
43 import android.view.Menu;
44 import android.view.MenuItem;
45 import android.view.View;
46 import android.view.Window;
47 import android.widget.AdapterView;
48 import android.widget.ListView;
49 import android.widget.TextView;
50 
51 /**
52  * Displays a list of the SMS messages stored on the ICC.
53  */
54 public class ManageSimMessages extends Activity
55         implements View.OnCreateContextMenuListener {
56     private static final Uri ICC_URI = Uri.parse("content://sms/icc");
57     private static final String TAG = "ManageSimMessages";
58     private static final int MENU_COPY_TO_PHONE_MEMORY = 0;
59     private static final int MENU_DELETE_FROM_SIM = 1;
60     private static final int MENU_VIEW = 2;
61     private static final int OPTION_MENU_DELETE_ALL = 0;
62 
63     private static final int SHOW_LIST = 0;
64     private static final int SHOW_EMPTY = 1;
65     private static final int SHOW_BUSY = 2;
66     private int mState;
67 
68 
69     private ContentResolver mContentResolver;
70     private Cursor mCursor = null;
71     private ListView mSimList;
72     private TextView mMessage;
73     private MessageListAdapter mListAdapter = null;
74     private AsyncQueryHandler mQueryHandler = null;
75 
76     public static final int SIM_FULL_NOTIFICATION_ID = 234;
77 
78     private final ContentObserver simChangeObserver =
79             new ContentObserver(new Handler()) {
80         @Override
81         public void onChange(boolean selfUpdate) {
82             refreshMessageList();
83         }
84     };
85 
86     @Override
onCreate(Bundle icicle)87     protected void onCreate(Bundle icicle) {
88         super.onCreate(icicle);
89         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
90 
91         mContentResolver = getContentResolver();
92         mQueryHandler = new QueryHandler(mContentResolver, this);
93         setContentView(R.layout.sim_list);
94         mSimList = (ListView) findViewById(R.id.messages);
95         mMessage = (TextView) findViewById(R.id.empty_message);
96 
97         init();
98     }
99 
100     @Override
onNewIntent(Intent intent)101     protected void onNewIntent(Intent intent) {
102         setIntent(intent);
103 
104         init();
105     }
106 
init()107     private void init() {
108         MessagingNotification.cancelNotification(getApplicationContext(),
109                 SIM_FULL_NOTIFICATION_ID);
110 
111         updateState(SHOW_BUSY);
112         startQuery();
113     }
114 
115     private class QueryHandler extends AsyncQueryHandler {
116         private final ManageSimMessages mParent;
117 
QueryHandler( ContentResolver contentResolver, ManageSimMessages parent)118         public QueryHandler(
119                 ContentResolver contentResolver, ManageSimMessages parent) {
120             super(contentResolver);
121             mParent = parent;
122         }
123 
124         @Override
onQueryComplete( int token, Object cookie, Cursor cursor)125         protected void onQueryComplete(
126                 int token, Object cookie, Cursor cursor) {
127             mCursor = cursor;
128             if (mCursor != null) {
129                 if (!mCursor.moveToFirst()) {
130                     // Let user know the SIM is empty
131                     updateState(SHOW_EMPTY);
132                 } else if (mListAdapter == null) {
133                     mListAdapter = new MessageListAdapter(
134                             mParent, mCursor, mSimList, false,
135                             Threads.COMMON_THREAD);
136                     mSimList.setAdapter(mListAdapter);
137                     mSimList.setOnCreateContextMenuListener(mParent);
138                     updateState(SHOW_LIST);
139                 } else {
140                     mListAdapter.changeCursor(mCursor);
141                     updateState(SHOW_LIST);
142                 }
143                 startManagingCursor(mCursor);
144                 registerSimChangeObserver();
145             }
146         }
147     }
148 
startQuery()149     private void startQuery() {
150         try {
151             mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
152         } catch (SQLiteException e) {
153             SqliteWrapper.checkSQLiteException(this, e);
154         }
155     }
156 
refreshMessageList()157     private void refreshMessageList() {
158         updateState(SHOW_BUSY);
159         if (mCursor != null) {
160             stopManagingCursor(mCursor);
161             mCursor.close();
162         }
163         startQuery();
164     }
165 
166     @Override
onCreateContextMenu( ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)167     public void onCreateContextMenu(
168             ContextMenu menu, View v,
169             ContextMenu.ContextMenuInfo menuInfo) {
170         menu.add(0, MENU_COPY_TO_PHONE_MEMORY, 0,
171                  R.string.sim_copy_to_phone_memory);
172         menu.add(0, MENU_DELETE_FROM_SIM, 0, R.string.sim_delete);
173 
174         // TODO: Enable this once viewMessage is written.
175         // menu.add(0, MENU_VIEW, 0, R.string.sim_view);
176     }
177 
178     @Override
onContextItemSelected(MenuItem item)179     public boolean onContextItemSelected(MenuItem item) {
180         AdapterView.AdapterContextMenuInfo info;
181         try {
182              info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
183         } catch (ClassCastException exception) {
184             Log.e(TAG, "Bad menuInfo.", exception);
185             return false;
186         }
187 
188         final Cursor cursor = (Cursor) mListAdapter.getItem(info.position);
189 
190         switch (item.getItemId()) {
191             case MENU_COPY_TO_PHONE_MEMORY:
192                 copyToPhoneMemory(cursor);
193                 return true;
194             case MENU_DELETE_FROM_SIM:
195                 confirmDeleteDialog(new OnClickListener() {
196                     public void onClick(DialogInterface dialog, int which) {
197                         updateState(SHOW_BUSY);
198                         deleteFromSim(cursor);
199                     }
200                 }, R.string.confirm_delete_SIM_message);
201                 return true;
202             case MENU_VIEW:
203                 viewMessage(cursor);
204                 return true;
205         }
206         return super.onContextItemSelected(item);
207     }
208 
209     @Override
onResume()210     public void onResume() {
211         super.onResume();
212         registerSimChangeObserver();
213     }
214 
215     @Override
onPause()216     public void onPause() {
217         super.onPause();
218         mContentResolver.unregisterContentObserver(simChangeObserver);
219     }
220 
registerSimChangeObserver()221     private void registerSimChangeObserver() {
222         mContentResolver.registerContentObserver(
223                 ICC_URI, true, simChangeObserver);
224     }
225 
copyToPhoneMemory(Cursor cursor)226     private void copyToPhoneMemory(Cursor cursor) {
227         String address = cursor.getString(
228                 cursor.getColumnIndexOrThrow("address"));
229         String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
230         Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
231 
232         try {
233             if (isIncomingMessage(cursor)) {
234                 Sms.Inbox.addMessage(mContentResolver, address, body, null, date, true);
235             } else {
236                 Sms.Sent.addMessage(mContentResolver, address, body, null, date);
237             }
238         } catch (SQLiteException e) {
239             SqliteWrapper.checkSQLiteException(this, e);
240         }
241     }
242 
isIncomingMessage(Cursor cursor)243     private boolean isIncomingMessage(Cursor cursor) {
244         int messageStatus = cursor.getInt(
245                 cursor.getColumnIndexOrThrow("status"));
246 
247         return (messageStatus == SmsManager.STATUS_ON_ICC_READ) ||
248                (messageStatus == SmsManager.STATUS_ON_ICC_UNREAD);
249     }
250 
deleteFromSim(Cursor cursor)251     private void deleteFromSim(Cursor cursor) {
252         String messageIndexString =
253                 cursor.getString(cursor.getColumnIndexOrThrow("index_on_icc"));
254         Uri simUri = ICC_URI.buildUpon().appendPath(messageIndexString).build();
255 
256         SqliteWrapper.delete(this, mContentResolver, simUri, null, null);
257     }
258 
deleteAllFromSim()259     private void deleteAllFromSim() {
260         Cursor cursor = (Cursor) mListAdapter.getCursor();
261 
262         if (cursor != null) {
263             if (cursor.moveToFirst()) {
264                 int count = cursor.getCount();
265 
266                 for (int i = 0; i < count; ++i) {
267                     deleteFromSim(cursor);
268                     cursor.moveToNext();
269                 }
270             }
271         }
272     }
273 
274     @Override
onPrepareOptionsMenu(Menu menu)275     public boolean onPrepareOptionsMenu(Menu menu) {
276         menu.clear();
277 
278         if ((null != mCursor) && (mCursor.getCount() > 0) && mState == SHOW_LIST) {
279             menu.add(0, OPTION_MENU_DELETE_ALL, 0, R.string.menu_delete_messages).setIcon(
280                     android.R.drawable.ic_menu_delete);
281         }
282 
283         return true;
284     }
285 
286     @Override
onOptionsItemSelected(MenuItem item)287     public boolean onOptionsItemSelected(MenuItem item) {
288         switch (item.getItemId()) {
289             case OPTION_MENU_DELETE_ALL:
290                 confirmDeleteDialog(new OnClickListener() {
291                     public void onClick(DialogInterface dialog, int which) {
292                         updateState(SHOW_BUSY);
293                         deleteAllFromSim();
294                     }
295                 }, R.string.confirm_delete_all_SIM_messages);
296                 break;
297         }
298 
299         return true;
300     }
301 
confirmDeleteDialog(OnClickListener listener, int messageId)302     private void confirmDeleteDialog(OnClickListener listener, int messageId) {
303         AlertDialog.Builder builder = new AlertDialog.Builder(this);
304         builder.setTitle(R.string.confirm_dialog_title);
305         builder.setIcon(android.R.drawable.ic_dialog_alert);
306         builder.setCancelable(true);
307         builder.setPositiveButton(R.string.yes, listener);
308         builder.setNegativeButton(R.string.no, null);
309         builder.setMessage(messageId);
310 
311         builder.show();
312     }
313 
updateState(int state)314     private void updateState(int state) {
315         if (mState == state) {
316             return;
317         }
318 
319         mState = state;
320         switch (state) {
321             case SHOW_LIST:
322                 mSimList.setVisibility(View.VISIBLE);
323                 mMessage.setVisibility(View.GONE);
324                 setTitle(getString(R.string.sim_manage_messages_title));
325                 setProgressBarIndeterminateVisibility(false);
326                 break;
327             case SHOW_EMPTY:
328                 mSimList.setVisibility(View.GONE);
329                 mMessage.setVisibility(View.VISIBLE);
330                 setTitle(getString(R.string.sim_manage_messages_title));
331                 setProgressBarIndeterminateVisibility(false);
332                 break;
333             case SHOW_BUSY:
334                 mSimList.setVisibility(View.GONE);
335                 mMessage.setVisibility(View.GONE);
336                 setTitle(getString(R.string.refreshing));
337                 setProgressBarIndeterminateVisibility(true);
338                 break;
339             default:
340                 Log.e(TAG, "Invalid State");
341         }
342     }
343 
viewMessage(Cursor cursor)344     private void viewMessage(Cursor cursor) {
345         // TODO: Add this.
346     }
347 }
348 
349