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