Home | History | Annotate | Download | only in ui
      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
     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
    100     protected void onNewIntent(Intent intent) {
    101         setIntent(intent);
    102 
    103         init();
    104     }
    105 
    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 
    117         public QueryHandler(
    118                 ContentResolver contentResolver, ManageSimMessages parent) {
    119             super(contentResolver);
    120             mParent = parent;
    121         }
    122 
    123         @Override
    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                 registerSimChangeObserver();
    147             } else {
    148                 // Let user know the SIM is empty
    149                 updateState(SHOW_EMPTY);
    150             }
    151         }
    152     }
    153 
    154     private void startQuery() {
    155         try {
    156             mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
    157         } catch (SQLiteException e) {
    158             SqliteWrapper.checkSQLiteException(this, e);
    159         }
    160     }
    161 
    162     private void refreshMessageList() {
    163         updateState(SHOW_BUSY);
    164         if (mCursor != null) {
    165             stopManagingCursor(mCursor);
    166             mCursor.close();
    167         }
    168         startQuery();
    169     }
    170 
    171     @Override
    172     public void onCreateContextMenu(
    173             ContextMenu menu, View v,
    174             ContextMenu.ContextMenuInfo menuInfo) {
    175         menu.add(0, MENU_COPY_TO_PHONE_MEMORY, 0,
    176                  R.string.sim_copy_to_phone_memory);
    177         menu.add(0, MENU_DELETE_FROM_SIM, 0, R.string.sim_delete);
    178 
    179         // TODO: Enable this once viewMessage is written.
    180         // menu.add(0, MENU_VIEW, 0, R.string.sim_view);
    181     }
    182 
    183     @Override
    184     public boolean onContextItemSelected(MenuItem item) {
    185         AdapterView.AdapterContextMenuInfo info;
    186         try {
    187              info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    188         } catch (ClassCastException exception) {
    189             Log.e(TAG, "Bad menuInfo.", exception);
    190             return false;
    191         }
    192 
    193         final Cursor cursor = (Cursor) mListAdapter.getItem(info.position);
    194 
    195         switch (item.getItemId()) {
    196             case MENU_COPY_TO_PHONE_MEMORY:
    197                 copyToPhoneMemory(cursor);
    198                 return true;
    199             case MENU_DELETE_FROM_SIM:
    200                 confirmDeleteDialog(new OnClickListener() {
    201                     public void onClick(DialogInterface dialog, int which) {
    202                         updateState(SHOW_BUSY);
    203                         deleteFromSim(cursor);
    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
    215     public void onResume() {
    216         super.onResume();
    217         registerSimChangeObserver();
    218     }
    219 
    220     @Override
    221     public void onPause() {
    222         super.onPause();
    223         mContentResolver.unregisterContentObserver(simChangeObserver);
    224     }
    225 
    226     private void registerSimChangeObserver() {
    227         mContentResolver.registerContentObserver(
    228                 ICC_URI, true, simChangeObserver);
    229     }
    230 
    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 
    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 
    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 
    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
    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
    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                     }
    300                 }, R.string.confirm_delete_all_SIM_messages);
    301                 break;
    302         }
    303 
    304         return true;
    305     }
    306 
    307     private void confirmDeleteDialog(OnClickListener listener, int messageId) {
    308         AlertDialog.Builder builder = new AlertDialog.Builder(this);
    309         builder.setTitle(R.string.confirm_dialog_title);
    310         builder.setIcon(android.R.drawable.ic_dialog_alert);
    311         builder.setCancelable(true);
    312         builder.setPositiveButton(R.string.yes, listener);
    313         builder.setNegativeButton(R.string.no, null);
    314         builder.setMessage(messageId);
    315 
    316         builder.show();
    317     }
    318 
    319     private void updateState(int state) {
    320         if (mState == state) {
    321             return;
    322         }
    323 
    324         mState = state;
    325         switch (state) {
    326             case SHOW_LIST:
    327                 mSimList.setVisibility(View.VISIBLE);
    328                 mMessage.setVisibility(View.GONE);
    329                 setTitle(getString(R.string.sim_manage_messages_title));
    330                 setProgressBarIndeterminateVisibility(false);
    331                 break;
    332             case SHOW_EMPTY:
    333                 mSimList.setVisibility(View.GONE);
    334                 mMessage.setVisibility(View.VISIBLE);
    335                 setTitle(getString(R.string.sim_manage_messages_title));
    336                 setProgressBarIndeterminateVisibility(false);
    337                 break;
    338             case SHOW_BUSY:
    339                 mSimList.setVisibility(View.GONE);
    340                 mMessage.setVisibility(View.GONE);
    341                 setTitle(getString(R.string.refreshing));
    342                 setProgressBarIndeterminateVisibility(true);
    343                 break;
    344             default:
    345                 Log.e(TAG, "Invalid State");
    346         }
    347     }
    348 
    349     private void viewMessage(Cursor cursor) {
    350         // TODO: Add this.
    351     }
    352 }
    353 
    354