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 mIsPhone = true;
41     private boolean mIsVoiceCapable = true;
42 
43     @Override
getDatabaseHelper(final Context context)44     protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
45         if (sDbHelper == null) {
46             sDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context);
47         }
48         return sDbHelper;
49     }
50 
51     @Override
newProfileProvider()52     public ProfileProvider newProfileProvider() {
53         return new SynchronousProfileProvider(this);
54     }
55 
setDataWipeEnabled(boolean flag)56     public void setDataWipeEnabled(boolean flag) {
57         mDataWipeEnabled = flag;
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         if (mDataWipeEnabled) {
97             synchronized (sDataWiped) {
98                 if (!sDataWiped) {
99                     sDataWiped = true;
100                     wipeData();
101                 }
102             }
103         }
104         return created;
105     }
106 
107     @Override
shouldThrowExceptionForInitializationError()108     protected boolean shouldThrowExceptionForInitializationError() {
109         return true;
110     }
111 
112     /** We'll use a static size for unit tests */
113     @Override
getMaxThumbnailDim()114     public int getMaxThumbnailDim() {
115         return 96;
116     }
117 
118     /** We'll use a static size for unit tests */
119     @Override
getMaxDisplayPhotoDim()120     public int getMaxDisplayPhotoDim() {
121         return 256;
122     }
123 
124     @Override
scheduleBackgroundTask(int task)125     protected void scheduleBackgroundTask(int task) {
126         performBackgroundTask(task, null);
127     }
128 
129     @Override
scheduleBackgroundTask(int task, Object arg)130     protected void scheduleBackgroundTask(int task, Object arg) {
131         performBackgroundTask(task, arg);
132     }
133 
134     @Override
updateLocaleInBackground()135     protected void updateLocaleInBackground() {
136     }
137 
138     @Override
updateDirectoriesInBackground(boolean rescan)139     protected void updateDirectoriesInBackground(boolean rescan) {
140     }
141 
142     @Override
getDefaultAccount()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
isContactsAccount(Account account)151     protected boolean isContactsAccount(Account account) {
152         return true;
153     }
154 
155     /**
156      * Creates a mock PhotoPriorityResolver
157      */
158     @Override
createPhotoPriorityResolver(Context context)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