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