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