1/*
2 * Copyright (C) 2009 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 */
16
17package com.android.providers.contacts;
18
19import android.accounts.Account;
20import android.content.Context;
21import android.database.sqlite.SQLiteDatabase;
22import android.util.Log;
23
24import junit.framework.Assert;
25
26import java.util.Locale;
27
28/**
29 * A version of {@link ContactsProvider2} class that performs aggregation
30 * synchronously and wipes all data at construction time.
31 */
32public class SynchronousContactsProvider2 extends ContactsProvider2 {
33    public static final String READ_ONLY_ACCOUNT_TYPE = "ro";
34
35    private static Boolean sDataWiped = false;
36    private static ContactsDatabaseHelper sDbHelper;
37    private boolean mDataWipeEnabled = true;
38    private Account mAccount;
39    private boolean mNetworkNotified;
40    private boolean mMetadataNetworkNotified;
41    private boolean mIsPhone = true;
42    private boolean mIsVoiceCapable = true;
43
44    @Override
45    public ContactsDatabaseHelper getDatabaseHelper(final Context context) {
46        if (sDbHelper == null) {
47            sDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context);
48        }
49        return sDbHelper;
50    }
51
52    @Override
53    public ProfileProvider newProfileProvider() {
54        return new SynchronousProfileProvider(this);
55    }
56
57    public void setDataWipeEnabled(boolean flag) {
58        mDataWipeEnabled = flag;
59    }
60
61    @Override
62    public void onBegin() {
63        super.onBegin();
64        mNetworkNotified = false;
65        mMetadataNetworkNotified = false;
66    }
67
68    @Override
69    protected void notifyChange(boolean syncToNetwork, boolean syncToMetadataNetwork) {
70        mNetworkNotified |= syncToNetwork;
71        mMetadataNetworkNotified |= syncToMetadataNetwork;
72    }
73
74    public boolean isNetworkNotified() {
75        return mNetworkNotified;
76    }
77
78    public boolean isMetadataNetworkNotified() {
79        return mMetadataNetworkNotified;
80    }
81
82    public void setIsPhone(boolean flag) {
83        mIsPhone = flag;
84    }
85
86    @Override
87    public boolean isPhone() {
88        return mIsPhone;
89    }
90
91    public void setIsVoiceCapable(boolean flag) {
92        mIsVoiceCapable = flag;
93    }
94
95    @Override
96    public boolean isVoiceCapable() {
97        return mIsVoiceCapable;
98    }
99
100    @Override
101    public boolean onCreate() {
102        boolean created = super.onCreate();
103        if (mDataWipeEnabled) {
104            synchronized (sDataWiped) {
105                if (!sDataWiped) {
106                    sDataWiped = true;
107                    wipeData();
108                }
109            }
110        }
111        return created;
112    }
113
114    @Override
115    protected boolean shouldThrowExceptionForInitializationError() {
116        return true;
117    }
118
119    /** We'll use a static size for unit tests */
120    @Override
121    public int getMaxThumbnailDim() {
122        return 96;
123    }
124
125    /** We'll use a static size for unit tests */
126    @Override
127    public int getMaxDisplayPhotoDim() {
128        return 256;
129    }
130
131    @Override
132    protected void scheduleBackgroundTask(int task) {
133        performBackgroundTask(task, null);
134    }
135
136    @Override
137    protected void scheduleBackgroundTask(int task, Object arg) {
138        performBackgroundTask(task, arg);
139    }
140
141    @Override
142    protected void updateLocaleInBackground() {
143    }
144
145    @Override
146    protected void updateDirectoriesInBackground(boolean rescan) {
147    }
148
149    @Override
150    protected Account getDefaultAccount() {
151        if (mAccount == null) {
152            mAccount = new Account("androidtest@gmail.com", "com.google");
153        }
154        return mAccount;
155    }
156
157    @Override
158    protected boolean isContactsAccount(Account account) {
159        return true;
160    }
161
162    /**
163     * Creates a mock PhotoPriorityResolver
164     */
165    @Override
166    PhotoPriorityResolver createPhotoPriorityResolver(Context context) {
167        return new PhotoPriorityResolver(context) {
168            @Override
169            public synchronized int getPhotoPriority(String accountType) {
170                if ("cupcake".equals(accountType)) {
171                    return 3;
172                }
173                if ("donut".equals(accountType)) {
174                    return 2;
175                }
176                if ("froyo".equals(accountType)) {
177                    return 1;
178                }
179                return 0;
180            }
181        };
182    }
183
184    @Override
185    protected Locale getLocale() {
186        return Locale.US;
187    }
188
189    @Override
190    public boolean isWritableAccountWithDataSet(String accountType) {
191        return !READ_ONLY_ACCOUNT_TYPE.equals(accountType);
192    }
193
194    public void prepareForFullAggregation(int maxContact) {
195        SQLiteDatabase db = getDatabaseHelper(getContext()).getWritableDatabase();
196        db.execSQL("UPDATE raw_contacts SET aggregation_mode=0,aggregation_needed=1;");
197        long rowId =
198            db.compileStatement("SELECT _id FROM raw_contacts LIMIT 1 OFFSET " + maxContact)
199                .simpleQueryForLong();
200        db.execSQL("DELETE FROM raw_contacts WHERE _id > " + rowId + ";");
201    }
202
203    public long getRawContactCount() {
204        SQLiteDatabase db = getDatabaseHelper(getContext()).getReadableDatabase();
205        return db.compileStatement("SELECT COUNT(*) FROM raw_contacts").simpleQueryForLong();
206    }
207
208    public long getContactCount() {
209        SQLiteDatabase db = getDatabaseHelper(getContext()).getReadableDatabase();
210        return db.compileStatement("SELECT COUNT(*) FROM contacts").simpleQueryForLong();
211    }
212
213    @Override
214    public void wipeData() {
215        Log.i(TAG, "wipeData");
216        super.wipeData();
217        SQLiteDatabase db = getDatabaseHelper(getContext()).getWritableDatabase();
218        db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('raw_contacts', 42)");
219        db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('contacts', 2009)");
220        db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('data', 777)");
221
222        getContactDirectoryManagerForTest().scanAllPackages();
223    }
224
225    // Flags to remember which transaction callback has been called for which mode.
226    private boolean mOnBeginTransactionInternalCalledInProfileMode;
227    private boolean mOnCommitTransactionInternalCalledInProfileMode;
228    private boolean mOnRollbackTransactionInternalCalledInProfileMode;
229
230    private boolean mOnBeginTransactionInternalCalledInContactMode;
231    private boolean mOnCommitTransactionInternalCalledInContactMode;
232    private boolean mOnRollbackTransactionInternalCalledInContactMode;
233
234    public void resetTrasactionCallbackCalledFlags() {
235        mOnBeginTransactionInternalCalledInProfileMode = false;
236        mOnCommitTransactionInternalCalledInProfileMode = false;
237        mOnRollbackTransactionInternalCalledInProfileMode = false;
238
239        mOnBeginTransactionInternalCalledInContactMode = false;
240        mOnCommitTransactionInternalCalledInContactMode = false;
241        mOnRollbackTransactionInternalCalledInContactMode = false;
242    }
243
244    @Override
245    protected void onBeginTransactionInternal(boolean forProfile) {
246        super.onBeginTransactionInternal(forProfile);
247        if (forProfile) {
248            mOnBeginTransactionInternalCalledInProfileMode = true;
249        } else {
250            mOnBeginTransactionInternalCalledInContactMode = true;
251        }
252    }
253
254    @Override
255    protected void onCommitTransactionInternal(boolean forProfile) {
256        super.onCommitTransactionInternal(forProfile);
257        if (forProfile) {
258            mOnCommitTransactionInternalCalledInProfileMode = true;
259        } else {
260            mOnCommitTransactionInternalCalledInContactMode = true;
261        }
262    }
263
264    @Override
265    protected void onRollbackTransactionInternal(boolean forProfile) {
266        super.onRollbackTransactionInternal(forProfile);
267        if (forProfile) {
268            mOnRollbackTransactionInternalCalledInProfileMode = true;
269        } else {
270            mOnRollbackTransactionInternalCalledInContactMode = true;
271        }
272    }
273
274    public void assertCommitTransactionCalledForProfileMode() {
275        Assert.assertTrue("begin", mOnBeginTransactionInternalCalledInProfileMode);
276        Assert.assertTrue("commit", mOnCommitTransactionInternalCalledInProfileMode);
277        Assert.assertFalse("rollback", mOnRollbackTransactionInternalCalledInProfileMode);
278    }
279
280    public void assertRollbackTransactionCalledForProfileMode() {
281        Assert.assertTrue("begin", mOnBeginTransactionInternalCalledInProfileMode);
282        Assert.assertFalse("commit", mOnCommitTransactionInternalCalledInProfileMode);
283        Assert.assertTrue("rollback", mOnRollbackTransactionInternalCalledInProfileMode);
284    }
285
286    public void assertNoTransactionsForProfileMode() {
287        Assert.assertFalse("begin", mOnBeginTransactionInternalCalledInProfileMode);
288        Assert.assertFalse("commit", mOnCommitTransactionInternalCalledInProfileMode);
289        Assert.assertFalse("rollback", mOnRollbackTransactionInternalCalledInProfileMode);
290    }
291
292
293    public void assertCommitTransactionCalledForContactMode() {
294        Assert.assertTrue("begin", mOnBeginTransactionInternalCalledInContactMode);
295        Assert.assertTrue("commit", mOnCommitTransactionInternalCalledInContactMode);
296        Assert.assertFalse("rollback", mOnRollbackTransactionInternalCalledInContactMode);
297    }
298
299    public void assertRollbackTransactionCalledForContactMode() {
300        Assert.assertTrue("begin", mOnBeginTransactionInternalCalledInContactMode);
301        Assert.assertFalse("commit", mOnCommitTransactionInternalCalledInContactMode);
302        Assert.assertTrue("rollback", mOnRollbackTransactionInternalCalledInContactMode);
303    }
304}
305