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 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 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. */ 99 void databaseContentChanged() { 100 runOnUiThread(new Runnable() { 101 public void run() { 102 mAdapterCursor.requery(); 103 } 104 }); 105 } 106 107 @Override 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 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 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 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 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 184 private void showDialogAndMarkRead(Cursor cursor) { 185 CellBroadcastMessage cbm = CellBroadcastMessage.createFromCursor(cursor); 186 boolean isAlertMessage = cbm.isPublicAlertMessage() || CellBroadcastConfigService 187 .isOperatorDefinedEmergencyId(cbm.getMessageIdentifier()); 188 // show emergency alerts with the warning icon, but don't play alert tone 189 CellBroadcastAlertDialog dialog = new CellBroadcastAlertDialog(this, 190 cbm.getDialogTitleResource(), cbm.getMessageBody(), 191 isAlertMessage, cbm.getDeliveryTime()); 192 dialog.show(); 193 } 194 195 /** 196 * Start the process of putting up a dialog to confirm deleting a broadcast. 197 * @param rowId the row ID of the broadcast to delete, or -1 to delete all broadcasts 198 */ 199 public void confirmDeleteThread(long rowId) { 200 DeleteThreadListener listener = new DeleteThreadListener(rowId); 201 confirmDeleteThreadDialog(listener, (rowId == -1), this); 202 } 203 204 /** 205 * Build and show the proper delete broadcast dialog. The UI is slightly different 206 * depending on whether there are locked messages in the thread(s) and whether we're 207 * deleting a single broadcast or all broadcasts. 208 * @param listener gets called when the delete button is pressed 209 * @param deleteAll whether to show a single thread or all threads UI 210 * @param context used to load the various UI elements 211 */ 212 public static void confirmDeleteThreadDialog(DeleteThreadListener listener, 213 boolean deleteAll, Context context) { 214 View contents = View.inflate(context, R.layout.delete_broadcast_dialog_view, null); 215 TextView msg = (TextView)contents.findViewById(R.id.message); 216 msg.setText(deleteAll 217 ? R.string.confirm_delete_all_broadcasts 218 : R.string.confirm_delete_broadcast); 219 220 AlertDialog.Builder builder = new AlertDialog.Builder(context); 221 builder.setTitle(R.string.confirm_dialog_title) 222 .setIcon(android.R.drawable.ic_dialog_alert) 223 .setCancelable(true) 224 .setPositiveButton(R.string.button_delete, listener) 225 .setNegativeButton(R.string.button_cancel, null) 226 .setView(contents) 227 .show(); 228 } 229 230 public class DeleteThreadListener implements OnClickListener { 231 private final long mRowId; 232 233 public DeleteThreadListener(long rowId) { 234 mRowId = rowId; 235 } 236 237 public void onClick(DialogInterface dialog, int whichButton) { 238 if (mRowId != -1) { 239 // delete from database on a separate service thread 240 Intent dbWriteIntent = new Intent(CellBroadcastListActivity.this, 241 CellBroadcastDatabaseService.class); 242 dbWriteIntent.setAction(CellBroadcastDatabaseService.ACTION_DELETE_BROADCAST); 243 dbWriteIntent.putExtra(CellBroadcastDatabaseService.DATABASE_ROW_ID_EXTRA, mRowId); 244 startService(dbWriteIntent); 245 } else { 246 // delete from database on a separate service thread 247 Intent dbWriteIntent = new Intent(CellBroadcastListActivity.this, 248 CellBroadcastDatabaseService.class); 249 dbWriteIntent.setAction(CellBroadcastDatabaseService.ACTION_DELETE_ALL_BROADCASTS); 250 startService(dbWriteIntent); 251 } 252 dialog.dismiss(); 253 } 254 } 255 256 private void parseIntent(Intent intent) { 257 if (intent == null) { 258 return; 259 } 260 Bundle extras = intent.getExtras(); 261 if (extras == null) { 262 return; 263 } 264 265 CellBroadcastMessage cbm = extras.getParcelable(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA); 266 int notificationId = extras.getInt(CellBroadcastAlertService.SMS_CB_NOTIFICATION_ID_EXTRA); 267 268 // Dismiss the notification that brought us here. 269 NotificationManager notificationManager = 270 (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); 271 notificationManager.cancel(notificationId); 272 273 boolean isEmergencyAlert = cbm.isPublicAlertMessage() || CellBroadcastConfigService 274 .isOperatorDefinedEmergencyId(cbm.getMessageIdentifier()); 275 276 CellBroadcastAlertDialog dialog = new CellBroadcastAlertDialog(this, 277 cbm.getDialogTitleResource(), cbm.getMessageBody(), 278 isEmergencyAlert, cbm.getDeliveryTime()); 279 dialog.show(); 280 } 281 } 282