150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby/*
250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Copyright (C) 2011 The Android Open Source Project
350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * you may not use this file except in compliance with the License.
650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * You may obtain a copy of the License at
750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
1050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Unless required by applicable law or agreed to in writing, software
1150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
1250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * See the License for the specific language governing permissions and
1450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * limitations under the License.
1550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby */
1650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypackage com.android.cellbroadcastreceiver;
1850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.app.IntentService;
2050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.ContentValues;
2150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.Intent;
2250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.database.sqlite.SQLiteDatabase;
2350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.util.Log;
2450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
2550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby/**
2650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Service to update the SQLite database to add a new broadcast message,
2750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * or to delete one or all previously received broadcasts.
2850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby */
2950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypublic class CellBroadcastDatabaseService extends IntentService {
3050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private static final String TAG = "CellBroadcastDatabaseService";
3150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Action to insert a new message (passed as CellBroadcastMessage extra). */
3350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static final String ACTION_INSERT_NEW_BROADCAST = "ACTION_INSERT_NEW_BROADCAST";
3450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Action to delete a single broadcast (row ID passed as extra). */
3650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static final String ACTION_DELETE_BROADCAST = "ACTION_DELETE_BROADCAST";
3750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Action to mark a broadcast as read by the user (by row ID or delivery time extra). */
3950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static final String ACTION_MARK_BROADCAST_READ = "ACTION_MARK_BROADCAST_READ";
4050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Action to delete all broadcasts from database (no extras). */
4250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static final String ACTION_DELETE_ALL_BROADCASTS = "ACTION_DELETE_ALL_BROADCASTS";
4350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Identifier for getExtra() for row ID to delete or mark read. */
4550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public static final String DATABASE_ROW_ID_EXTRA =
4650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            "com.android.cellbroadcastreceiver.DATABASE_ROW_ID";
4750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Identifier for getExtra() for delivery time of broadcast to mark read. */
4950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public static final String DATABASE_DELIVERY_TIME_EXTRA =
5050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            "com.android.cellbroadcastreceiver.DATABASE_DELIVERY_TIME";
5150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
5250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private SQLiteDatabase mBroadcastDb;
5350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
5450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /** Callback for the active list activity when the contents change. */
5550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private static CellBroadcastListActivity sActiveListActivity;
5650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
5750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public CellBroadcastDatabaseService() {
5850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        super(TAG);     // use class name for worker thread name
5950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
6050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
6150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    @Override
6250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public void onCreate() {
6350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        super.onCreate();
6450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
6550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (mBroadcastDb == null) {
6650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            CellBroadcastDatabase.DatabaseHelper helper =
6750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    new CellBroadcastDatabase.DatabaseHelper(this);
6850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            mBroadcastDb = helper.getWritableDatabase();
6950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
7050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
7150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
7250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    @Override
7350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public void onDestroy() {
7450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        super.onDestroy();
7550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
7650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (mBroadcastDb != null) {
7750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            mBroadcastDb.close();
7850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            mBroadcastDb = null;
7950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
8050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
8150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
8250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static void setActiveListActivity(CellBroadcastListActivity activity) {
8350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        sActiveListActivity = activity;
8450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
8550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
8650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    @Override
8750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public void onHandleIntent(Intent intent) {
8850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        // TODO: security check to detect malicious broadcast injections
8950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        String action = intent.getAction();
9050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        boolean notifyActiveListActivity = false;
9150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (ACTION_INSERT_NEW_BROADCAST.equals(action)) {
9250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            CellBroadcastMessage cbm = intent.getParcelableExtra(
9350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
9450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (cbm == null) {
9550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "ACTION_INSERT_NEW_BROADCAST with no CB message extra");
9650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                return;
9750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
9850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
9950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            ContentValues cv = cbm.getContentValues();
10050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            long rowId = mBroadcastDb.insert(CellBroadcastDatabase.TABLE_NAME, null, cv);
10150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowId == -1) {
10250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "failed to insert new broadcast into database!");
10350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            } else {
10450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                notifyActiveListActivity = true;
10550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
10650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else if (ACTION_DELETE_BROADCAST.equals(action)) {
10750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            long rowId = intent.getLongExtra(DATABASE_ROW_ID_EXTRA, -1);
10850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowId == -1) {
10950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "ACTION_DELETE_BROADCAST missing row ID to delete");
11050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                return;
11150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
11250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
11350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            int rowCount = mBroadcastDb.delete(CellBroadcastDatabase.TABLE_NAME,
11450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    CellBroadcastDatabase.Columns._ID + "=?",
11550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    new String[]{Long.toString(rowId)});
11650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowCount != 0) {
11750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                notifyActiveListActivity = true;
11850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
11950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else if (ACTION_DELETE_ALL_BROADCASTS.equals(action)) {
12050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            mBroadcastDb.delete(CellBroadcastDatabase.TABLE_NAME, null, null);
12150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            notifyActiveListActivity = true;
12250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else if (ACTION_MARK_BROADCAST_READ.equals(action)) {
12350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            long rowId = intent.getLongExtra(DATABASE_ROW_ID_EXTRA, -1);
12450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            long deliveryTime = intent.getLongExtra(DATABASE_DELIVERY_TIME_EXTRA, -1);
12550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowId == -1 && deliveryTime == -1) {
12650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "ACTION_MARK_BROADCAST_READ missing row ID or delivery time");
12750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                return;
12850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
12950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            ContentValues cv = new ContentValues(1);
13050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            cv.put(CellBroadcastDatabase.Columns.MESSAGE_READ, 1);
13150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            int rowCount;
13250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowId != -1) {
13350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                rowCount = mBroadcastDb.update(CellBroadcastDatabase.TABLE_NAME, cv,
13450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    CellBroadcastDatabase.Columns._ID + "=?",
13550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    new String[]{Long.toString(rowId)});
13650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            } else {
13750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                rowCount = mBroadcastDb.update(CellBroadcastDatabase.TABLE_NAME, cv,
13850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    CellBroadcastDatabase.Columns.DELIVERY_TIME + "=?",
13950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    new String[]{Long.toString(deliveryTime)});
14050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
14150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (rowCount != 0) {
14250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                notifyActiveListActivity = true;
14350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
14450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else {
14550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            Log.e(TAG, "ignoring unexpected Intent with action " + action);
14650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
14750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (notifyActiveListActivity && sActiveListActivity != null) {
14850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            sActiveListActivity.databaseContentChanged();
14950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
15050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
15150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby}
152