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.AlertDialog; 20 import android.app.ListActivity; 21 import android.app.NotificationManager; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.DialogInterface.OnClickListener; 25 import android.content.Intent; 26 import android.database.Cursor; 27 import android.database.sqlite.SQLiteDatabase; 28 import android.os.Bundle; 29 import android.view.ContextMenu; 30 import android.view.ContextMenu.ContextMenuInfo; 31 import android.view.Menu; 32 import android.view.MenuItem; 33 import android.view.View; 34 import android.view.View.OnCreateContextMenuListener; 35 import android.widget.ListView; 36 import android.widget.TextView; 37 38 /** 39 * This activity provides a list view of received cell broadcasts. 40 */ 41 public class CellBroadcastListActivity extends ListActivity { 42 private static final String TAG = "CellBroadcastListActivity"; 43 44 // IDs of the main menu items. 45 public static final int MENU_DELETE_ALL = 3; 46 public static final int MENU_PREFERENCES = 4; 47 48 // IDs of the context menu items for the list of broadcasts. 49 public static final int MENU_DELETE = 0; 50 public static final int MENU_VIEW = 1; 51 52 private CellBroadcastListAdapter mListAdapter; 53 54 private SQLiteDatabase mBroadcastDb; 55 56 private Cursor mAdapterCursor; 57 58 @Override onCreate(Bundle savedInstanceState)59 protected void onCreate(Bundle savedInstanceState) { 60 super.onCreate(savedInstanceState); 61 setContentView(R.layout.cell_broadcast_list_screen); 62 63 ListView listView = getListView(); 64 listView.setOnCreateContextMenuListener(mOnCreateContextMenuListener); 65 66 if (mBroadcastDb == null) { 67 CellBroadcastDatabase.DatabaseHelper helper = 68 new CellBroadcastDatabase.DatabaseHelper(this); 69 mBroadcastDb = helper.getReadableDatabase(); 70 } 71 72 if (mAdapterCursor == null) { 73 mAdapterCursor = CellBroadcastDatabase.getCursor(mBroadcastDb); 74 } 75 76 mListAdapter = new CellBroadcastListAdapter(this, mAdapterCursor); 77 setListAdapter(mListAdapter); 78 79 CellBroadcastDatabaseService.setActiveListActivity(this); 80 81 parseIntent(getIntent()); 82 } 83 84 @Override onDestroy()85 protected void onDestroy() { 86 if (mAdapterCursor != null) { 87 mAdapterCursor.close(); 88 mAdapterCursor = null; 89 } 90 if (mBroadcastDb != null) { 91 mBroadcastDb.close(); 92 mBroadcastDb = null; 93 } 94 CellBroadcastDatabaseService.setActiveListActivity(null); 95 super.onDestroy(); 96 } 97 98 /** Callback from CellBroadcastDatabaseService after content changes. */ databaseContentChanged()99 void databaseContentChanged() { 100 runOnUiThread(new Runnable() { 101 public void run() { 102 mAdapterCursor.requery(); 103 } 104 }); 105 } 106 107 @Override onNewIntent(Intent intent)108 protected void onNewIntent(Intent intent) { 109 // TODO: how do multiple messages stack together? 110 // removeDialog(DIALOG_SHOW_MESSAGE); 111 parseIntent(intent); 112 } 113 114 @Override onPrepareOptionsMenu(Menu menu)115 public boolean onPrepareOptionsMenu(Menu menu) { 116 menu.clear(); 117 118 if (mListAdapter.getCount() > 0) { 119 menu.add(0, MENU_DELETE_ALL, 0, R.string.menu_delete_all).setIcon( 120 android.R.drawable.ic_menu_delete); 121 } 122 123 menu.add(0, MENU_PREFERENCES, 0, R.string.menu_preferences).setIcon( 124 android.R.drawable.ic_menu_preferences); 125 126 return true; 127 } 128 129 @Override onOptionsItemSelected(MenuItem item)130 public boolean onOptionsItemSelected(MenuItem item) { 131 switch(item.getItemId()) { 132 case MENU_DELETE_ALL: 133 confirmDeleteThread(-1); 134 break; 135 136 case MENU_PREFERENCES: 137 Intent intent = new Intent(this, CellBroadcastSettings.class); 138 startActivityIfNeeded(intent, -1); 139 break; 140 141 default: 142 return true; 143 } 144 return false; 145 } 146 147 @Override onListItemClick(ListView l, View v, int position, long id)148 protected void onListItemClick(ListView l, View v, int position, long id) { 149 Cursor cursor = mListAdapter.getCursor(); 150 if (cursor != null && cursor.getPosition() >= 0) { 151 showDialogAndMarkRead(cursor); 152 } 153 } 154 155 private final OnCreateContextMenuListener mOnCreateContextMenuListener = 156 new OnCreateContextMenuListener() { 157 public void onCreateContextMenu(ContextMenu menu, View v, 158 ContextMenuInfo menuInfo) { 159 menu.add(0, MENU_VIEW, 0, R.string.menu_view); 160 menu.add(0, MENU_DELETE, 0, R.string.menu_delete); 161 } 162 }; 163 164 @Override onContextItemSelected(MenuItem item)165 public boolean onContextItemSelected(MenuItem item) { 166 Cursor cursor = mListAdapter.getCursor(); 167 if (cursor != null && cursor.getPosition() >= 0) { 168 switch (item.getItemId()) { 169 case MENU_DELETE: 170 confirmDeleteThread(cursor.getLong(CellBroadcastDatabase.COLUMN_ID)); 171 break; 172 173 case MENU_VIEW: 174 showDialogAndMarkRead(cursor); 175 break; 176 177 default: 178 break; 179 } 180 } 181 return super.onContextItemSelected(item); 182 } 183 showDialogAndMarkRead(Cursor cursor)184 private void showDialogAndMarkRead(Cursor cursor) { 185 CellBroadcastMessage cbm = CellBroadcastMessage.createFromCursor(cursor); 186 // show emergency alerts with the warning icon, but don't play alert tone 187 CellBroadcastAlertDialog dialog = new CellBroadcastAlertDialog(this, 188 cbm.getDialogTitleResource(), cbm.getMessageBody(), 189 cbm.isPublicAlertMessage(), cbm.getDeliveryTime()); 190 dialog.show(); 191 } 192 193 /** 194 * Start the process of putting up a dialog to confirm deleting a broadcast. 195 * @param rowId the row ID of the broadcast to delete, or -1 to delete all broadcasts 196 */ confirmDeleteThread(long rowId)197 public void confirmDeleteThread(long rowId) { 198 DeleteThreadListener listener = new DeleteThreadListener(rowId); 199 confirmDeleteThreadDialog(listener, (rowId == -1), this); 200 } 201 202 /** 203 * Build and show the proper delete broadcast dialog. The UI is slightly different 204 * depending on whether there are locked messages in the thread(s) and whether we're 205 * deleting a single broadcast or all broadcasts. 206 * @param listener gets called when the delete button is pressed 207 * @param deleteAll whether to show a single thread or all threads UI 208 * @param context used to load the various UI elements 209 */ confirmDeleteThreadDialog(DeleteThreadListener listener, boolean deleteAll, Context context)210 public static void confirmDeleteThreadDialog(DeleteThreadListener listener, 211 boolean deleteAll, Context context) { 212 View contents = View.inflate(context, R.layout.delete_broadcast_dialog_view, null); 213 TextView msg = (TextView)contents.findViewById(R.id.message); 214 msg.setText(deleteAll 215 ? R.string.confirm_delete_all_broadcasts 216 : R.string.confirm_delete_broadcast); 217 218 AlertDialog.Builder builder = new AlertDialog.Builder(context); 219 builder.setTitle(R.string.confirm_dialog_title) 220 .setIcon(android.R.drawable.ic_dialog_alert) 221 .setCancelable(true) 222 .setPositiveButton(R.string.button_delete, listener) 223 .setNegativeButton(R.string.button_cancel, null) 224 .setView(contents) 225 .show(); 226 } 227 228 public class DeleteThreadListener implements OnClickListener { 229 private final long mRowId; 230 DeleteThreadListener(long rowId)231 public DeleteThreadListener(long rowId) { 232 mRowId = rowId; 233 } 234 onClick(DialogInterface dialog, int whichButton)235 public void onClick(DialogInterface dialog, int whichButton) { 236 if (mRowId != -1) { 237 // delete from database on a separate service thread 238 Intent dbWriteIntent = new Intent(CellBroadcastListActivity.this, 239 CellBroadcastDatabaseService.class); 240 dbWriteIntent.setAction(CellBroadcastDatabaseService.ACTION_DELETE_BROADCAST); 241 dbWriteIntent.putExtra(CellBroadcastDatabaseService.DATABASE_ROW_ID_EXTRA, mRowId); 242 startService(dbWriteIntent); 243 } else { 244 // delete from database on a separate service thread 245 Intent dbWriteIntent = new Intent(CellBroadcastListActivity.this, 246 CellBroadcastDatabaseService.class); 247 dbWriteIntent.setAction(CellBroadcastDatabaseService.ACTION_DELETE_ALL_BROADCASTS); 248 startService(dbWriteIntent); 249 } 250 dialog.dismiss(); 251 } 252 } 253 parseIntent(Intent intent)254 private void parseIntent(Intent intent) { 255 if (intent == null) { 256 return; 257 } 258 Bundle extras = intent.getExtras(); 259 if (extras == null) { 260 return; 261 } 262 263 CellBroadcastMessage cbm = extras.getParcelable(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA); 264 int notificationId = extras.getInt(CellBroadcastAlertService.SMS_CB_NOTIFICATION_ID_EXTRA); 265 266 // Dismiss the notification that brought us here. 267 NotificationManager notificationManager = 268 (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); 269 notificationManager.cancel(notificationId); 270 271 boolean isEmergencyAlert = cbm.isPublicAlertMessage(); 272 273 CellBroadcastAlertDialog dialog = new CellBroadcastAlertDialog(this, 274 cbm.getDialogTitleResource(), cbm.getMessageBody(), 275 isEmergencyAlert, cbm.getDeliveryTime()); 276 dialog.show(); 277 } 278 } 279