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