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