Home | History | Annotate | Download | only in cellbroadcastreceiver
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.cellbroadcastreceiver;
     18 
     19 import android.app.Activity;
     20 import android.app.AlertDialog;
     21 import android.app.FragmentManager;
     22 import android.app.ListFragment;
     23 import android.app.LoaderManager;
     24 import android.app.NotificationManager;
     25 import android.content.Context;
     26 import android.content.CursorLoader;
     27 import android.content.DialogInterface;
     28 import android.content.DialogInterface.OnClickListener;
     29 import android.content.Intent;
     30 import android.content.Loader;
     31 import android.database.Cursor;
     32 import android.os.Bundle;
     33 import android.provider.Telephony;
     34 import android.telephony.CellBroadcastMessage;
     35 import android.view.ContextMenu;
     36 import android.view.ContextMenu.ContextMenuInfo;
     37 import android.view.LayoutInflater;
     38 import android.view.Menu;
     39 import android.view.MenuInflater;
     40 import android.view.MenuItem;
     41 import android.view.View;
     42 import android.view.View.OnCreateContextMenuListener;
     43 import android.view.ViewGroup;
     44 import android.widget.CursorAdapter;
     45 import android.widget.ListView;
     46 
     47 /**
     48  * This activity provides a list view of received cell broadcasts. Most of the work is handled
     49  * in the inner CursorLoaderListFragment class.
     50  */
     51 public class CellBroadcastListActivity extends Activity {
     52 
     53     @Override
     54     protected void onCreate(Bundle savedInstanceState) {
     55         super.onCreate(savedInstanceState);
     56 
     57         // Dismiss the notification that brought us here (if any).
     58         ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE))
     59                 .cancel(CellBroadcastAlertService.NOTIFICATION_ID);
     60 
     61         FragmentManager fm = getFragmentManager();
     62 
     63         // Create the list fragment and add it as our sole content.
     64         if (fm.findFragmentById(android.R.id.content) == null) {
     65             CursorLoaderListFragment listFragment = new CursorLoaderListFragment();
     66             fm.beginTransaction().add(android.R.id.content, listFragment).commit();
     67         }
     68     }
     69 
     70     /**
     71      * List fragment queries SQLite database on worker thread.
     72      */
     73     public static class CursorLoaderListFragment extends ListFragment
     74             implements LoaderManager.LoaderCallbacks<Cursor> {
     75 
     76         // IDs of the main menu items.
     77         private static final int MENU_DELETE_ALL           = 3;
     78         private static final int MENU_PREFERENCES          = 4;
     79 
     80         // IDs of the context menu items (package local, accessed from inner DeleteThreadListener).
     81         static final int MENU_DELETE               = 0;
     82         static final int MENU_VIEW                 = 1;
     83 
     84         // This is the Adapter being used to display the list's data.
     85         CursorAdapter mAdapter;
     86 
     87         @Override
     88         public void onCreate(Bundle savedInstanceState) {
     89             super.onCreate(savedInstanceState);
     90 
     91             // We have a menu item to show in action bar.
     92             setHasOptionsMenu(true);
     93         }
     94 
     95         @Override
     96         public View onCreateView(LayoutInflater inflater, ViewGroup container,
     97                 Bundle savedInstanceState) {
     98             return inflater.inflate(R.layout.cell_broadcast_list_screen, container, false);
     99         }
    100 
    101         @Override
    102         public void onActivityCreated(Bundle savedInstanceState) {
    103             super.onActivityCreated(savedInstanceState);
    104 
    105             // Set context menu for long-press.
    106             ListView listView = getListView();
    107             listView.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
    108 
    109             // Create a cursor adapter to display the loaded data.
    110             mAdapter = new CellBroadcastCursorAdapter(getActivity(), null);
    111             setListAdapter(mAdapter);
    112 
    113             // Prepare the loader.  Either re-connect with an existing one,
    114             // or start a new one.
    115             getLoaderManager().initLoader(0, null, this);
    116         }
    117 
    118         @Override
    119         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    120             menu.add(0, MENU_DELETE_ALL, 0, R.string.menu_delete_all).setIcon(
    121                     android.R.drawable.ic_menu_delete);
    122             menu.add(0, MENU_PREFERENCES, 0, R.string.menu_preferences).setIcon(
    123                     android.R.drawable.ic_menu_preferences);
    124         }
    125 
    126         @Override
    127         public void onPrepareOptionsMenu(Menu menu) {
    128             menu.findItem(MENU_DELETE_ALL).setVisible(!mAdapter.isEmpty());
    129         }
    130 
    131         @Override
    132         public void onListItemClick(ListView l, View v, int position, long id) {
    133             CellBroadcastListItem cbli = (CellBroadcastListItem) v;
    134             showDialogAndMarkRead(cbli.getMessage());
    135         }
    136 
    137         @Override
    138         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    139             return new CursorLoader(getActivity(), CellBroadcastContentProvider.CONTENT_URI,
    140                     Telephony.CellBroadcasts.QUERY_COLUMNS, null, null,
    141                     Telephony.CellBroadcasts.DELIVERY_TIME + " DESC");
    142         }
    143 
    144         @Override
    145         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    146             // Swap the new cursor in.  (The framework will take care of closing the
    147             // old cursor once we return.)
    148             mAdapter.swapCursor(data);
    149         }
    150 
    151         @Override
    152         public void onLoaderReset(Loader<Cursor> loader) {
    153             // This is called when the last Cursor provided to onLoadFinished()
    154             // above is about to be closed.  We need to make sure we are no
    155             // longer using it.
    156             mAdapter.swapCursor(null);
    157         }
    158 
    159         private void showDialogAndMarkRead(CellBroadcastMessage cbm) {
    160             // show emergency alerts with the warning icon, but don't play alert tone
    161             Intent i = new Intent(getActivity(), CellBroadcastAlertDialog.class);
    162             i.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, cbm);
    163             startActivity(i);
    164         }
    165 
    166         private final OnCreateContextMenuListener mOnCreateContextMenuListener =
    167                 new OnCreateContextMenuListener() {
    168                     @Override
    169                     public void onCreateContextMenu(ContextMenu menu, View v,
    170                             ContextMenuInfo menuInfo) {
    171                         menu.setHeaderTitle(R.string.message_options);
    172                         menu.add(0, MENU_VIEW, 0, R.string.menu_view);
    173                         menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
    174                     }
    175                 };
    176 
    177         @Override
    178         public boolean onContextItemSelected(MenuItem item) {
    179             Cursor cursor = mAdapter.getCursor();
    180             if (cursor != null && cursor.getPosition() >= 0) {
    181                 switch (item.getItemId()) {
    182                     case MENU_DELETE:
    183                         // We need to decrement the unread alert count if deleting unread alert
    184                         boolean isUnread = (cursor.getInt(cursor.getColumnIndexOrThrow(
    185                                 Telephony.CellBroadcasts.MESSAGE_READ)) == 0);
    186                         confirmDeleteThread(cursor.getLong(cursor.getColumnIndexOrThrow(
    187                                 Telephony.CellBroadcasts._ID)), isUnread);
    188                         break;
    189 
    190                     case MENU_VIEW:
    191                         showDialogAndMarkRead(CellBroadcastMessage.createFromCursor(cursor));
    192                         break;
    193 
    194                     default:
    195                         break;
    196                 }
    197             }
    198             return super.onContextItemSelected(item);
    199         }
    200 
    201         @Override
    202         public boolean onOptionsItemSelected(MenuItem item) {
    203             switch(item.getItemId()) {
    204                 case MENU_DELETE_ALL:
    205                     confirmDeleteThread(-1, false);
    206                     break;
    207 
    208                 case MENU_PREFERENCES:
    209                     Intent intent = new Intent(getActivity(), CellBroadcastSettings.class);
    210                     startActivity(intent);
    211                     break;
    212 
    213                 default:
    214                     return true;
    215             }
    216             return false;
    217         }
    218 
    219         /**
    220          * Start the process of putting up a dialog to confirm deleting a broadcast.
    221          * @param rowId the row ID of the broadcast to delete, or -1 to delete all broadcasts
    222          * @param unread true if the alert was not already marked as read
    223          */
    224         public void confirmDeleteThread(long rowId, boolean unread) {
    225             DeleteThreadListener listener = new DeleteThreadListener(rowId, unread);
    226             confirmDeleteThreadDialog(listener, (rowId == -1), getActivity());
    227         }
    228 
    229         /**
    230          * Build and show the proper delete broadcast dialog. The UI is slightly different
    231          * depending on whether there are locked messages in the thread(s) and whether we're
    232          * deleting a single broadcast or all broadcasts.
    233          * @param listener gets called when the delete button is pressed
    234          * @param deleteAll whether to show a single thread or all threads UI
    235          * @param context used to load the various UI elements
    236          */
    237         public static void confirmDeleteThreadDialog(DeleteThreadListener listener,
    238                 boolean deleteAll, Context context) {
    239             AlertDialog.Builder builder = new AlertDialog.Builder(context);
    240             builder.setIcon(android.R.drawable.ic_dialog_alert)
    241                     .setCancelable(true)
    242                     .setPositiveButton(R.string.button_delete, listener)
    243                     .setNegativeButton(R.string.button_cancel, null)
    244                     .setMessage(deleteAll ? R.string.confirm_delete_all_broadcasts
    245                             : R.string.confirm_delete_broadcast)
    246                     .show();
    247         }
    248 
    249         public class DeleteThreadListener implements OnClickListener {
    250             private final long mRowId;
    251             private final boolean mIsUnread;
    252 
    253             public DeleteThreadListener(long rowId, boolean unread) {
    254                 mRowId = rowId;
    255                 mIsUnread = unread;
    256             }
    257 
    258             @Override
    259             public void onClick(DialogInterface dialog, int whichButton) {
    260                 // delete from database on a background thread
    261                 new CellBroadcastContentProvider.AsyncCellBroadcastTask(
    262                         getActivity().getContentResolver()).execute(
    263                         new CellBroadcastContentProvider.CellBroadcastOperation() {
    264                             @Override
    265                             public boolean execute(CellBroadcastContentProvider provider) {
    266                                 if (mRowId != -1) {
    267                                     return provider.deleteBroadcast(mRowId, mIsUnread);
    268                                 } else {
    269                                     return provider.deleteAllBroadcasts();
    270                                 }
    271                             }
    272                         });
    273 
    274                 dialog.dismiss();
    275             }
    276         }
    277     }
    278 
    279     @Override
    280     protected void onNewIntent(Intent intent) {
    281         if (intent == null) {
    282             return;
    283         }
    284 
    285         Bundle extras = intent.getExtras();
    286         if (extras == null) {
    287             return;
    288         }
    289 
    290         CellBroadcastMessage cbm = extras.getParcelable(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
    291         int notificationId = extras.getInt(CellBroadcastAlertService.SMS_CB_NOTIFICATION_ID_EXTRA);
    292 
    293         // Dismiss the notification that brought us here.
    294         NotificationManager notificationManager =
    295             (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
    296         notificationManager.cancel(notificationId);
    297 
    298         // launch the dialog activity to show the alert
    299         Intent i = new Intent(this, CellBroadcastAlertDialog.class);
    300         i.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, cbm);
    301         startActivity(i);
    302     }
    303 }
    304