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