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.
5 #include "chrome/browser/sync/profile_sync_service_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.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/profiles/profile_manager.h"
19 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/browser/sync/about_sync_util.h"
21 #include "chrome/browser/sync/profile_sync_service.h"
22 #include "chrome/browser/sync/profile_sync_service_factory.h"
23 #include "chrome/browser/sync/sync_ui_util.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/sync_driver/pref_names.h"
27 #include "components/sync_driver/sync_prefs.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "google/cacheinvalidation/types.pb.h"
30 #include "google_apis/gaia/gaia_constants.h"
31 #include "google_apis/gaia/google_service_auth_error.h"
32 #include "jni/ProfileSyncService_jni.h"
33 #include "sync/internal_api/public/network_resources.h"
34 #include "sync/internal_api/public/read_transaction.h"
35 #include "ui/base/l10n/l10n_util.h"
37 using base::android::AttachCurrentThread
;
38 using base::android::CheckException
;
39 using base::android::ConvertJavaStringToUTF8
;
40 using base::android::ConvertUTF8ToJavaString
;
41 using base::android::ScopedJavaLocalRef
;
42 using content::BrowserThread
;
47 #define DEFINE_MODEL_TYPE_SELECTION(name,value) name = value,
48 #include "chrome/browser/sync/profile_sync_service_model_type_selection_android.h"
49 #undef DEFINE_MODEL_TYPE_SELECTION
54 ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv
* env
, jobject obj
)
57 weak_java_profile_sync_service_(env
, obj
) {
58 if (g_browser_process
== NULL
||
59 g_browser_process
->profile_manager() == NULL
) {
60 NOTREACHED() << "Browser process or profile manager not initialized";
64 profile_
= ProfileManager::GetActiveUserProfile();
65 if (profile_
== NULL
) {
66 NOTREACHED() << "Sync Init: Profile not found.";
70 sync_prefs_
.reset(new sync_driver::SyncPrefs(profile_
->GetPrefs()));
73 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_
);
74 DCHECK(sync_service_
);
77 void ProfileSyncServiceAndroid::Init() {
78 sync_service_
->AddObserver(this);
81 void ProfileSyncServiceAndroid::RemoveObserver() {
82 if (sync_service_
->HasObserver(this)) {
83 sync_service_
->RemoveObserver(this);
87 ProfileSyncServiceAndroid::~ProfileSyncServiceAndroid() {
91 void ProfileSyncServiceAndroid::OnStateChanged() {
92 // Notify the java world that our sync state has changed.
93 JNIEnv
* env
= AttachCurrentThread();
94 Java_ProfileSyncService_syncStateChanged(
95 env
, weak_java_profile_sync_service_
.get(env
).obj());
98 void ProfileSyncServiceAndroid::EnableSync(JNIEnv
* env
, jobject
) {
99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
100 // Don't need to do anything if we're already enabled.
101 if (sync_prefs_
->IsStartSuppressed())
102 sync_service_
->UnsuppressAndStart();
104 DVLOG(2) << "Ignoring call to EnableSync() because sync is already enabled";
107 void ProfileSyncServiceAndroid::DisableSync(JNIEnv
* env
, jobject
) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
109 // Don't need to do anything if we're already disabled.
110 if (!sync_prefs_
->IsStartSuppressed()) {
111 sync_service_
->StopAndSuppress();
114 << "Ignoring call to DisableSync() because sync is already disabled";
118 void ProfileSyncServiceAndroid::SignInSync(JNIEnv
* env
, jobject
) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
120 // Just return if sync already has everything it needs to start up (sync
121 // should start up automatically as long as it has credentials). This can
122 // happen normally if (for example) the user closes and reopens the sync
123 // settings window quickly during initial startup.
124 if (sync_service_
->IsSyncEnabledAndLoggedIn() &&
125 sync_service_
->IsOAuthRefreshTokenAvailable() &&
126 sync_service_
->HasSyncSetupCompleted()) {
130 // Enable sync (if we don't have credentials yet, this will enable sync but
131 // will not start it up - sync will start once credentials arrive).
132 sync_service_
->UnsuppressAndStart();
135 void ProfileSyncServiceAndroid::SignOutSync(JNIEnv
* env
, jobject
) {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
138 sync_service_
->DisableForUser();
140 // Need to clear suppress start flag manually
141 sync_prefs_
->SetStartSuppressed(false);
144 void ProfileSyncServiceAndroid::FlushDirectory(JNIEnv
* env
, jobject
) {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
146 sync_service_
->FlushDirectory();
149 ScopedJavaLocalRef
<jstring
> ProfileSyncServiceAndroid::QuerySyncStatusSummary(
150 JNIEnv
* env
, jobject
) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
153 std::string
status(sync_service_
->QuerySyncStatusSummaryString());
154 return ConvertUTF8ToJavaString(env
, status
);
157 jboolean
ProfileSyncServiceAndroid::SetSyncSessionsId(
158 JNIEnv
* env
, jobject obj
, jstring tag
) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
161 std::string machine_tag
= ConvertJavaStringToUTF8(env
, tag
);
162 sync_prefs_
->SetSyncSessionsGUID(machine_tag
);
166 jint
ProfileSyncServiceAndroid::GetAuthError(JNIEnv
* env
, jobject
) {
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
168 return sync_service_
->GetAuthError().state();
171 jboolean
ProfileSyncServiceAndroid::IsEncryptEverythingEnabled(
172 JNIEnv
* env
, jobject
) {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
174 return sync_service_
->EncryptEverythingEnabled();
177 jboolean
ProfileSyncServiceAndroid::IsSyncInitialized(JNIEnv
* env
, jobject
) {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
179 return sync_service_
->SyncActive();
182 jboolean
ProfileSyncServiceAndroid::IsFirstSetupInProgress(
183 JNIEnv
* env
, jobject
) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
185 return sync_service_
->FirstSetupInProgress();
188 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequired(JNIEnv
* env
, jobject
) {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
190 return sync_service_
->IsPassphraseRequired();
193 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequiredForDecryption(
194 JNIEnv
* env
, jobject obj
) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
196 // In case of CUSTOM_PASSPHRASE we always sync passwords. Prompt the user for
197 // a passphrase if cryptographer has any pending keys.
198 if (sync_service_
->GetPassphraseType() == syncer::CUSTOM_PASSPHRASE
) {
199 return !IsCryptographerReady(env
, obj
);
201 if (sync_service_
->IsPassphraseRequiredForDecryption()) {
202 // Passwords datatype should never prompt for a passphrase, except when
203 // user is using a custom passphrase. Do not prompt for a passphrase if
204 // passwords are the only encrypted datatype. This prevents a temporary
205 // notification for passphrase when PSS has not completed configuring
206 // DataTypeManager, after configuration password datatype shall be disabled.
207 const syncer::ModelTypeSet encrypted_types
=
208 sync_service_
->GetEncryptedDataTypes();
209 return !encrypted_types
.Equals(syncer::ModelTypeSet(syncer::PASSWORDS
));
214 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequiredForExternalType(
215 JNIEnv
* env
, jobject
) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
218 sync_service_
->passphrase_required_reason() == syncer::REASON_DECRYPTION
;
221 jboolean
ProfileSyncServiceAndroid::IsUsingSecondaryPassphrase(
222 JNIEnv
* env
, jobject
) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
224 return sync_service_
->IsUsingSecondaryPassphrase();
227 jboolean
ProfileSyncServiceAndroid::SetDecryptionPassphrase(
228 JNIEnv
* env
, jobject obj
, jstring passphrase
) {
229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
230 std::string key
= ConvertJavaStringToUTF8(env
, passphrase
);
231 return sync_service_
->SetDecryptionPassphrase(key
);
234 void ProfileSyncServiceAndroid::SetEncryptionPassphrase(
235 JNIEnv
* env
, jobject obj
, jstring passphrase
, jboolean is_gaia
) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
237 std::string key
= ConvertJavaStringToUTF8(env
, passphrase
);
238 sync_service_
->SetEncryptionPassphrase(
240 is_gaia
? ProfileSyncService::IMPLICIT
: ProfileSyncService::EXPLICIT
);
243 jboolean
ProfileSyncServiceAndroid::IsCryptographerReady(JNIEnv
* env
, jobject
) {
244 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
245 return sync_service_
->IsCryptographerReady(&trans
);
248 jint
ProfileSyncServiceAndroid::GetPassphraseType(JNIEnv
* env
, jobject
) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
250 return sync_service_
->GetPassphraseType();
253 jboolean
ProfileSyncServiceAndroid::HasExplicitPassphraseTime(
254 JNIEnv
* env
, jobject
) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
256 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
257 return !passphrase_time
.is_null();
260 jlong
ProfileSyncServiceAndroid::GetExplicitPassphraseTime(
261 JNIEnv
* env
, jobject
) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
263 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
264 return passphrase_time
.ToJavaTime();
267 ScopedJavaLocalRef
<jstring
>
268 ProfileSyncServiceAndroid::GetSyncEnterGooglePassphraseBodyWithDateText(
269 JNIEnv
* env
, jobject
) {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
271 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
272 base::string16 passphrase_time_str
=
273 base::TimeFormatShortDate(passphrase_time
);
274 return base::android::ConvertUTF16ToJavaString(env
,
275 l10n_util::GetStringFUTF16(
276 IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY_WITH_DATE
,
277 passphrase_time_str
));
280 ScopedJavaLocalRef
<jstring
>
281 ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyWithDateText(
282 JNIEnv
* env
, jobject
) {
283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
284 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
285 base::string16 passphrase_time_str
=
286 base::TimeFormatShortDate(passphrase_time
);
287 return base::android::ConvertUTF16ToJavaString(env
,
288 l10n_util::GetStringFUTF16(IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE
,
289 passphrase_time_str
));
292 ScopedJavaLocalRef
<jstring
>
293 ProfileSyncServiceAndroid::GetCurrentSignedInAccountText(
294 JNIEnv
* env
, jobject
) {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
296 const std::string
& sync_username
=
297 SigninManagerFactory::GetForProfile(profile_
)->GetAuthenticatedUsername();
298 return base::android::ConvertUTF16ToJavaString(env
,
299 l10n_util::GetStringFUTF16(
300 IDS_SYNC_ACCOUNT_SYNCING_TO_USER
,
301 base::ASCIIToUTF16(sync_username
)));
304 ScopedJavaLocalRef
<jstring
>
305 ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyText(
306 JNIEnv
* env
, jobject
) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
308 return ConvertUTF8ToJavaString(
309 env
, l10n_util::GetStringUTF8(IDS_SYNC_ENTER_PASSPHRASE_BODY
));
312 jboolean
ProfileSyncServiceAndroid::IsSyncKeystoreMigrationDone(
313 JNIEnv
* env
, jobject
) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
315 syncer::SyncStatus status
;
316 bool is_status_valid
= sync_service_
->QueryDetailedSyncStatus(&status
);
317 return is_status_valid
&& !status
.keystore_migration_time
.is_null();
320 jlong
ProfileSyncServiceAndroid::GetEnabledDataTypes(JNIEnv
* env
,
322 syncer::ModelTypeSet types
= sync_service_
->GetActiveDataTypes();
323 types
.PutAll(syncer::ControlTypes());
324 return ModelTypeSetToSelection(types
);
327 void ProfileSyncServiceAndroid::SetPreferredDataTypes(
328 JNIEnv
* env
, jobject obj
,
329 jboolean sync_everything
,
330 jlong model_type_selection
) {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
332 syncer::ModelTypeSet types
;
333 // Note: only user selectable types should be included here.
334 if (model_type_selection
& AUTOFILL
)
335 types
.Put(syncer::AUTOFILL
);
336 if (model_type_selection
& BOOKMARK
)
337 types
.Put(syncer::BOOKMARKS
);
338 if (model_type_selection
& PASSWORD
)
339 types
.Put(syncer::PASSWORDS
);
340 if (model_type_selection
& PROXY_TABS
)
341 types
.Put(syncer::PROXY_TABS
);
342 if (model_type_selection
& TYPED_URL
)
343 types
.Put(syncer::TYPED_URLS
);
344 DCHECK(syncer::UserSelectableTypes().HasAll(types
));
345 sync_service_
->OnUserChoseDatatypes(sync_everything
, types
);
348 void ProfileSyncServiceAndroid::SetSetupInProgress(
349 JNIEnv
* env
, jobject obj
, jboolean in_progress
) {
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
351 sync_service_
->SetSetupInProgress(in_progress
);
354 void ProfileSyncServiceAndroid::SetSyncSetupCompleted(
355 JNIEnv
* env
, jobject obj
) {
356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
357 sync_service_
->SetSyncSetupCompleted();
360 jboolean
ProfileSyncServiceAndroid::HasSyncSetupCompleted(
361 JNIEnv
* env
, jobject obj
) {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
363 return sync_service_
->HasSyncSetupCompleted();
366 jboolean
ProfileSyncServiceAndroid::IsStartSuppressed(
367 JNIEnv
* env
, jobject obj
) {
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
369 return sync_prefs_
->IsStartSuppressed();
372 void ProfileSyncServiceAndroid::EnableEncryptEverything(
373 JNIEnv
* env
, jobject obj
) {
374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
375 sync_service_
->EnableEncryptEverything();
378 jboolean
ProfileSyncServiceAndroid::HasKeepEverythingSynced(
379 JNIEnv
* env
, jobject
) {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
381 return sync_prefs_
->HasKeepEverythingSynced();
384 jboolean
ProfileSyncServiceAndroid::HasUnrecoverableError(
385 JNIEnv
* env
, jobject
) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
387 return sync_service_
->HasUnrecoverableError();
390 ScopedJavaLocalRef
<jstring
> ProfileSyncServiceAndroid::GetAboutInfoForTest(
391 JNIEnv
* env
, jobject
) {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
394 scoped_ptr
<base::DictionaryValue
> about_info
=
395 sync_ui_util::ConstructAboutInformation(sync_service_
);
396 std::string about_info_json
;
397 base::JSONWriter::Write(about_info
.get(), &about_info_json
);
399 return ConvertUTF8ToJavaString(env
, about_info_json
);
402 jlong
ProfileSyncServiceAndroid::GetLastSyncedTimeForTest(
403 JNIEnv
* env
, jobject obj
) {
404 // Use profile preferences here instead of SyncPrefs to avoid an extra
405 // conversion, since SyncPrefs::GetLastSyncedTime() converts the stored value
407 return static_cast<jlong
>(
408 profile_
->GetPrefs()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime
));
411 void ProfileSyncServiceAndroid::OverrideNetworkResourcesForTest(
414 jlong network_resources
) {
415 syncer::NetworkResources
* resources
=
416 reinterpret_cast<syncer::NetworkResources
*>(network_resources
);
417 sync_service_
->OverrideNetworkResourcesForTest(
418 make_scoped_ptr
<syncer::NetworkResources
>(resources
));
422 jlong
ProfileSyncServiceAndroid::ModelTypeSetToSelection(
423 syncer::ModelTypeSet types
) {
424 jlong model_type_selection
= 0;
425 if (types
.Has(syncer::BOOKMARKS
)) {
426 model_type_selection
|= BOOKMARK
;
428 if (types
.Has(syncer::AUTOFILL
)) {
429 model_type_selection
|= AUTOFILL
;
431 if (types
.Has(syncer::AUTOFILL_PROFILE
)) {
432 model_type_selection
|= AUTOFILL_PROFILE
;
434 if (types
.Has(syncer::PASSWORDS
)) {
435 model_type_selection
|= PASSWORD
;
437 if (types
.Has(syncer::TYPED_URLS
)) {
438 model_type_selection
|= TYPED_URL
;
440 if (types
.Has(syncer::SESSIONS
)) {
441 model_type_selection
|= SESSION
;
443 if (types
.Has(syncer::HISTORY_DELETE_DIRECTIVES
)) {
444 model_type_selection
|= HISTORY_DELETE_DIRECTIVE
;
446 if (types
.Has(syncer::PROXY_TABS
)) {
447 model_type_selection
|= PROXY_TABS
;
449 if (types
.Has(syncer::FAVICON_IMAGES
)) {
450 model_type_selection
|= FAVICON_IMAGE
;
452 if (types
.Has(syncer::FAVICON_TRACKING
)) {
453 model_type_selection
|= FAVICON_TRACKING
;
455 if (types
.Has(syncer::DEVICE_INFO
)) {
456 model_type_selection
|= DEVICE_INFO
;
458 if (types
.Has(syncer::NIGORI
)) {
459 model_type_selection
|= NIGORI
;
461 if (types
.Has(syncer::EXPERIMENTS
)) {
462 model_type_selection
|= EXPERIMENTS
;
464 if (types
.Has(syncer::SUPERVISED_USER_SETTINGS
)) {
465 model_type_selection
|= SUPERVISED_USER_SETTING
;
467 return model_type_selection
;
471 std::string
ProfileSyncServiceAndroid::ModelTypeSelectionToStringForTest(
472 jlong model_type_selection
) {
473 ScopedJavaLocalRef
<jstring
> string
=
474 Java_ProfileSyncService_modelTypeSelectionToStringForTest(
475 AttachCurrentThread(), model_type_selection
);
476 return ConvertJavaStringToUTF8(string
);
480 ProfileSyncServiceAndroid
*
481 ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid() {
482 return reinterpret_cast<ProfileSyncServiceAndroid
*>(
483 Java_ProfileSyncService_getProfileSyncServiceAndroid(
484 AttachCurrentThread(), base::android::GetApplicationContext()));
487 static jlong
Init(JNIEnv
* env
, jobject obj
) {
488 ProfileSyncServiceAndroid
* profile_sync_service_android
=
489 new ProfileSyncServiceAndroid(env
, obj
);
490 profile_sync_service_android
->Init();
491 return reinterpret_cast<intptr_t>(profile_sync_service_android
);
495 bool ProfileSyncServiceAndroid::Register(JNIEnv
* env
) {
496 return RegisterNativesImpl(env
);