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