1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16package com.android.providers.contacts;
17
18import com.android.providers.contacts.util.ContactsPermissions;
19
20import android.content.ContentValues;
21import android.content.Context;
22import android.content.Intent;
23import android.content.res.AssetFileDescriptor;
24import android.database.Cursor;
25import android.database.sqlite.SQLiteDatabase;
26import android.net.Uri;
27import android.os.CancellationSignal;
28import android.provider.ContactsContract.Intents;
29
30import java.io.FileDescriptor;
31import java.io.FileNotFoundException;
32import java.io.PrintWriter;
33import java.util.Locale;
34
35/**
36 * Simple content provider to handle directing profile-specific calls against a separate
37 * database from the rest of contacts.
38 */
39public class ProfileProvider extends AbstractContactsProvider {
40    private static final String READ_CONTACTS_PERMISSION = "android.permission.READ_CONTACTS";
41
42    // The Contacts provider handles most of the logic - this provider is only invoked when the
43    // URI belongs to a profile action, setting up the proper database.
44    private final ContactsProvider2 mDelegate;
45
46    public ProfileProvider(ContactsProvider2 delegate) {
47        mDelegate = delegate;
48    }
49
50    @Override
51    protected ProfileDatabaseHelper newDatabaseHelper(Context context) {
52        return ProfileDatabaseHelper.getInstance(context);
53    }
54
55    public ProfileDatabaseHelper getDatabaseHelper() {
56        return (ProfileDatabaseHelper) super.getDatabaseHelper();
57    }
58
59    @Override
60    protected ThreadLocal<ContactsTransaction> getTransactionHolder() {
61        return mDelegate.getTransactionHolder();
62    }
63
64    @Override
65    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
66            String sortOrder) {
67        return query(uri, projection, selection, selectionArgs, sortOrder, null);
68    }
69
70    @Override
71    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
72            String sortOrder, CancellationSignal cancellationSignal) {
73        incrementStats(mQueryStats);
74        try {
75            return mDelegate.queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1,
76                    cancellationSignal);
77        } finally {
78            finishOperation();
79        }
80    }
81
82    @Override
83    protected Uri insertInTransaction(Uri uri, ContentValues values) {
84        useProfileDbForTransaction();
85        return mDelegate.insertInTransaction(uri, values);
86    }
87
88    @Override
89    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
90            String[] selectionArgs) {
91        useProfileDbForTransaction();
92        return mDelegate.updateInTransaction(uri, values, selection, selectionArgs);
93    }
94
95    @Override
96    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
97        useProfileDbForTransaction();
98        return mDelegate.deleteInTransaction(uri, selection, selectionArgs);
99    }
100
101    @Override
102    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
103        return mDelegate.openAssetFileLocal(uri, mode);
104    }
105
106    private void useProfileDbForTransaction() {
107        ContactsTransaction transaction = getCurrentTransaction();
108        SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
109        transaction.startTransactionForDb(db, ContactsProvider2.PROFILE_DB_TAG, this);
110    }
111
112    @Override
113    protected void notifyChange() {
114        mDelegate.notifyChange();
115    }
116
117    protected void notifyChange(boolean syncToNetwork, boolean syncToMetadataNetWork) {
118        mDelegate.notifyChange(syncToNetwork, syncToMetadataNetWork);
119    }
120
121    protected Locale getLocale() {
122        return mDelegate.getLocale();
123    }
124
125    @Override
126    public void onBegin() {
127        mDelegate.onBeginTransactionInternal(true);
128    }
129
130    @Override
131    public void onCommit() {
132        mDelegate.onCommitTransactionInternal(true);
133        sendProfileChangedBroadcast();
134    }
135
136    @Override
137    public void onRollback() {
138        mDelegate.onRollbackTransactionInternal(true);
139    }
140
141    @Override
142    protected boolean yield(ContactsTransaction transaction) {
143        return mDelegate.yield(transaction);
144    }
145
146    @Override
147    public String getType(Uri uri) {
148        return mDelegate.getType(uri);
149    }
150
151    /** Use only for debug logging */
152    @Override
153    public String toString() {
154        return "ProfileProvider";
155    }
156
157    private void sendProfileChangedBroadcast() {
158        final Intent intent = new Intent(Intents.ACTION_PROFILE_CHANGED);
159        mDelegate.getContext().sendBroadcast(intent, READ_CONTACTS_PERMISSION);
160        // TODO b/35323708 update user profile data here instead of notifying Settings
161        intent.setPackage("com.android.settings");
162        mDelegate.getContext().sendBroadcast(intent, READ_CONTACTS_PERMISSION);
163    }
164
165    @Override
166    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
167        dump(pw, "Profile");
168    }
169}
170