1929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee/*
2929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * Copyright (C) 2011 The Android Open Source Project
3929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
4929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee *
5929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * Licensed under the Apache License, Version 2.0 (the "License");
6929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * you may not use this file except in compliance with the License.
7929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * You may obtain a copy of the License at
8929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee *
9929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee *      http://www.apache.org/licenses/LICENSE-2.0
10929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee *
11929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * Unless required by applicable law or agreed to in writing, software
12929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * distributed under the License is distributed on an "AS IS" BASIS,
13929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * See the License for the specific language governing permissions and
15929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * limitations under the License
16929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee */
17929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
18929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeepackage com.android.providers.contacts;
19929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
2098a77ec8057c5fe0ff487ca7d0910312693e5689Debashish Chatterjeeimport static android.Manifest.permission.ADD_VOICEMAIL;
21929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport static com.android.providers.contacts.Manifest.permission.READ_WRITE_ALL_VOICEMAIL;
22929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
2313cb841466fefcd041cd86b7877d000dfe73e8ecDebashish Chatterjeeimport com.android.common.io.MoreCloseables;
24929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
25929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport com.android.providers.contacts.util.DbQueryUtils;
26929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport com.google.android.collect.Lists;
27929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
28929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.ComponentName;
29929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.ContentUris;
30929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.ContentValues;
31929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.Context;
32929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.Intent;
33929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.pm.ActivityInfo;
34929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.content.pm.ResolveInfo;
35929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.database.Cursor;
36929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.database.DatabaseUtils.InsertHelper;
37929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.database.sqlite.SQLiteDatabase;
38929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.net.Uri;
39929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.os.Binder;
402e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjeeimport android.provider.CallLog.Calls;
41929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.provider.VoicemailContract;
42929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.provider.VoicemailContract.Status;
43929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.provider.VoicemailContract.Voicemails;
44929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport android.util.Log;
45929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
46929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport java.util.ArrayList;
47929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport java.util.Collection;
48929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport java.util.HashSet;
49929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport java.util.List;
50929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjeeimport java.util.Set;
51929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
52929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee/**
53929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * An implementation of {@link DatabaseModifier} for voicemail related tables which additionally
54929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee * generates necessary notifications after the modification operation is performed.
552e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee * The class generates notifications for both voicemail as well as call log URI depending on which
562e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee * of then got affected by the change.
57929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee */
582e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjeepublic class DbModifierWithNotification implements DatabaseModifier {
59929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private static final String TAG = "DbModifierWithVmNotification";
60929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
61929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private static final String[] PROJECTION = new String[] {
62929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            VoicemailContract.SOURCE_PACKAGE_FIELD
63929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    };
64929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private static final int SOURCE_PACKAGE_COLUMN_INDEX = 0;
65929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private static final String NON_NULL_SOURCE_PACKAGE_SELECTION =
66929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            VoicemailContract.SOURCE_PACKAGE_FIELD + " IS NOT NULL";
67929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
68929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final String mTableName;
69929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final SQLiteDatabase mDb;
70929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final InsertHelper mInsertHelper;
71929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final Context mContext;
72929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final Uri mBaseUri;
732e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    private final boolean mIsCallsTable;
74929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private final VoicemailPermissions mVoicemailPermissions;
75929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
762e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    public DbModifierWithNotification(String tableName, SQLiteDatabase db, Context context) {
77929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        this(tableName, db, null, context);
78929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
79929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
802e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    public DbModifierWithNotification(String tableName, InsertHelper insertHelper,
81929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            Context context) {
82929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        this(tableName, null, insertHelper, context);
83929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
84929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
852e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    private DbModifierWithNotification(String tableName, SQLiteDatabase db,
86929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            InsertHelper insertHelper, Context context) {
87929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mTableName = tableName;
88929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mDb = db;
89929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mInsertHelper = insertHelper;
90929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mContext = context;
91929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mBaseUri = mTableName.equals(Tables.VOICEMAIL_STATUS) ?
92929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                Status.CONTENT_URI : Voicemails.CONTENT_URI;
932e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        mIsCallsTable = mTableName.equals(Tables.CALLS);
94929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mVoicemailPermissions = new VoicemailPermissions(mContext);
95929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
96929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
97929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    @Override
98929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    public long insert(String table, String nullColumnHack, ContentValues values) {
99929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> packagesModified = getModifiedPackages(values);
100929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        long rowId = mDb.insert(table, nullColumnHack, values);
101929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if (rowId > 0 && packagesModified.size() != 0) {
1022e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChangeOnInsert(ContentUris.withAppendedId(mBaseUri, rowId),
1032e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                    packagesModified);
1042e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        }
1052e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        if (rowId > 0 && mIsCallsTable) {
1062e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyCallLogChange();
107929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
108929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return rowId;
109929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
110929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
111929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    @Override
112929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    public long insert(ContentValues values) {
113929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> packagesModified = getModifiedPackages(values);
114929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        long rowId = mInsertHelper.insert(values);
115929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if (rowId > 0 && packagesModified.size() != 0) {
1162e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChangeOnInsert(
1172e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                    ContentUris.withAppendedId(mBaseUri, rowId), packagesModified);
1182e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        }
1192e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        if (rowId > 0 && mIsCallsTable) {
1202e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyCallLogChange();
121929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
122929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return rowId;
123929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
124929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
1252e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    private void notifyCallLogChange() {
1262e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        mContext.getContentResolver().notifyChange(Calls.CONTENT_URI, null, false);
1272e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    }
1282e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee
1292e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    private void notifyVoicemailChangeOnInsert(Uri notificationUri, Set<String> packagesModified) {
1302e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        if (mIsCallsTable) {
1312e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChange(notificationUri, packagesModified,
1322e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                    VoicemailContract.ACTION_NEW_VOICEMAIL, Intent.ACTION_PROVIDER_CHANGED);
133929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        } else {
1342e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChange(notificationUri, packagesModified,
1352e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                    Intent.ACTION_PROVIDER_CHANGED);
136929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
137929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
138929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
139929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    @Override
140929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
141929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> packagesModified = getModifiedPackages(whereClause, whereArgs);
142929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        packagesModified.addAll(getModifiedPackages(values));
143929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        int count = mDb.update(table, values, whereClause, whereArgs);
144929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if (count > 0 && packagesModified.size() != 0) {
1452e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED);
1462e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        }
1472e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        if (count > 0 && mIsCallsTable) {
1482e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyCallLogChange();
149929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
150929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return count;
151929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
152929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
153929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    @Override
154929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    public int delete(String table, String whereClause, String[] whereArgs) {
155929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> packagesModified = getModifiedPackages(whereClause, whereArgs);
156929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        int count = mDb.delete(table, whereClause, whereArgs);
157929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if (count > 0 && packagesModified.size() != 0) {
1582e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyVoicemailChange(mBaseUri, packagesModified, Intent.ACTION_PROVIDER_CHANGED);
1592e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        }
1602e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        if (count > 0 && mIsCallsTable) {
1612e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee            notifyCallLogChange();
162929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
163929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return count;
164929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
165929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
166929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    /**
167929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * Returns the set of packages affected when a modify operation is run for the specified
168929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * where clause. When called from an insert operation an empty set returned by this method
169929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * implies (indirectly) that this does not affect any voicemail entry, as a voicemail entry is
170929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * always expected to have the source package field set.
171929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     */
172929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private Set<String> getModifiedPackages(String whereClause, String[] whereArgs) {
173929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> modifiedPackages = new HashSet<String>();
174929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Cursor cursor = mDb.query(mTableName, PROJECTION,
175929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                DbQueryUtils.concatenateClauses(NON_NULL_SOURCE_PACKAGE_SELECTION, whereClause),
176929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                whereArgs, null, null, null);
177929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        while(cursor.moveToNext()) {
178929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            modifiedPackages.add(cursor.getString(SOURCE_PACKAGE_COLUMN_INDEX));
179929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
18013cb841466fefcd041cd86b7877d000dfe73e8ecDebashish Chatterjee        MoreCloseables.closeQuietly(cursor);
181929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return modifiedPackages;
182929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
183929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
184929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    /**
185929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * Returns the source package that gets affected (in an insert/update operation) by the supplied
186929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * content values. An empty set returned by this method also implies (indirectly) that this does
187929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * not affect any voicemail entry, as a voicemail entry is always expected to have the source
188929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * package field set.
189929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     */
190929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private Set<String> getModifiedPackages(ContentValues values) {
191929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Set<String> impactedPackages = new HashSet<String>();
192929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if(values.containsKey(VoicemailContract.SOURCE_PACKAGE_FIELD)) {
193929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            impactedPackages.add(values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD));
194929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
195929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return impactedPackages;
196929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
197929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
1982e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    private void notifyVoicemailChange(Uri notificationUri, Set<String> modifiedPackages,
199929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            String... intentActions) {
200929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        // Notify the observers.
201929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        // Must be done only once, even if there are multiple broadcast intents.
202929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        mContext.getContentResolver().notifyChange(notificationUri, null, true);
203929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Collection<String> callingPackages = getCallingPackages();
204929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        // Now fire individual intents.
205929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        for (String intentAction : intentActions) {
206929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            // self_change extra should be included only for provider_changed events.
207929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            boolean includeSelfChangeExtra = intentAction.equals(Intent.ACTION_PROVIDER_CHANGED);
208929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            for (ComponentName component :
209929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                    getBroadcastReceiverComponents(intentAction, notificationUri)) {
2108d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                // Ignore any package that is not affected by the change and don't have full access
2118d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                // either.
2128d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                if (!modifiedPackages.contains(component.getPackageName()) &&
2138d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                        !mVoicemailPermissions.packageHasFullAccess(component.getPackageName())) {
2148d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                    continue;
2158d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee                }
2168d5a094810ce8c60b83e534d903a0d662e621252Debashish Chatterjee
217929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                Intent intent = new Intent(intentAction, notificationUri);
218929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                intent.setComponent(component);
219929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                if (includeSelfChangeExtra && callingPackages != null) {
220929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                    intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE,
221929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                            callingPackages.contains(component.getPackageName()));
222929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                }
223929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                String permissionNeeded = modifiedPackages.contains(component.getPackageName()) ?
22498a77ec8057c5fe0ff487ca7d0910312693e5689Debashish Chatterjee                        ADD_VOICEMAIL : READ_WRITE_ALL_VOICEMAIL;
225929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                mContext.sendBroadcast(intent, permissionNeeded);
226929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                Log.v(TAG, String.format("Sent intent. act:%s, url:%s, comp:%s, perm:%s," +
227929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                        " self_change:%s", intent.getAction(), intent.getData(),
228929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                        component.getClassName(), permissionNeeded,
229929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                        intent.hasExtra(VoicemailContract.EXTRA_SELF_CHANGE) ?
230929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                                intent.getBooleanExtra(VoicemailContract.EXTRA_SELF_CHANGE, false) :
231929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                                        null));
232929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            }
233929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
234929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
235929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
236929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    /** Determines the components that can possibly receive the specified intent. */
237929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private List<ComponentName> getBroadcastReceiverComponents(String intentAction, Uri uri) {
238929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        Intent intent = new Intent(intentAction, uri);
239929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        List<ComponentName> receiverComponents = new ArrayList<ComponentName>();
240929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        // For broadcast receivers ResolveInfo.activityInfo is the one that is populated.
241929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        for (ResolveInfo resolveInfo :
242929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                mContext.getPackageManager().queryBroadcastReceivers(intent, 0)) {
243929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            ActivityInfo activityInfo = resolveInfo.activityInfo;
244929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            receiverComponents.add(new ComponentName(activityInfo.packageName, activityInfo.name));
245929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
246929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return receiverComponents;
247929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
248929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
249929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    /**
250929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * Returns the package names of the calling process. If the calling process has more than
251929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     * one packages, this returns them all
252929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee     */
253929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private Collection<String> getCallingPackages() {
254929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        int caller = Binder.getCallingUid();
255929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        if (caller == 0) {
256929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee            return null;
257929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        }
258929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return Lists.newArrayList(mContext.getPackageManager().getPackagesForUid(caller));
259929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
260929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee}
261