• 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 android.app.ActionBar;
21 import android.app.Activity;
22 import android.app.AlertDialog;
23 import android.content.AsyncQueryHandler;
24 import android.content.ContentResolver;
25 import android.content.DialogInterface;
26 import android.content.DialogInterface.OnClickListener;
27 import android.content.Intent;
28 import android.database.ContentObserver;
29 import android.database.Cursor;
30 import android.database.sqlite.SQLiteException;
31 import android.database.sqlite.SqliteWrapper;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.provider.Telephony.Sms;
36 import android.telephony.SmsManager;
37 import android.util.Log;
38 import android.view.ContextMenu;
39 import android.view.Menu;
40 import android.view.MenuItem;
41 import android.view.View;
42 import android.view.Window;
43 import android.widget.AdapterView;
44 import android.widget.ListView;
45 import android.widget.TextView;
46 
47 import com.android.mms.R;
48 import com.android.mms.transaction.MessagingNotification;
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         ActionBar actionBar = getActionBar();
97         actionBar.setDisplayHomeAsUpEnabled(true);
98 
99         init();
100     }
101 
102     @Override
onNewIntent(Intent intent)103     protected void onNewIntent(Intent intent) {
104         setIntent(intent);
105 
106         init();
107     }
108 
init()109     private void init() {
110         MessagingNotification.cancelNotification(getApplicationContext(),
111                 SIM_FULL_NOTIFICATION_ID);
112 
113         updateState(SHOW_BUSY);
114         startQuery();
115     }
116 
117     private class QueryHandler extends AsyncQueryHandler {
118         private final ManageSimMessages mParent;
119 
QueryHandler( ContentResolver contentResolver, ManageSimMessages parent)120         public QueryHandler(
121                 ContentResolver contentResolver, ManageSimMessages parent) {
122             super(contentResolver);
123             mParent = parent;
124         }
125 
126         @Override
onQueryComplete( int token, Object cookie, Cursor cursor)127         protected void onQueryComplete(
128                 int token, Object cookie, Cursor cursor) {
129             mCursor = cursor;
130             if (mCursor != null) {
131                 if (!mCursor.moveToFirst()) {
132                     // Let user know the SIM is empty
133                     updateState(SHOW_EMPTY);
134                 } else if (mListAdapter == null) {
135                     // Note that the MessageListAdapter doesn't support auto-requeries. If we
136                     // want to respond to changes we'd need to add a line like:
137                     //   mListAdapter.setOnDataSetChangedListener(mDataSetChangedListener);
138                     // See ComposeMessageActivity for an example.
139                     mListAdapter = new MessageListAdapter(
140                             mParent, mCursor, mSimList, false, null);
141                     mSimList.setAdapter(mListAdapter);
142                     mSimList.setOnCreateContextMenuListener(mParent);
143                     updateState(SHOW_LIST);
144                 } else {
145                     mListAdapter.changeCursor(mCursor);
146                     updateState(SHOW_LIST);
147                 }
148                 startManagingCursor(mCursor);
149             } else {
150                 // Let user know the SIM is empty
151                 updateState(SHOW_EMPTY);
152             }
153         }
154     }
155 
startQuery()156     private void startQuery() {
157         try {
158             mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
159         } catch (SQLiteException e) {
160             SqliteWrapper.checkSQLiteException(this, e);
161         }
162     }
163 
refreshMessageList()164     private void refreshMessageList() {
165         updateState(SHOW_BUSY);
166         if (mCursor != null) {
167             stopManagingCursor(mCursor);
168             mCursor.close();
169         }
170         startQuery();
171     }
172 
173     @Override
onCreateContextMenu( ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)174     public void onCreateContextMenu(
175             ContextMenu menu, View v,
176             ContextMenu.ContextMenuInfo menuInfo) {
177         menu.add(0, MENU_COPY_TO_PHONE_MEMORY, 0,
178                  R.string.sim_copy_to_phone_memory);
179         menu.add(0, MENU_DELETE_FROM_SIM, 0, R.string.sim_delete);
180 
181         // TODO: Enable this once viewMessage is written.
182         // menu.add(0, MENU_VIEW, 0, R.string.sim_view);
183     }
184 
185     @Override
onContextItemSelected(MenuItem item)186     public boolean onContextItemSelected(MenuItem item) {
187         AdapterView.AdapterContextMenuInfo info;
188         try {
189              info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
190         } catch (ClassCastException exception) {
191             Log.e(TAG, "Bad menuInfo.", exception);
192             return false;
193         }
194 
195         final Cursor cursor = (Cursor) mListAdapter.getItem(info.position);
196 
197         switch (item.getItemId()) {
198             case MENU_COPY_TO_PHONE_MEMORY:
199                 copyToPhoneMemory(cursor);
200                 return true;
201             case MENU_DELETE_FROM_SIM:
202                 confirmDeleteDialog(new OnClickListener() {
203                     public void onClick(DialogInterface dialog, int which) {
204                         updateState(SHOW_BUSY);
205                         deleteFromSim(cursor);
206                         dialog.dismiss();
207                     }
208                 }, R.string.confirm_delete_SIM_message);
209                 return true;
210             case MENU_VIEW:
211                 viewMessage(cursor);
212                 return true;
213         }
214         return super.onContextItemSelected(item);
215     }
216 
217     @Override
onResume()218     public void onResume() {
219         super.onResume();
220         registerSimChangeObserver();
221     }
222 
223     @Override
onPause()224     public void onPause() {
225         super.onPause();
226         mContentResolver.unregisterContentObserver(simChangeObserver);
227     }
228 
registerSimChangeObserver()229     private void registerSimChangeObserver() {
230         mContentResolver.registerContentObserver(
231                 ICC_URI, true, simChangeObserver);
232     }
233 
copyToPhoneMemory(Cursor cursor)234     private void copyToPhoneMemory(Cursor cursor) {
235         String address = cursor.getString(
236                 cursor.getColumnIndexOrThrow("address"));
237         String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
238         Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
239 
240         try {
241             if (isIncomingMessage(cursor)) {
242                 Sms.Inbox.addMessage(mContentResolver, address, body, null, date, true /* read */);
243             } else {
244                 Sms.Sent.addMessage(mContentResolver, address, body, null, date);
245             }
246         } catch (SQLiteException e) {
247             SqliteWrapper.checkSQLiteException(this, e);
248         }
249     }
250 
isIncomingMessage(Cursor cursor)251     private boolean isIncomingMessage(Cursor cursor) {
252         int messageStatus = cursor.getInt(
253                 cursor.getColumnIndexOrThrow("status"));
254 
255         return (messageStatus == SmsManager.STATUS_ON_ICC_READ) ||
256                (messageStatus == SmsManager.STATUS_ON_ICC_UNREAD);
257     }
258 
deleteFromSim(Cursor cursor)259     private void deleteFromSim(Cursor cursor) {
260         String messageIndexString =
261                 cursor.getString(cursor.getColumnIndexOrThrow("index_on_icc"));
262         Uri simUri = ICC_URI.buildUpon().appendPath(messageIndexString).build();
263 
264         SqliteWrapper.delete(this, mContentResolver, simUri, null, null);
265     }
266 
deleteAllFromSim()267     private void deleteAllFromSim() {
268         Cursor cursor = (Cursor) mListAdapter.getCursor();
269 
270         if (cursor != null) {
271             if (cursor.moveToFirst()) {
272                 int count = cursor.getCount();
273 
274                 for (int i = 0; i < count; ++i) {
275                     deleteFromSim(cursor);
276                     cursor.moveToNext();
277                 }
278             }
279         }
280     }
281 
282     @Override
onPrepareOptionsMenu(Menu menu)283     public boolean onPrepareOptionsMenu(Menu menu) {
284         menu.clear();
285 
286         if (mState == SHOW_LIST && (null != mCursor) && (mCursor.getCount() > 0)) {
287             menu.add(0, OPTION_MENU_DELETE_ALL, 0, R.string.menu_delete_messages).setIcon(
288                     android.R.drawable.ic_menu_delete);
289         }
290 
291         return true;
292     }
293 
294     @Override
onOptionsItemSelected(MenuItem item)295     public boolean onOptionsItemSelected(MenuItem item) {
296         switch (item.getItemId()) {
297             case OPTION_MENU_DELETE_ALL:
298                 confirmDeleteDialog(new OnClickListener() {
299                     public void onClick(DialogInterface dialog, int which) {
300                         updateState(SHOW_BUSY);
301                         deleteAllFromSim();
302                         dialog.dismiss();
303                     }
304                 }, R.string.confirm_delete_all_SIM_messages);
305                 break;
306 
307             case android.R.id.home:
308                 // The user clicked on the Messaging icon in the action bar. Take them back from
309                 // wherever they came from
310                 finish();
311                 break;
312         }
313 
314         return true;
315     }
316 
confirmDeleteDialog(OnClickListener listener, int messageId)317     private void confirmDeleteDialog(OnClickListener listener, int messageId) {
318         AlertDialog.Builder builder = new AlertDialog.Builder(this);
319         builder.setTitle(R.string.confirm_dialog_title);
320         builder.setIconAttribute(android.R.attr.alertDialogIcon);
321         builder.setCancelable(true);
322         builder.setPositiveButton(R.string.yes, listener);
323         builder.setNegativeButton(R.string.no, null);
324         builder.setMessage(messageId);
325 
326         builder.show();
327     }
328 
updateState(int state)329     private void updateState(int state) {
330         if (mState == state) {
331             return;
332         }
333 
334         mState = state;
335         switch (state) {
336             case SHOW_LIST:
337                 mSimList.setVisibility(View.VISIBLE);
338                 mMessage.setVisibility(View.GONE);
339                 setTitle(getString(R.string.sim_manage_messages_title));
340                 setProgressBarIndeterminateVisibility(false);
341                 mSimList.requestFocus();
342                 break;
343             case SHOW_EMPTY:
344                 mSimList.setVisibility(View.GONE);
345                 mMessage.setVisibility(View.VISIBLE);
346                 setTitle(getString(R.string.sim_manage_messages_title));
347                 setProgressBarIndeterminateVisibility(false);
348                 break;
349             case SHOW_BUSY:
350                 mSimList.setVisibility(View.GONE);
351                 mMessage.setVisibility(View.GONE);
352                 setTitle(getString(R.string.refreshing));
353                 setProgressBarIndeterminateVisibility(true);
354                 break;
355             default:
356                 Log.e(TAG, "Invalid State");
357         }
358     }
359 
viewMessage(Cursor cursor)360     private void viewMessage(Cursor cursor) {
361         // TODO: Add this.
362     }
363 }
364 
365