1da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby/* 2da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Copyright (C) 2012 The Android Open Source Project 3da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * 4da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Licensed under the Apache License, Version 2.0 (the "License"); 5da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * you may not use this file except in compliance with the License. 6da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * You may obtain a copy of the License at 7da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * 8da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * http://www.apache.org/licenses/LICENSE-2.0 9da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * 10da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Unless required by applicable law or agreed to in writing, software 11da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * distributed under the License is distributed on an "AS IS" BASIS, 12da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * See the License for the specific language governing permissions and 14da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * limitations under the License. 15da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 16da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 17da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambypackage com.android.cellbroadcastreceiver; 18da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 19da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.content.ContentProvider; 20da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.content.ContentProviderClient; 21da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.content.ContentResolver; 22da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.content.ContentValues; 23da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.content.UriMatcher; 24da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.database.Cursor; 25da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.database.sqlite.SQLiteDatabase; 26da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.database.sqlite.SQLiteOpenHelper; 27da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.database.sqlite.SQLiteQueryBuilder; 28da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.net.Uri; 29da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.os.AsyncTask; 30da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.provider.Telephony; 31da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.telephony.CellBroadcastMessage; 32da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.text.TextUtils; 33da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambyimport android.util.Log; 34da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 35da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby/** 36da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * ContentProvider for the database of received cell broadcasts. 37da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 38da5c415f6d0999131e93384b5fb90422ada8e4daJake Hambypublic class CellBroadcastContentProvider extends ContentProvider { 39da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final String TAG = "CellBroadcastContentProvider"; 40da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 41da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** URI matcher for ContentProvider queries. */ 42da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 43da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 44da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** Authority string for content URIs. */ 45da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby static final String CB_AUTHORITY = "cellbroadcasts"; 46da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 47da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** Content URI for notifying observers. */ 48da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts/"); 49da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 50da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** URI matcher type to get all cell broadcasts. */ 51da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final int CB_ALL = 0; 52da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 53da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** URI matcher type to get a cell broadcast by ID. */ 54da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final int CB_ALL_ID = 1; 55da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 56da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** MIME type for the list of all cell broadcasts. */ 57da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final String CB_LIST_TYPE = "vnd.android.cursor.dir/cellbroadcast"; 58da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 59da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** MIME type for an individual cell broadcast. */ 60da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private static final String CB_TYPE = "vnd.android.cursor.item/cellbroadcast"; 61da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 62da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby static { 63da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby sUriMatcher.addURI(CB_AUTHORITY, null, CB_ALL); 64da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby sUriMatcher.addURI(CB_AUTHORITY, "#", CB_ALL_ID); 65da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 66da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 67da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** The database for this content provider. */ 68da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private SQLiteOpenHelper mOpenHelper; 69da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 70da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 71da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Initialize content provider. 72da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return true if the provider was successfully loaded, false otherwise 73da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 74da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 75da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public boolean onCreate() { 76da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby mOpenHelper = new CellBroadcastDatabaseHelper(getContext()); 77da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return true; 78da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 79da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 80da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 81da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Return a cursor for the cell broadcast table. 82da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param uri the URI to query. 83da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param projection the list of columns to put into the cursor, or null. 84da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param selection the selection criteria to apply when filtering rows, or null. 85da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param selectionArgs values to replace ?s in selection string. 86da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param sortOrder how the rows in the cursor should be sorted, or null to sort from most 87da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * recently received to least recently received. 88da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return a Cursor or null. 89da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 90da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 91da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 92da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby String sortOrder) { 93da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 94da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby qb.setTables(CellBroadcastDatabaseHelper.TABLE_NAME); 95da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 96da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby int match = sUriMatcher.match(uri); 97da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby switch (match) { 98da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby case CB_ALL: 99da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby // get all broadcasts 100da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby break; 101da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 102da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby case CB_ALL_ID: 103da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby // get broadcast by ID 104da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby qb.appendWhere("(_id=" + uri.getPathSegments().get(0) + ')'); 105da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby break; 106da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 107da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby default: 108da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.e(TAG, "Invalid query: " + uri); 109da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby throw new IllegalArgumentException("Unknown URI: " + uri); 110da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 111da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 112da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby String orderBy; 113da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (!TextUtils.isEmpty(sortOrder)) { 114da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby orderBy = sortOrder; 115da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } else { 116da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby orderBy = Telephony.CellBroadcasts.DEFAULT_SORT_ORDER; 117da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 118da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 119da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 120da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); 121da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (c != null) { 122da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby c.setNotificationUri(getContext().getContentResolver(), CONTENT_URI); 123da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 124da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return c; 125da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 126da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 127da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 128da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Return the MIME type of the data at the specified URI. 129da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param uri the URI to query. 130da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return a MIME type string, or null if there is no type. 131da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 132da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 133da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public String getType(Uri uri) { 134da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby int match = sUriMatcher.match(uri); 135da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby switch (match) { 136da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby case CB_ALL: 137da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return CB_LIST_TYPE; 138da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 139da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby case CB_ALL_ID: 140da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return CB_TYPE; 141da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 142da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby default: 143da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return null; 144da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 145da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 146da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 147da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 148da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Insert a new row. This throws an exception, as the database can only be modified by 149da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * calling custom methods in this class, and not via the ContentProvider interface. 150da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param uri the content:// URI of the insertion request. 151da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param values a set of column_name/value pairs to add to the database. 152da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return the URI for the newly inserted item. 153da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 154da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 155da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public Uri insert(Uri uri, ContentValues values) { 156da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby throw new UnsupportedOperationException("insert not supported"); 157da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 158da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 159da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 160da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Delete one or more rows. This throws an exception, as the database can only be modified by 161da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * calling custom methods in this class, and not via the ContentProvider interface. 162da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param uri the full URI to query, including a row ID (if a specific record is requested). 163da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param selection an optional restriction to apply to rows when deleting. 164da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return the number of rows affected. 165da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 166da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 167da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public int delete(Uri uri, String selection, String[] selectionArgs) { 168da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby throw new UnsupportedOperationException("delete not supported"); 169da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 170da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 171da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 172da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Update one or more rows. This throws an exception, as the database can only be modified by 173da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * calling custom methods in this class, and not via the ContentProvider interface. 174da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param uri the URI to query, potentially including the row ID. 175da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param values a Bundle mapping from column names to new column values. 176da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param selection an optional filter to match rows to update. 177da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return the number of rows affected. 178da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 179da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 180da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 181da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby throw new UnsupportedOperationException("update not supported"); 182da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 183da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 184da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 185da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Internal method to insert a new Cell Broadcast into the database and notify observers. 186da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param message the message to insert 187eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby * @return true if the broadcast is new, false if it's a duplicate broadcast. 188da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 189da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby boolean insertNewBroadcast(CellBroadcastMessage message) { 190da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 191da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby ContentValues cv = message.getContentValues(); 192da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 1934be1ab169dadd108cceff8f76067cf874bda9d97Jake Hamby // Note: this method previously queried the database for duplicate message IDs, but this 1944be1ab169dadd108cceff8f76067cf874bda9d97Jake Hamby // is not compatible with CMAS carrier requirements and could also cause other emergency 1954be1ab169dadd108cceff8f76067cf874bda9d97Jake Hamby // alerts, e.g. ETWS, to not display if the database is filled with old messages. 1964be1ab169dadd108cceff8f76067cf874bda9d97Jake Hamby // Use duplicate message ID detection in CellBroadcastAlertService instead of DB query. 197eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby 198eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby long rowId = db.insert(CellBroadcastDatabaseHelper.TABLE_NAME, null, cv); 199eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby if (rowId == -1) { 200eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby Log.e(TAG, "failed to insert new broadcast into database"); 201eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby // Return true on DB write failure because we still want to notify the user. 202eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby // The CellBroadcastMessage will be passed with the intent, so the message will be 203eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby // displayed in the emergency alert dialog, or the dialog that is displayed when 204eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby // the user selects the notification for a non-emergency broadcast, even if the 205eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby // broadcast could not be written to the database. 206eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby } 207eef14be1b2b77fc08a6cc5ef301ba49ea54c0c0aJake Hamby return true; // broadcast is not a duplicate 208da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 209da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 210da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 211da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Internal method to delete a cell broadcast by row ID and notify observers. 212da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param rowId the row ID of the broadcast to delete 213da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return true if the database was updated, false otherwise 214da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 21557273ebfa13f96bf5aba9902b70e2b179fec9e4cJake Hamby boolean deleteBroadcast(long rowId) { 216da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 217da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 218da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby int rowCount = db.delete(CellBroadcastDatabaseHelper.TABLE_NAME, 219da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Telephony.CellBroadcasts._ID + "=?", 220da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby new String[]{Long.toString(rowId)}); 221da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (rowCount != 0) { 222da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return true; 223da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } else { 224da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.e(TAG, "failed to delete broadcast at row " + rowId); 225da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return false; 226da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 227da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 228da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 229da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 230da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Internal method to delete all cell broadcasts and notify observers. 231da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return true if the database was updated, false otherwise 232da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 233da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby boolean deleteAllBroadcasts() { 234da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 235da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 236da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby int rowCount = db.delete(CellBroadcastDatabaseHelper.TABLE_NAME, null, null); 237da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (rowCount != 0) { 238da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return true; 239da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } else { 240da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.e(TAG, "failed to delete all broadcasts"); 241da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return false; 242da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 243da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 244da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 245da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 246da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Internal method to mark a broadcast as read and notify observers. The broadcast can be 247da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * identified by delivery time (for new alerts) or by row ID. The caller is responsible for 248da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * decrementing the unread non-emergency alert count, if necessary. 249da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * 250da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param columnName the column name to query (ID or delivery time) 251da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param columnValue the ID or delivery time of the broadcast to mark read 252da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return true if the database was updated, false otherwise 253da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 254da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby boolean markBroadcastRead(String columnName, long columnValue) { 255da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 256da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 257da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby ContentValues cv = new ContentValues(1); 258da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby cv.put(Telephony.CellBroadcasts.MESSAGE_READ, 1); 259da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 260da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby String whereClause = columnName + "=?"; 261da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby String[] whereArgs = new String[]{Long.toString(columnValue)}; 262da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 263da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby int rowCount = db.update(CellBroadcastDatabaseHelper.TABLE_NAME, cv, whereClause, whereArgs); 264da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (rowCount != 0) { 265da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return true; 266da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } else { 267da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.e(TAG, "failed to mark broadcast read: " + columnName + " = " + columnValue); 268da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return false; 269da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 270da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 271da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 272da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** Callback for users of AsyncCellBroadcastOperation. */ 273da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby interface CellBroadcastOperation { 274da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 275da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Perform an operation using the specified provider. 276da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param provider the CellBroadcastContentProvider to use 277da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return true if any rows were changed, false otherwise 278da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 279da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby boolean execute(CellBroadcastContentProvider provider); 280da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 281da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 282da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 283da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Async task to call this content provider's internal methods on a background thread. 284da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * The caller supplies the CellBroadcastOperation object to call for this provider. 285da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 286da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby static class AsyncCellBroadcastTask extends AsyncTask<CellBroadcastOperation, Void, Void> { 287da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** Reference to this app's content resolver. */ 288da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby private ContentResolver mContentResolver; 289da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 290da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby AsyncCellBroadcastTask(ContentResolver contentResolver) { 291da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby mContentResolver = contentResolver; 292da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 293da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 294da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby /** 295da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * Perform a generic operation on the CellBroadcastContentProvider. 296da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @param params the CellBroadcastOperation object to call for this provider 297da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby * @return void 298da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby */ 299da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby @Override 300da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby protected Void doInBackground(CellBroadcastOperation... params) { 301da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby ContentProviderClient cpc = mContentResolver.acquireContentProviderClient( 302da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby CellBroadcastContentProvider.CB_AUTHORITY); 303da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby CellBroadcastContentProvider provider = (CellBroadcastContentProvider) 304da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby cpc.getLocalContentProvider(); 305da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 306da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (provider != null) { 307da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby try { 308da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby boolean changed = params[0].execute(provider); 309da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby if (changed) { 310da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.d(TAG, "database changed: notifying observers..."); 311da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby mContentResolver.notifyChange(CONTENT_URI, null, false); 312da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 313da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } finally { 314da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby cpc.release(); 315da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 316da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } else { 317da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby Log.e(TAG, "getLocalContentProvider() returned null"); 318da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 319da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby 320da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby mContentResolver = null; // free reference to content resolver 321da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby return null; 322da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 323da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby } 324da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby} 325