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 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
getDatabaseHelper(final Context context)45     public ContactsDatabaseHelper getDatabaseHelper(final Context context) {
46         if (sDbHelper == null) {
47             sDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context);
48         }
49         return sDbHelper;
50     }
51 
52     @Override
newProfileProvider()53     public ProfileProvider newProfileProvider() {
54         return new SynchronousProfileProvider(this);
55     }
56 
setDataWipeEnabled(boolean flag)57     public void setDataWipeEnabled(boolean flag) {
58         mDataWipeEnabled = flag;
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         if (mDataWipeEnabled) {
104             synchronized (sDataWiped) {
105                 if (!sDataWiped) {
106                     sDataWiped = true;
107                     wipeData();
108                 }
109             }
110         }
111         return created;
112     }
113 
114     @Override
shouldThrowExceptionForInitializationError()115     protected boolean shouldThrowExceptionForInitializationError() {
116         return true;
117     }
118 
119     /** We'll use a static size for unit tests */
120     @Override
getMaxThumbnailDim()121     public int getMaxThumbnailDim() {
122         return 96;
123     }
124 
125     /** We'll use a static size for unit tests */
126     @Override
getMaxDisplayPhotoDim()127     public int getMaxDisplayPhotoDim() {
128         return 256;
129     }
130 
131     @Override
scheduleBackgroundTask(int task)132     protected void scheduleBackgroundTask(int task) {
133         performBackgroundTask(task, null);
134     }
135 
136     @Override
scheduleBackgroundTask(int task, Object arg)137     protected void scheduleBackgroundTask(int task, Object arg) {
138         performBackgroundTask(task, arg);
139     }
140 
141     @Override
updateLocaleInBackground()142     protected void updateLocaleInBackground() {
143     }
144 
145     @Override
updateDirectoriesInBackground(boolean rescan)146     protected void updateDirectoriesInBackground(boolean rescan) {
147     }
148 
149     @Override
getDefaultAccount()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
isContactsAccount(Account account)158     protected boolean isContactsAccount(Account account) {
159         return true;
160     }
161 
162     /**
163      * Creates a mock PhotoPriorityResolver
164      */
165     @Override
createPhotoPriorityResolver(Context context)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