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_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/i18n/time_formatting.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/profiles/profile_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_ui_util.h"
26 #include "chrome/grit/generated_resources.h"
27 #include "components/signin/core/browser/signin_manager.h"
28 #include "components/sync_driver/pref_names.h"
29 #include "components/sync_driver/sync_prefs.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "google/cacheinvalidation/types.pb.h"
32 #include "google_apis/gaia/gaia_constants.h"
33 #include "google_apis/gaia/google_service_auth_error.h"
34 #include "jni/ProfileSyncService_jni.h"
35 #include "sync/internal_api/public/network_resources.h"
36 #include "sync/internal_api/public/read_transaction.h"
37 #include "ui/base/l10n/l10n_util.h"
39 using base::android::AttachCurrentThread
;
40 using base::android::CheckException
;
41 using base::android::ConvertJavaStringToUTF8
;
42 using base::android::ConvertUTF8ToJavaString
;
43 using base::android::ScopedJavaLocalRef
;
44 using content::BrowserThread
;
48 // Native callback for the JNI GetAllNodes method. When
49 // ProfileSyncService::GetAllNodes completes, this method is called and the
50 // results are sent to the Java callback.
51 void NativeGetAllNodesCallback(
52 const base::android::ScopedJavaGlobalRef
<jobject
>& callback
,
53 scoped_ptr
<base::ListValue
> result
) {
54 JNIEnv
* env
= base::android::AttachCurrentThread();
55 std::string json_string
;
56 if (!result
.get() || !base::JSONWriter::Write(*result
, &json_string
)) {
57 DVLOG(1) << "Writing as JSON failed. Passing empty string to Java code.";
58 json_string
= std::string();
61 ScopedJavaLocalRef
<jstring
> java_json_string
=
62 ConvertUTF8ToJavaString(env
, json_string
);
63 Java_ProfileSyncService_onGetAllNodesResult(env
,
65 java_json_string
.obj());
70 ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv
* env
, jobject obj
)
73 weak_java_profile_sync_service_(env
, obj
) {
74 if (g_browser_process
== NULL
||
75 g_browser_process
->profile_manager() == NULL
) {
76 NOTREACHED() << "Browser process or profile manager not initialized";
80 profile_
= ProfileManager::GetActiveUserProfile();
81 if (profile_
== NULL
) {
82 NOTREACHED() << "Sync Init: Profile not found.";
86 sync_prefs_
.reset(new sync_driver::SyncPrefs(profile_
->GetPrefs()));
89 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_
);
90 DCHECK(sync_service_
);
93 void ProfileSyncServiceAndroid::Init() {
94 sync_service_
->AddObserver(this);
97 void ProfileSyncServiceAndroid::RemoveObserver() {
98 if (sync_service_
->HasObserver(this)) {
99 sync_service_
->RemoveObserver(this);
103 ProfileSyncServiceAndroid::~ProfileSyncServiceAndroid() {
107 void ProfileSyncServiceAndroid::OnStateChanged() {
108 // Notify the java world that our sync state has changed.
109 JNIEnv
* env
= AttachCurrentThread();
110 Java_ProfileSyncService_syncStateChanged(
111 env
, weak_java_profile_sync_service_
.get(env
).obj());
114 jboolean
ProfileSyncServiceAndroid::IsPassphrasePrompted(JNIEnv
* env
,
116 const std::string group_name
=
117 base::FieldTrialList::FindFullName("LimitSyncPassphrasePrompt");
118 if (group_name
!= "Enabled")
120 return sync_prefs_
->IsPassphrasePrompted();
123 void ProfileSyncServiceAndroid::SetPassphrasePrompted(JNIEnv
* env
,
126 sync_prefs_
->SetPassphrasePrompted(prompted
);
129 void ProfileSyncServiceAndroid::RequestStart(JNIEnv
* env
, jobject
) {
130 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
131 sync_service_
->RequestStart();
134 void ProfileSyncServiceAndroid::RequestStop(JNIEnv
* env
, jobject
) {
135 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
136 sync_service_
->RequestStop(ProfileSyncService::KEEP_DATA
);
139 void ProfileSyncServiceAndroid::SignOutSync(JNIEnv
* env
, jobject
) {
140 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
142 sync_service_
->RequestStop(ProfileSyncService::CLEAR_DATA
);
145 void ProfileSyncServiceAndroid::FlushDirectory(JNIEnv
* env
, jobject
) {
146 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
147 sync_service_
->FlushDirectory();
150 ScopedJavaLocalRef
<jstring
> ProfileSyncServiceAndroid::QuerySyncStatusSummary(
151 JNIEnv
* env
, jobject
) {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
154 std::string
status(sync_service_
->QuerySyncStatusSummaryString());
155 return ConvertUTF8ToJavaString(env
, status
);
158 void ProfileSyncServiceAndroid::GetAllNodes(JNIEnv
* env
,
161 base::android::ScopedJavaGlobalRef
<jobject
> java_callback
;
162 java_callback
.Reset(env
, callback
);
164 base::Callback
<void(scoped_ptr
<base::ListValue
>)> native_callback
=
165 base::Bind(&NativeGetAllNodesCallback
, java_callback
);
166 sync_service_
->GetAllNodes(native_callback
);
169 void ProfileSyncServiceAndroid::SetSyncSessionsId(
170 JNIEnv
* env
, jobject obj
, jstring tag
) {
171 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
173 std::string machine_tag
= ConvertJavaStringToUTF8(env
, tag
);
174 sync_prefs_
->SetSyncSessionsGUID(machine_tag
);
177 jint
ProfileSyncServiceAndroid::GetAuthError(JNIEnv
* env
, jobject
) {
178 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
179 return sync_service_
->GetAuthError().state();
182 jboolean
ProfileSyncServiceAndroid::IsEncryptEverythingEnabled(
183 JNIEnv
* env
, jobject
) {
184 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
185 return sync_service_
->EncryptEverythingEnabled();
188 jboolean
ProfileSyncServiceAndroid::IsSyncInitialized(JNIEnv
* env
, jobject
) {
189 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
190 return sync_service_
->backend_initialized();
193 jboolean
ProfileSyncServiceAndroid::IsFirstSetupInProgress(
194 JNIEnv
* env
, jobject
) {
195 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
196 return sync_service_
->FirstSetupInProgress();
199 jboolean
ProfileSyncServiceAndroid::IsEncryptEverythingAllowed(
200 JNIEnv
* env
, jobject obj
) {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
202 return sync_service_
->EncryptEverythingAllowed();
205 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequired(JNIEnv
* env
, jobject
) {
206 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
207 return sync_service_
->IsPassphraseRequired();
210 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequiredForDecryption(
211 JNIEnv
* env
, jobject obj
) {
212 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
213 // In case of CUSTOM_PASSPHRASE we always sync passwords. Prompt the user for
214 // a passphrase if cryptographer has any pending keys.
215 if (sync_service_
->GetPassphraseType() == syncer::CUSTOM_PASSPHRASE
) {
216 return !IsCryptographerReady(env
, obj
);
218 if (sync_service_
->IsPassphraseRequiredForDecryption()) {
219 // Passwords datatype should never prompt for a passphrase, except when
220 // user is using a custom passphrase. Do not prompt for a passphrase if
221 // passwords are the only encrypted datatype. This prevents a temporary
222 // notification for passphrase when PSS has not completed configuring
223 // DataTypeManager, after configuration password datatype shall be disabled.
224 const syncer::ModelTypeSet encrypted_types
=
225 sync_service_
->GetEncryptedDataTypes();
226 return !encrypted_types
.Equals(syncer::ModelTypeSet(syncer::PASSWORDS
));
231 jboolean
ProfileSyncServiceAndroid::IsPassphraseRequiredForExternalType(
232 JNIEnv
* env
, jobject
) {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
235 sync_service_
->passphrase_required_reason() == syncer::REASON_DECRYPTION
;
238 jboolean
ProfileSyncServiceAndroid::IsUsingSecondaryPassphrase(
239 JNIEnv
* env
, jobject
) {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
241 return sync_service_
->IsUsingSecondaryPassphrase();
244 jboolean
ProfileSyncServiceAndroid::SetDecryptionPassphrase(
245 JNIEnv
* env
, jobject obj
, jstring passphrase
) {
246 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
247 std::string key
= ConvertJavaStringToUTF8(env
, passphrase
);
248 return sync_service_
->SetDecryptionPassphrase(key
);
251 void ProfileSyncServiceAndroid::SetEncryptionPassphrase(
252 JNIEnv
* env
, jobject obj
, jstring passphrase
) {
253 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
254 std::string key
= ConvertJavaStringToUTF8(env
, passphrase
);
255 sync_service_
->SetEncryptionPassphrase(key
, ProfileSyncService::EXPLICIT
);
258 jboolean
ProfileSyncServiceAndroid::IsCryptographerReady(JNIEnv
* env
, jobject
) {
259 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
260 return sync_service_
->IsCryptographerReady(&trans
);
263 jint
ProfileSyncServiceAndroid::GetPassphraseType(JNIEnv
* env
, jobject
) {
264 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
265 return sync_service_
->GetPassphraseType();
268 jboolean
ProfileSyncServiceAndroid::HasExplicitPassphraseTime(
269 JNIEnv
* env
, jobject
) {
270 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
271 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
272 return !passphrase_time
.is_null();
275 jlong
ProfileSyncServiceAndroid::GetExplicitPassphraseTime(
276 JNIEnv
* env
, jobject
) {
277 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
278 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
279 return passphrase_time
.ToJavaTime();
282 ScopedJavaLocalRef
<jstring
>
283 ProfileSyncServiceAndroid::GetSyncEnterGooglePassphraseBodyWithDateText(
284 JNIEnv
* env
, jobject
) {
285 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
286 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
287 base::string16 passphrase_time_str
=
288 base::TimeFormatShortDate(passphrase_time
);
289 return base::android::ConvertUTF16ToJavaString(env
,
290 l10n_util::GetStringFUTF16(
291 IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY_WITH_DATE
,
292 passphrase_time_str
));
295 ScopedJavaLocalRef
<jstring
>
296 ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyWithDateText(
297 JNIEnv
* env
, jobject
) {
298 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
299 base::Time passphrase_time
= sync_service_
->GetExplicitPassphraseTime();
300 base::string16 passphrase_time_str
=
301 base::TimeFormatShortDate(passphrase_time
);
302 return base::android::ConvertUTF16ToJavaString(env
,
303 l10n_util::GetStringFUTF16(IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE
,
304 passphrase_time_str
));
307 ScopedJavaLocalRef
<jstring
>
308 ProfileSyncServiceAndroid::GetCurrentSignedInAccountText(
309 JNIEnv
* env
, jobject
) {
310 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
311 const std::string
& sync_username
=
312 SigninManagerFactory::GetForProfile(profile_
)->GetAuthenticatedUsername();
313 return base::android::ConvertUTF16ToJavaString(env
,
314 l10n_util::GetStringFUTF16(
315 IDS_SYNC_ACCOUNT_SYNCING_TO_USER
,
316 base::ASCIIToUTF16(sync_username
)));
319 ScopedJavaLocalRef
<jstring
>
320 ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyText(
321 JNIEnv
* env
, jobject
) {
322 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
323 return ConvertUTF8ToJavaString(
324 env
, l10n_util::GetStringUTF8(IDS_SYNC_ENTER_PASSPHRASE_BODY
));
327 jboolean
ProfileSyncServiceAndroid::IsSyncKeystoreMigrationDone(
328 JNIEnv
* env
, jobject
) {
329 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
330 syncer::SyncStatus status
;
331 bool is_status_valid
= sync_service_
->QueryDetailedSyncStatus(&status
);
332 return is_status_valid
&& !status
.keystore_migration_time
.is_null();
335 ScopedJavaLocalRef
<jintArray
> ProfileSyncServiceAndroid::GetActiveDataTypes(
336 JNIEnv
* env
, jobject obj
) {
337 syncer::ModelTypeSet types
= sync_service_
->GetActiveDataTypes();
338 types
.PutAll(syncer::ControlTypes());
339 return ModelTypeSetToJavaIntArray(env
, types
);
342 ScopedJavaLocalRef
<jintArray
> ProfileSyncServiceAndroid::GetPreferredDataTypes(
343 JNIEnv
* env
, jobject obj
) {
344 syncer::ModelTypeSet types
= sync_service_
->GetPreferredDataTypes();
345 types
.PutAll(syncer::ControlTypes());
346 return ModelTypeSetToJavaIntArray(env
, types
);
349 void ProfileSyncServiceAndroid::SetPreferredDataTypes(
350 JNIEnv
* env
, jobject obj
,
351 jboolean sync_everything
,
352 jintArray model_type_array
) {
353 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
354 std::vector
<int> types_vector
;
355 base::android::JavaIntArrayToIntVector(env
, model_type_array
, &types_vector
);
356 syncer::ModelTypeSet types
;
357 for (size_t i
= 0; i
< types_vector
.size(); i
++) {
358 types
.Put(static_cast<syncer::ModelType
>(types_vector
[i
]));
360 types
.RetainAll(syncer::UserSelectableTypes());
361 sync_service_
->OnUserChoseDatatypes(sync_everything
, types
);
364 void ProfileSyncServiceAndroid::SetSetupInProgress(
365 JNIEnv
* env
, jobject obj
, jboolean in_progress
) {
366 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
367 sync_service_
->SetSetupInProgress(in_progress
);
370 void ProfileSyncServiceAndroid::SetSyncSetupCompleted(
371 JNIEnv
* env
, jobject obj
) {
372 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
373 sync_service_
->SetSyncSetupCompleted();
376 jboolean
ProfileSyncServiceAndroid::HasSyncSetupCompleted(
377 JNIEnv
* env
, jobject obj
) {
378 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
379 return sync_service_
->HasSyncSetupCompleted();
382 jboolean
ProfileSyncServiceAndroid::IsSyncRequested(
383 JNIEnv
* env
, jobject obj
) {
384 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
385 return sync_service_
->IsSyncRequested();
388 jboolean
ProfileSyncServiceAndroid::IsSyncActive(JNIEnv
* env
, jobject obj
) {
389 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
390 return sync_service_
->IsSyncActive();
393 void ProfileSyncServiceAndroid::EnableEncryptEverything(
394 JNIEnv
* env
, jobject obj
) {
395 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
396 sync_service_
->EnableEncryptEverything();
399 jboolean
ProfileSyncServiceAndroid::HasKeepEverythingSynced(
400 JNIEnv
* env
, jobject
) {
401 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
402 return sync_prefs_
->HasKeepEverythingSynced();
405 jboolean
ProfileSyncServiceAndroid::HasUnrecoverableError(
406 JNIEnv
* env
, jobject
) {
407 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
408 return sync_service_
->HasUnrecoverableError();
411 ScopedJavaLocalRef
<jstring
> ProfileSyncServiceAndroid::GetAboutInfoForTest(
412 JNIEnv
* env
, jobject
) {
413 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
415 scoped_ptr
<base::DictionaryValue
> about_info
=
416 sync_ui_util::ConstructAboutInformation(sync_service_
);
417 std::string about_info_json
;
418 base::JSONWriter::Write(*about_info
, &about_info_json
);
420 return ConvertUTF8ToJavaString(env
, about_info_json
);
423 jlong
ProfileSyncServiceAndroid::GetLastSyncedTimeForTest(
424 JNIEnv
* env
, jobject obj
) {
425 // Use profile preferences here instead of SyncPrefs to avoid an extra
426 // conversion, since SyncPrefs::GetLastSyncedTime() converts the stored value
428 return static_cast<jlong
>(
429 profile_
->GetPrefs()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime
));
432 void ProfileSyncServiceAndroid::OverrideNetworkResourcesForTest(
435 jlong network_resources
) {
436 syncer::NetworkResources
* resources
=
437 reinterpret_cast<syncer::NetworkResources
*>(network_resources
);
438 sync_service_
->OverrideNetworkResourcesForTest(
439 make_scoped_ptr
<syncer::NetworkResources
>(resources
));
443 ScopedJavaLocalRef
<jintArray
>
444 ProfileSyncServiceAndroid::ModelTypeSetToJavaIntArray(
446 syncer::ModelTypeSet types
) {
447 std::vector
<int> type_vector
;
448 for (syncer::ModelTypeSet::Iterator it
= types
.First(); it
.Good(); it
.Inc()) {
449 type_vector
.push_back(it
.Get());
451 return base::android::ToJavaIntArray(env
, type_vector
);
455 ProfileSyncServiceAndroid
*
456 ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid() {
457 return reinterpret_cast<ProfileSyncServiceAndroid
*>(
458 Java_ProfileSyncService_getProfileSyncServiceAndroid(
459 AttachCurrentThread(), base::android::GetApplicationContext()));
462 static jlong
Init(JNIEnv
* env
, jobject obj
) {
463 ProfileSyncServiceAndroid
* profile_sync_service_android
=
464 new ProfileSyncServiceAndroid(env
, obj
);
465 profile_sync_service_android
->Init();
466 return reinterpret_cast<intptr_t>(profile_sync_service_android
);
470 bool ProfileSyncServiceAndroid::Register(JNIEnv
* env
) {
471 return RegisterNativesImpl(env
);