- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / profile_sync_service_android.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/sync/profile_sync_service_android.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/bind.h"
10 #include "base/i18n/time_formatting.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/signin/signin_manager.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/sync/about_sync_util.h"
23 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/browser/sync/sync_prefs.h"
26 #include "chrome/browser/sync/sync_ui_util.h"
27 #include "chrome/common/pref_names.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_source.h"
30 #include "google/cacheinvalidation/types.pb.h"
31 #include "google_apis/gaia/gaia_constants.h"
32 #include "google_apis/gaia/google_service_auth_error.h"
33 #include "grit/generated_resources.h"
34 #include "jni/ProfileSyncService_jni.h"
35 #include "sync/internal_api/public/read_transaction.h"
36 #include "ui/base/l10n/l10n_util.h"
37
38 using base::android::AttachCurrentThread;
39 using base::android::CheckException;
40 using base::android::ConvertJavaStringToUTF8;
41 using base::android::ConvertUTF8ToJavaString;
42 using base::android::ScopedJavaLocalRef;
43 using content::BrowserThread;
44
45 namespace {
46
47 enum {
48 #define DEFINE_MODEL_TYPE_SELECTION(name,value)  name = value,
49 #include "chrome/browser/sync/profile_sync_service_model_type_selection_android.h"
50 #undef DEFINE_MODEL_TYPE_SELECTION
51 };
52
53 }  // namespace
54
55 ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv* env, jobject obj)
56     : profile_(NULL),
57       sync_service_(NULL),
58       weak_java_profile_sync_service_(env, obj) {
59   if (g_browser_process == NULL ||
60       g_browser_process->profile_manager() == NULL) {
61     NOTREACHED() << "Browser process or profile manager not initialized";
62     return;
63   }
64
65   profile_ = g_browser_process->profile_manager()->GetDefaultProfile();
66   if (profile_ == NULL) {
67     NOTREACHED() << "Sync Init: Profile not found.";
68     return;
69   }
70
71   sync_prefs_.reset(new browser_sync::SyncPrefs(profile_->GetPrefs()));
72
73   sync_service_ =
74       ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_);
75   DCHECK(sync_service_);
76 }
77
78 void ProfileSyncServiceAndroid::Init() {
79   sync_service_->AddObserver(this);
80 }
81
82 void ProfileSyncServiceAndroid::RemoveObserver() {
83   if (sync_service_->HasObserver(this)) {
84     sync_service_->RemoveObserver(this);
85   }
86 }
87
88 ProfileSyncServiceAndroid::~ProfileSyncServiceAndroid() {
89   RemoveObserver();
90 }
91
92 void ProfileSyncServiceAndroid::SendNudgeNotification(
93     int object_source,
94     const std::string& str_object_id,
95     int64 version,
96     const std::string& state) {
97   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98
99   // TODO(nileshagrawal): Merge this with ChromeInvalidationClient::Invalidate.
100   // Construct the ModelTypeStateMap and send it over with the notification.
101   invalidation::ObjectId object_id(
102       object_source,
103       str_object_id);
104   syncer::ObjectIdInvalidationMap object_ids_with_states;
105   if (version == ipc::invalidation::Constants::UNKNOWN) {
106     object_ids_with_states.Insert(
107         syncer::Invalidation::InitUnknownVersion(object_id));
108   } else {
109     ObjectIdVersionMap::iterator it =
110         max_invalidation_versions_.find(object_id);
111     if ((it != max_invalidation_versions_.end()) &&
112         (version <= it->second)) {
113       DVLOG(1) << "Dropping redundant invalidation with version " << version;
114       return;
115     }
116     max_invalidation_versions_[object_id] = version;
117     object_ids_with_states.Insert(
118         syncer::Invalidation::Init(object_id, version, state));
119   }
120
121   content::NotificationService::current()->Notify(
122       chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
123       content::Source<Profile>(profile_),
124       content::Details<const syncer::ObjectIdInvalidationMap>(
125           &object_ids_with_states));
126 }
127
128 void ProfileSyncServiceAndroid::OnStateChanged() {
129   // Notify the java world that our sync state has changed.
130   JNIEnv* env = AttachCurrentThread();
131   Java_ProfileSyncService_syncStateChanged(
132       env, weak_java_profile_sync_service_.get(env).obj());
133 }
134
135 void ProfileSyncServiceAndroid::EnableSync(JNIEnv* env, jobject) {
136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137   // Don't need to do anything if we're already enabled.
138   if (sync_prefs_->IsStartSuppressed())
139     sync_service_->UnsuppressAndStart();
140   else
141     DVLOG(2) << "Ignoring call to EnableSync() because sync is already enabled";
142 }
143
144 void ProfileSyncServiceAndroid::DisableSync(JNIEnv* env, jobject) {
145   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
146   // Don't need to do anything if we're already disabled.
147   if (!sync_prefs_->IsStartSuppressed()) {
148     sync_service_->StopAndSuppress();
149   } else {
150     DVLOG(2)
151         << "Ignoring call to DisableSync() because sync is already disabled";
152   }
153 }
154
155 void ProfileSyncServiceAndroid::SignInSync(JNIEnv* env, jobject) {
156   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157   // Just return if sync already has everything it needs to start up (sync
158   // should start up automatically as long as it has credentials). This can
159   // happen normally if (for example) the user closes and reopens the sync
160   // settings window quickly during initial startup.
161   if (sync_service_->IsSyncEnabledAndLoggedIn() &&
162       sync_service_->IsOAuthRefreshTokenAvailable() &&
163       sync_service_->HasSyncSetupCompleted()) {
164     return;
165   }
166
167   // Enable sync (if we don't have credentials yet, this will enable sync but
168   // will not start it up - sync will start once credentials arrive).
169   sync_service_->UnsuppressAndStart();
170 }
171
172 void ProfileSyncServiceAndroid::SignOutSync(JNIEnv* env, jobject) {
173   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174   DCHECK(profile_);
175   sync_service_->DisableForUser();
176
177   // Need to clear suppress start flag manually
178   sync_prefs_->SetStartSuppressed(false);
179 }
180
181 ScopedJavaLocalRef<jstring> ProfileSyncServiceAndroid::QuerySyncStatusSummary(
182     JNIEnv* env, jobject) {
183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184   DCHECK(profile_);
185   std::string status(sync_service_->QuerySyncStatusSummaryString());
186   return ConvertUTF8ToJavaString(env, status);
187 }
188
189 jboolean ProfileSyncServiceAndroid::SetSyncSessionsId(
190     JNIEnv* env, jobject obj, jstring tag) {
191   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192   DCHECK(profile_);
193   std::string machine_tag = ConvertJavaStringToUTF8(env, tag);
194   sync_prefs_->SetSyncSessionsGUID(machine_tag);
195   return true;
196 }
197
198 jint ProfileSyncServiceAndroid::GetAuthError(JNIEnv* env, jobject) {
199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200   return sync_service_->GetAuthError().state();
201 }
202
203 jboolean ProfileSyncServiceAndroid::IsEncryptEverythingEnabled(
204     JNIEnv* env, jobject) {
205   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206   return sync_service_->EncryptEverythingEnabled();
207 }
208
209 jboolean ProfileSyncServiceAndroid::IsSyncInitialized(JNIEnv* env, jobject) {
210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211   return sync_service_->sync_initialized();
212 }
213
214 jboolean ProfileSyncServiceAndroid::IsFirstSetupInProgress(
215     JNIEnv* env, jobject) {
216   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217   return sync_service_->FirstSetupInProgress();
218 }
219
220 jboolean ProfileSyncServiceAndroid::IsPassphraseRequired(JNIEnv* env, jobject) {
221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222   return sync_service_->IsPassphraseRequired();
223 }
224
225 jboolean ProfileSyncServiceAndroid::IsPassphraseRequiredForDecryption(
226     JNIEnv* env, jobject obj) {
227   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228   // In case of CUSTOM_PASSPHRASE we always sync passwords. Prompt the user for
229   // a passphrase if cryptographer has any pending keys.
230   if (sync_service_->GetPassphraseType() == syncer::CUSTOM_PASSPHRASE) {
231     return !IsCryptographerReady(env, obj);
232   }
233   if (sync_service_->IsPassphraseRequiredForDecryption()) {
234     // Passwords datatype should never prompt for a passphrase, except when
235     // user is using a custom passphrase. Do not prompt for a passphrase if
236     // passwords are the only encrypted datatype. This prevents a temporary
237     // notification for passphrase  when PSS has not completed configuring
238     // DataTypeManager, after configuration password datatype shall be disabled.
239     const syncer::ModelTypeSet encrypted_types =
240         sync_service_->GetEncryptedDataTypes();
241     return !encrypted_types.Equals(syncer::ModelTypeSet(syncer::PASSWORDS));
242   }
243   return false;
244 }
245
246 jboolean ProfileSyncServiceAndroid::IsPassphraseRequiredForExternalType(
247     JNIEnv* env, jobject) {
248   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249   return
250       sync_service_->passphrase_required_reason() == syncer::REASON_DECRYPTION;
251 }
252
253 jboolean ProfileSyncServiceAndroid::IsUsingSecondaryPassphrase(
254     JNIEnv* env, jobject) {
255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256   return sync_service_->IsUsingSecondaryPassphrase();
257 }
258
259 jboolean ProfileSyncServiceAndroid::SetDecryptionPassphrase(
260     JNIEnv* env, jobject obj, jstring passphrase) {
261   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262   std::string key = ConvertJavaStringToUTF8(env, passphrase);
263   return sync_service_->SetDecryptionPassphrase(key);
264 }
265
266 void ProfileSyncServiceAndroid::SetEncryptionPassphrase(
267     JNIEnv* env, jobject obj, jstring passphrase, jboolean is_gaia) {
268   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
269   std::string key = ConvertJavaStringToUTF8(env, passphrase);
270   sync_service_->SetEncryptionPassphrase(
271       key,
272       is_gaia ? ProfileSyncService::IMPLICIT : ProfileSyncService::EXPLICIT);
273 }
274
275 jboolean ProfileSyncServiceAndroid::IsCryptographerReady(JNIEnv* env, jobject) {
276   syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
277   return sync_service_->IsCryptographerReady(&trans);
278 }
279
280 jint ProfileSyncServiceAndroid::GetPassphraseType(JNIEnv* env, jobject) {
281   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282   return sync_service_->GetPassphraseType();
283 }
284
285 jboolean ProfileSyncServiceAndroid::HasExplicitPassphraseTime(
286     JNIEnv* env, jobject) {
287   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
289   return !passphrase_time.is_null();
290 }
291
292 ScopedJavaLocalRef<jstring>
293     ProfileSyncServiceAndroid::GetSyncEnterGooglePassphraseBodyWithDateText(
294         JNIEnv* env, jobject) {
295   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
296   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
297   string16 passphrase_time_str = base::TimeFormatShortDate(passphrase_time);
298   return base::android::ConvertUTF16ToJavaString(env,
299       l10n_util::GetStringFUTF16(
300         IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY_WITH_DATE,
301         passphrase_time_str));
302 }
303
304 ScopedJavaLocalRef<jstring>
305     ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyWithDateText(
306         JNIEnv* env, jobject) {
307   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
309   string16 passphrase_time_str = base::TimeFormatShortDate(passphrase_time);
310   return base::android::ConvertUTF16ToJavaString(env,
311       l10n_util::GetStringFUTF16(IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE,
312         passphrase_time_str));
313 }
314
315 ScopedJavaLocalRef<jstring>
316     ProfileSyncServiceAndroid::GetCurrentSignedInAccountText(
317         JNIEnv* env, jobject) {
318   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319   const std::string& sync_username =
320       SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername();
321   return base::android::ConvertUTF16ToJavaString(env,
322       l10n_util::GetStringFUTF16(
323           IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
324           ASCIIToUTF16(sync_username)));
325 }
326
327 ScopedJavaLocalRef<jstring>
328     ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyText(
329         JNIEnv* env, jobject) {
330   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331   return ConvertUTF8ToJavaString(
332       env, l10n_util::GetStringUTF8(IDS_SYNC_ENTER_PASSPHRASE_BODY));
333 }
334
335 jboolean ProfileSyncServiceAndroid::IsSyncKeystoreMigrationDone(
336       JNIEnv* env, jobject) {
337   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338   syncer::SyncStatus status;
339   bool is_status_valid = sync_service_->QueryDetailedSyncStatus(&status);
340   return is_status_valid && !status.keystore_migration_time.is_null();
341 }
342
343 jlong ProfileSyncServiceAndroid::GetEnabledDataTypes(JNIEnv* env,
344                                                      jobject obj) {
345   jlong model_type_selection = 0;
346   syncer::ModelTypeSet types = sync_service_->GetActiveDataTypes();
347   types.PutAll(syncer::ControlTypes());
348   if (types.Has(syncer::BOOKMARKS)) {
349     model_type_selection |= BOOKMARK;
350   }
351   if (types.Has(syncer::AUTOFILL)) {
352     model_type_selection |= AUTOFILL;
353   }
354   if (types.Has(syncer::AUTOFILL_PROFILE)) {
355     model_type_selection |= AUTOFILL_PROFILE;
356   }
357   if (types.Has(syncer::PASSWORDS)) {
358     model_type_selection |= PASSWORD;
359   }
360   if (types.Has(syncer::TYPED_URLS)) {
361     model_type_selection |= TYPED_URL;
362   }
363   if (types.Has(syncer::SESSIONS)) {
364     model_type_selection |= SESSION;
365   }
366   if (types.Has(syncer::HISTORY_DELETE_DIRECTIVES)) {
367     model_type_selection |= HISTORY_DELETE_DIRECTIVE;
368   }
369   if (types.Has(syncer::PROXY_TABS)) {
370     model_type_selection |= PROXY_TABS;
371   }
372   if (types.Has(syncer::FAVICON_IMAGES)) {
373     model_type_selection |= FAVICON_IMAGE;
374   }
375   if (types.Has(syncer::FAVICON_TRACKING)) {
376     model_type_selection |= FAVICON_TRACKING;
377   }
378   if (types.Has(syncer::DEVICE_INFO)) {
379     model_type_selection |= DEVICE_INFO;
380   }
381   if (types.Has(syncer::NIGORI)) {
382     model_type_selection |= NIGORI;
383   }
384   if (types.Has(syncer::EXPERIMENTS)) {
385     model_type_selection |= EXPERIMENTS;
386   }
387   return model_type_selection;
388 }
389
390 void ProfileSyncServiceAndroid::SetPreferredDataTypes(
391     JNIEnv* env, jobject obj,
392     jboolean sync_everything,
393     jlong model_type_selection) {
394   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
395   syncer::ModelTypeSet types;
396   // Note: only user selectable types should be included here.
397   if (model_type_selection & AUTOFILL)
398     types.Put(syncer::AUTOFILL);
399   if (model_type_selection & BOOKMARK)
400     types.Put(syncer::BOOKMARKS);
401   if (model_type_selection & PASSWORD)
402     types.Put(syncer::PASSWORDS);
403   if (model_type_selection & PROXY_TABS)
404     types.Put(syncer::PROXY_TABS);
405   if (model_type_selection & TYPED_URL)
406     types.Put(syncer::TYPED_URLS);
407   DCHECK(syncer::UserSelectableTypes().HasAll(types));
408   sync_service_->OnUserChoseDatatypes(sync_everything, types);
409 }
410
411 void ProfileSyncServiceAndroid::SetSetupInProgress(
412     JNIEnv* env, jobject obj, jboolean in_progress) {
413   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414   sync_service_->SetSetupInProgress(in_progress);
415 }
416
417 void ProfileSyncServiceAndroid::SetSyncSetupCompleted(
418     JNIEnv* env, jobject obj) {
419   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420   sync_service_->SetSyncSetupCompleted();
421 }
422
423 jboolean ProfileSyncServiceAndroid::HasSyncSetupCompleted(
424     JNIEnv* env, jobject obj) {
425   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
426   return sync_service_->HasSyncSetupCompleted();
427 }
428
429 jboolean ProfileSyncServiceAndroid::IsStartSuppressed(
430     JNIEnv* env, jobject obj) {
431   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432   return sync_prefs_->IsStartSuppressed();
433 }
434
435 void ProfileSyncServiceAndroid::EnableEncryptEverything(
436     JNIEnv* env, jobject obj) {
437   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
438   sync_service_->EnableEncryptEverything();
439 }
440
441 jboolean ProfileSyncServiceAndroid::HasKeepEverythingSynced(
442     JNIEnv* env, jobject) {
443   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444   return sync_prefs_->HasKeepEverythingSynced();
445 }
446
447 jboolean ProfileSyncServiceAndroid::HasUnrecoverableError(
448     JNIEnv* env, jobject) {
449   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450   return sync_service_->HasUnrecoverableError();
451 }
452
453 ScopedJavaLocalRef<jstring> ProfileSyncServiceAndroid::GetAboutInfoForTest(
454     JNIEnv* env, jobject) {
455   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
456
457   scoped_ptr<DictionaryValue> about_info =
458       sync_ui_util::ConstructAboutInformation(sync_service_);
459   std::string about_info_json;
460   base::JSONWriter::Write(about_info.get(), &about_info_json);
461
462   return ConvertUTF8ToJavaString(env, about_info_json);
463 }
464
465 jlong ProfileSyncServiceAndroid::GetLastSyncedTimeForTest(
466     JNIEnv* env, jobject obj) {
467   // Use profile preferences here instead of SyncPrefs to avoid an extra
468   // conversion, since SyncPrefs::GetLastSyncedTime() converts the stored value
469   // to to base::Time.
470   return static_cast<jlong>(
471       profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
472 }
473
474 void ProfileSyncServiceAndroid::NudgeSyncer(JNIEnv* env,
475                                             jobject obj,
476                                             jint objectSource,
477                                             jstring objectId,
478                                             jlong version,
479                                             jstring state) {
480   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
481   SendNudgeNotification(objectSource, ConvertJavaStringToUTF8(env, objectId),
482                         version, ConvertJavaStringToUTF8(env, state));
483 }
484
485 void ProfileSyncServiceAndroid::NudgeSyncerForAllTypes(JNIEnv* env,
486                                                        jobject obj) {
487   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
488   syncer::ObjectIdInvalidationMap object_ids_with_states;
489   content::NotificationService::current()->Notify(
490         chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
491         content::Source<Profile>(profile_),
492         content::Details<const syncer::ObjectIdInvalidationMap>(
493             &object_ids_with_states));
494 }
495
496 // static
497 ProfileSyncServiceAndroid*
498     ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid() {
499   return reinterpret_cast<ProfileSyncServiceAndroid*>(
500           Java_ProfileSyncService_getProfileSyncServiceAndroid(
501       AttachCurrentThread(), base::android::GetApplicationContext()));
502 }
503
504 static int Init(JNIEnv* env, jobject obj) {
505   ProfileSyncServiceAndroid* profile_sync_service_android =
506       new ProfileSyncServiceAndroid(env, obj);
507   profile_sync_service_android->Init();
508   return reinterpret_cast<jint>(profile_sync_service_android);
509 }
510
511 // static
512 bool ProfileSyncServiceAndroid::Register(JNIEnv* env) {
513   return RegisterNativesImpl(env);
514 }