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 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
     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
    103     protected void onNewIntent(Intent intent) {
    104         setIntent(intent);
    105 
    106         init();
    107     }
    108 
    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 
    120         public QueryHandler(
    121                 ContentResolver contentResolver, ManageSimMessages parent) {
    122             super(contentResolver);
    123             mParent = parent;
    124         }
    125 
    126         @Override
    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             // Show option menu when query complete.
    154             invalidateOptionsMenu();
    155         }
    156     }
    157 
    158     private void startQuery() {
    159         try {
    160             mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
    161         } catch (SQLiteException e) {
    162             SqliteWrapper.checkSQLiteException(this, e);
    163         }
    164     }
    165 
    166     private void refreshMessageList() {
    167         updateState(SHOW_BUSY);
    168         if (mCursor != null) {
    169             stopManagingCursor(mCursor);
    170             mCursor.close();
    171         }
    172         startQuery();
    173     }
    174 
    175     @Override
    176     public void onCreateContextMenu(
    177             ContextMenu menu, View v,
    178             ContextMenu.ContextMenuInfo menuInfo) {
    179         menu.add(0, MENU_COPY_TO_PHONE_MEMORY, 0,
    180                  R.string.sim_copy_to_phone_memory);
    181         menu.add(0, MENU_DELETE_FROM_SIM, 0, R.string.sim_delete);
    182 
    183         // TODO: Enable this once viewMessage is written.
    184         // menu.add(0, MENU_VIEW, 0, R.string.sim_view);
    185     }
    186 
    187     @Override
    188     public boolean onContextItemSelected(MenuItem item) {
    189         AdapterView.AdapterContextMenuInfo info;
    190         try {
    191              info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    192         } catch (ClassCastException exception) {
    193             Log.e(TAG, "Bad menuInfo.", exception);
    194             return false;
    195         }
    196 
    197         final Cursor cursor = (Cursor) mListAdapter.getItem(info.position);
    198 
    199         switch (item.getItemId()) {
    200             case MENU_COPY_TO_PHONE_MEMORY:
    201                 copyToPhoneMemory(cursor);
    202                 return true;
    203             case MENU_DELETE_FROM_SIM:
    204                 confirmDeleteDialog(new OnClickListener() {
    205                     public void onClick(DialogInterface dialog, int which) {
    206                         updateState(SHOW_BUSY);
    207                         deleteFromSim(cursor);
    208                         dialog.dismiss();
    209                     }
    210                 }, R.string.confirm_delete_SIM_message);
    211                 return true;
    212             case MENU_VIEW:
    213                 viewMessage(cursor);
    214                 return true;
    215         }
    216         return super.onContextItemSelected(item);
    217     }
    218 
    219     @Override
    220     public void onResume() {
    221         super.onResume();
    222         registerSimChangeObserver();
    223     }
    224 
    225     @Override
    226     public void onPause() {
    227         super.onPause();
    228         mContentResolver.unregisterContentObserver(simChangeObserver);
    229     }
    230 
    231     private void registerSimChangeObserver() {
    232         mContentResolver.registerContentObserver(
    233                 ICC_URI, true, simChangeObserver);
    234     }
    235 
    236     private void copyToPhoneMemory(Cursor cursor) {
    237         String address = cursor.getString(
    238                 cursor.getColumnIndexOrThrow("address"));
    239         String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
    240         Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
    241 
    242         try {
    243             if (isIncomingMessage(cursor)) {
    244                 Sms.Inbox.addMessage(mContentResolver, address, body, null, date, true /* read */);
    245             } else {
    246                 Sms.Sent.addMessage(mContentResolver, address, body, null, date);
    247             }
    248         } catch (SQLiteException e) {
    249             SqliteWrapper.checkSQLiteException(this, e);
    250         }
    251     }
    252 
    253     private boolean isIncomingMessage(Cursor cursor) {
    254         int messageStatus = cursor.getInt(
    255                 cursor.getColumnIndexOrThrow("status"));
    256 
    257         return (messageStatus == SmsManager.STATUS_ON_ICC_READ) ||
    258                (messageStatus == SmsManager.STATUS_ON_ICC_UNREAD);
    259     }
    260 
    261     private void deleteFromSim(Cursor cursor) {
    262         String messageIndexString =
    263                 cursor.getString(cursor.getColumnIndexOrThrow("index_on_icc"));
    264         Uri simUri = ICC_URI.buildUpon().appendPath(messageIndexString).build();
    265 
    266         SqliteWrapper.delete(this, mContentResolver, simUri, null, null);
    267     }
    268 
    269     private void deleteAllFromSim() {
    270         Cursor cursor = (Cursor) mListAdapter.getCursor();
    271 
    272         if (cursor != null) {
    273             if (cursor.moveToFirst()) {
    274                 int count = cursor.getCount();
    275 
    276                 for (int i = 0; i < count; ++i) {
    277                     deleteFromSim(cursor);
    278                     cursor.moveToNext();
    279                 }
    280             }
    281         }
    282     }
    283 
    284     @Override
    285     public boolean onPrepareOptionsMenu(Menu menu) {
    286         menu.clear();
    287 
    288         if (mState == SHOW_LIST && (null != mCursor) && (mCursor.getCount() > 0)) {
    289             menu.add(0, OPTION_MENU_DELETE_ALL, 0, R.string.menu_delete_messages).setIcon(
    290                     android.R.drawable.ic_menu_delete);
    291         }
    292 
    293         return true;
    294     }
    295 
    296     @Override
    297     public boolean onOptionsItemSelected(MenuItem item) {
    298         switch (item.getItemId()) {
    299             case OPTION_MENU_DELETE_ALL:
    300                 confirmDeleteDialog(new OnClickListener() {
    301                     public void onClick(DialogInterface dialog, int which) {
    302                         updateState(SHOW_BUSY);
    303                         deleteAllFromSim();
    304                         dialog.dismiss();
    305                     }
    306                 }, R.string.confirm_delete_all_SIM_messages);
    307                 break;
    308 
    309             case android.R.id.home:
    310                 // The user clicked on the Messaging icon in the action bar. Take them back from
    311                 // wherever they came from
    312                 finish();
    313                 break;
    314         }
    315 
    316         return true;
    317     }
    318 
    319     private void confirmDeleteDialog(OnClickListener listener, int messageId) {
    320         AlertDialog.Builder builder = new AlertDialog.Builder(this);
    321         builder.setTitle(R.string.confirm_dialog_title);
    322         builder.setIconAttribute(android.R.attr.alertDialogIcon);
    323         builder.setCancelable(true);
    324         builder.setPositiveButton(R.string.yes, listener);
    325         builder.setNegativeButton(R.string.no, null);
    326         builder.setMessage(messageId);
    327 
    328         builder.show();
    329     }
    330 
    331     private void updateState(int state) {
    332         if (mState == state) {
    333             return;
    334         }
    335 
    336         mState = state;
    337         switch (state) {
    338             case SHOW_LIST:
    339                 mSimList.setVisibility(View.VISIBLE);
    340                 mMessage.setVisibility(View.GONE);
    341                 setTitle(getString(R.string.sim_manage_messages_title));
    342                 setProgressBarIndeterminateVisibility(false);
    343                 mSimList.requestFocus();
    344                 break;
    345             case SHOW_EMPTY:
    346                 mSimList.setVisibility(View.GONE);
    347                 mMessage.setVisibility(View.VISIBLE);
    348                 setTitle(getString(R.string.sim_manage_messages_title));
    349                 setProgressBarIndeterminateVisibility(false);
    350                 break;
    351             case SHOW_BUSY:
    352                 mSimList.setVisibility(View.GONE);
    353                 mMessage.setVisibility(View.GONE);
    354                 setTitle(getString(R.string.refreshing));
    355                 setProgressBarIndeterminateVisibility(true);
    356                 break;
    357             default:
    358                 Log.e(TAG, "Invalid State");
    359         }
    360     }
    361 
    362     private void viewMessage(Cursor cursor) {
    363         // TODO: Add this.
    364     }
    365 }
    366 
    367