• 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 android.database.sqlite.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                     // Note that the MessageListAdapter doesn't support auto-requeries. If we
133                     // want to respond to changes we'd need to add a line like:
134                     //   mListAdapter.setOnDataSetChangedListener(mDataSetChangedListener);
135                     // See ComposeMessageActivity for an example.
136                     mListAdapter = new MessageListAdapter(
137                             mParent, mCursor, mSimList, false, null);
138                     mSimList.setAdapter(mListAdapter);
139                     mSimList.setOnCreateContextMenuListener(mParent);
140                     updateState(SHOW_LIST);
141                 } else {
142                     mListAdapter.changeCursor(mCursor);
143                     updateState(SHOW_LIST);
144                 }
145                 startManagingCursor(mCursor);
146             } else {
147                 // Let user know the SIM is empty
148                 updateState(SHOW_EMPTY);
149             }
150         }
151     }
152 
startQuery()153     private void startQuery() {
154         try {
155             mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
156         } catch (SQLiteException e) {
157             SqliteWrapper.checkSQLiteException(this, e);
158         }
159     }
160 
refreshMessageList()161     private void refreshMessageList() {
162         updateState(SHOW_BUSY);
163         if (mCursor != null) {
164             stopManagingCursor(mCursor);
165             mCursor.close();
166         }
167         startQuery();
168     }
169 
170     @Override
onCreateContextMenu( ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)171     public void onCreateContextMenu(
172             ContextMenu menu, View v,
173             ContextMenu.ContextMenuInfo menuInfo) {
174         menu.add(0, MENU_COPY_TO_PHONE_MEMORY, 0,
175                  R.string.sim_copy_to_phone_memory);
176         menu.add(0, MENU_DELETE_FROM_SIM, 0, R.string.sim_delete);
177 
178         // TODO: Enable this once viewMessage is written.
179         // menu.add(0, MENU_VIEW, 0, R.string.sim_view);
180     }
181 
182     @Override
onContextItemSelected(MenuItem item)183     public boolean onContextItemSelected(MenuItem item) {
184         AdapterView.AdapterContextMenuInfo info;
185         try {
186              info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
187         } catch (ClassCastException exception) {
188             Log.e(TAG, "Bad menuInfo.", exception);
189             return false;
190         }
191 
192         final Cursor cursor = (Cursor) mListAdapter.getItem(info.position);
193 
194         switch (item.getItemId()) {
195             case MENU_COPY_TO_PHONE_MEMORY:
196                 copyToPhoneMemory(cursor);
197                 return true;
198             case MENU_DELETE_FROM_SIM:
199                 confirmDeleteDialog(new OnClickListener() {
200                     public void onClick(DialogInterface dialog, int which) {
201                         updateState(SHOW_BUSY);
202                         deleteFromSim(cursor);
203                         dialog.dismiss();
204                     }
205                 }, R.string.confirm_delete_SIM_message);
206                 return true;
207             case MENU_VIEW:
208                 viewMessage(cursor);
209                 return true;
210         }
211         return super.onContextItemSelected(item);
212     }
213 
214     @Override
onResume()215     public void onResume() {
216         super.onResume();
217         registerSimChangeObserver();
218     }
219 
220     @Override
onPause()221     public void onPause() {
222         super.onPause();
223         mContentResolver.unregisterContentObserver(simChangeObserver);
224     }
225 
registerSimChangeObserver()226     private void registerSimChangeObserver() {
227         mContentResolver.registerContentObserver(
228                 ICC_URI, true, simChangeObserver);
229     }
230 
copyToPhoneMemory(Cursor cursor)231     private void copyToPhoneMemory(Cursor cursor) {
232         String address = cursor.getString(
233                 cursor.getColumnIndexOrThrow("address"));
234         String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
235         Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
236 
237         try {
238             if (isIncomingMessage(cursor)) {
239                 Sms.Inbox.addMessage(mContentResolver, address, body, null, date, true /* read */);
240             } else {
241                 Sms.Sent.addMessage(mContentResolver, address, body, null, date);
242             }
243         } catch (SQLiteException e) {
244             SqliteWrapper.checkSQLiteException(this, e);
245         }
246     }
247 
isIncomingMessage(Cursor cursor)248     private boolean isIncomingMessage(Cursor cursor) {
249         int messageStatus = cursor.getInt(
250                 cursor.getColumnIndexOrThrow("status"));
251 
252         return (messageStatus == SmsManager.STATUS_ON_ICC_READ) ||
253                (messageStatus == SmsManager.STATUS_ON_ICC_UNREAD);
254     }
255 
deleteFromSim(Cursor cursor)256     private void deleteFromSim(Cursor cursor) {
257         String messageIndexString =
258                 cursor.getString(cursor.getColumnIndexOrThrow("index_on_icc"));
259         Uri simUri = ICC_URI.buildUpon().appendPath(messageIndexString).build();
260 
261         SqliteWrapper.delete(this, mContentResolver, simUri, null, null);
262     }
263 
deleteAllFromSim()264     private void deleteAllFromSim() {
265         Cursor cursor = (Cursor) mListAdapter.getCursor();
266 
267         if (cursor != null) {
268             if (cursor.moveToFirst()) {
269                 int count = cursor.getCount();
270 
271                 for (int i = 0; i < count; ++i) {
272                     deleteFromSim(cursor);
273                     cursor.moveToNext();
274                 }
275             }
276         }
277     }
278 
279     @Override
onPrepareOptionsMenu(Menu menu)280     public boolean onPrepareOptionsMenu(Menu menu) {
281         menu.clear();
282 
283         if ((null != mCursor) && (mCursor.getCount() > 0) && mState == SHOW_LIST) {
284             menu.add(0, OPTION_MENU_DELETE_ALL, 0, R.string.menu_delete_messages).setIcon(
285                     android.R.drawable.ic_menu_delete);
286         }
287 
288         return true;
289     }
290 
291     @Override
onOptionsItemSelected(MenuItem item)292     public boolean onOptionsItemSelected(MenuItem item) {
293         switch (item.getItemId()) {
294             case OPTION_MENU_DELETE_ALL:
295                 confirmDeleteDialog(new OnClickListener() {
296                     public void onClick(DialogInterface dialog, int which) {
297                         updateState(SHOW_BUSY);
298                         deleteAllFromSim();
299                         dialog.dismiss();
300                     }
301                 }, R.string.confirm_delete_all_SIM_messages);
302                 break;
303         }
304 
305         return true;
306     }
307 
confirmDeleteDialog(OnClickListener listener, int messageId)308     private void confirmDeleteDialog(OnClickListener listener, int messageId) {
309         AlertDialog.Builder builder = new AlertDialog.Builder(this);
310         builder.setTitle(R.string.confirm_dialog_title);
311         builder.setIcon(android.R.drawable.ic_dialog_alert);
312         builder.setCancelable(true);
313         builder.setPositiveButton(R.string.yes, listener);
314         builder.setNegativeButton(R.string.no, null);
315         builder.setMessage(messageId);
316 
317         builder.show();
318     }
319 
updateState(int state)320     private void updateState(int state) {
321         if (mState == state) {
322             return;
323         }
324 
325         mState = state;
326         switch (state) {
327             case SHOW_LIST:
328                 mSimList.setVisibility(View.VISIBLE);
329                 mMessage.setVisibility(View.GONE);
330                 setTitle(getString(R.string.sim_manage_messages_title));
331                 setProgressBarIndeterminateVisibility(false);
332                 mSimList.requestFocus();
333                 break;
334             case SHOW_EMPTY:
335                 mSimList.setVisibility(View.GONE);
336                 mMessage.setVisibility(View.VISIBLE);
337                 setTitle(getString(R.string.sim_manage_messages_title));
338                 setProgressBarIndeterminateVisibility(false);
339                 break;
340             case SHOW_BUSY:
341                 mSimList.setVisibility(View.GONE);
342                 mMessage.setVisibility(View.GONE);
343                 setTitle(getString(R.string.refreshing));
344                 setProgressBarIndeterminateVisibility(true);
345                 break;
346             default:
347                 Log.e(TAG, "Invalid State");
348         }
349     }
350 
viewMessage(Cursor cursor)351     private void viewMessage(Cursor cursor) {
352         // TODO: Add this.
353     }
354 }
355 
356