| // Copyright 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "chrome/browser/sync/profile_sync_service_android.h" | 
 |  | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/android/jni_array.h" | 
 | #include "base/android/jni_string.h" | 
 | #include "base/bind.h" | 
 | #include "base/callback.h" | 
 | #include "base/i18n/time_formatting.h" | 
 | #include "base/json/json_writer.h" | 
 | #include "base/logging.h" | 
 | #include "base/memory/ptr_util.h" | 
 | #include "base/strings/utf_string_conversions.h" | 
 | #include "base/time/time.h" | 
 | #include "chrome/android/chrome_jni_headers/ProfileSyncService_jni.h" | 
 | #include "chrome/browser/browser_process.h" | 
 | #include "chrome/browser/profiles/profile_manager.h" | 
 | #include "chrome/browser/sync/profile_sync_service_factory.h" | 
 | #include "chrome/browser/sync/session_sync_service_factory.h" | 
 | #include "chrome/grit/generated_resources.h" | 
 | #include "components/prefs/pref_service.h" | 
 | #include "components/signin/public/identity_manager/account_info.h" | 
 | #include "components/strings/grit/components_strings.h" | 
 | #include "components/sync/base/model_type.h" | 
 | #include "components/sync/base/user_selectable_type.h" | 
 | #include "components/sync/driver/profile_sync_service.h" | 
 | #include "components/sync/driver/sync_service_utils.h" | 
 | #include "components/sync_sessions/session_sync_service.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "google_apis/gaia/google_service_auth_error.h" | 
 | #include "ui/base/l10n/l10n_util.h" | 
 |  | 
 | using base::android::AttachCurrentThread; | 
 | using base::android::ConvertJavaStringToUTF8; | 
 | using base::android::ConvertUTF8ToJavaString; | 
 | using base::android::JavaParamRef; | 
 | using base::android::ScopedJavaLocalRef; | 
 | using content::BrowserThread; | 
 |  | 
 | namespace { | 
 |  | 
 | // Native callback for the JNI GetAllNodes method. When | 
 | // ProfileSyncService::GetAllNodes completes, this method is called and the | 
 | // results are sent to the Java callback. | 
 | void NativeGetAllNodesCallback( | 
 |     const base::android::ScopedJavaGlobalRef<jobject>& callback, | 
 |     std::unique_ptr<base::ListValue> result) { | 
 |   JNIEnv* env = base::android::AttachCurrentThread(); | 
 |   std::string json_string; | 
 |   if (!result.get() || !base::JSONWriter::Write(*result, &json_string)) { | 
 |     DVLOG(1) << "Writing as JSON failed. Passing empty string to Java code."; | 
 |     json_string = std::string(); | 
 |   } | 
 |  | 
 |   ScopedJavaLocalRef<jstring> java_json_string = | 
 |       ConvertUTF8ToJavaString(env, json_string); | 
 |   Java_ProfileSyncService_onGetAllNodesResult(env, callback, java_json_string); | 
 | } | 
 |  | 
 | ScopedJavaLocalRef<jintArray> JNI_ProfileSyncService_ModelTypeSetToJavaIntArray( | 
 |     JNIEnv* env, | 
 |     syncer::ModelTypeSet types) { | 
 |   std::vector<int> type_vector; | 
 |   for (syncer::ModelType type : types) { | 
 |     type_vector.push_back(type); | 
 |   } | 
 |   return base::android::ToJavaIntArray(env, type_vector); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv* env, jobject obj) | 
 |     : profile_(nullptr), | 
 |       sync_service_(nullptr), | 
 |       weak_java_profile_sync_service_(env, obj) { | 
 |   if (g_browser_process == nullptr || | 
 |       g_browser_process->profile_manager() == nullptr) { | 
 |     NOTREACHED() << "Browser process or profile manager not initialized"; | 
 |     return; | 
 |   } | 
 |  | 
 |   profile_ = ProfileManager::GetLastUsedProfile(); | 
 |   if (profile_ == nullptr) { | 
 |     NOTREACHED() << "Sync Init: Profile not found."; | 
 |     return; | 
 |   } | 
 |  | 
 |   sync_service_ = | 
 |       ProfileSyncServiceFactory::GetAsProfileSyncServiceForProfile(profile_); | 
 | } | 
 |  | 
 | bool ProfileSyncServiceAndroid::Init() { | 
 |   if (sync_service_) { | 
 |     sync_service_->AddObserver(this); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | ProfileSyncServiceAndroid::~ProfileSyncServiceAndroid() { | 
 |   if (sync_service_) { | 
 |     sync_service_->RemoveObserver(this); | 
 |   } | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::OnStateChanged(syncer::SyncService* sync) { | 
 |   // Notify the java world that our sync state has changed. | 
 |   JNIEnv* env = AttachCurrentThread(); | 
 |   Java_ProfileSyncService_syncStateChanged( | 
 |       env, weak_java_profile_sync_service_.get(env)); | 
 | } | 
 |  | 
 | // Pure ProfileSyncService calls. | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsSyncRequested( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsSyncRequested(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::CanSyncFeatureStart( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->CanSyncFeatureStart(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetSyncRequested(JNIEnv* env, | 
 |                                                  const JavaParamRef<jobject>&, | 
 |                                                  jboolean requested) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   sync_service_->GetUserSettings()->SetSyncRequested(requested); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsSyncAllowedByPlatform( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   return !sync_service_->HasDisableReason( | 
 |       syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetSyncAllowedByPlatform( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     jboolean allowed) { | 
 |   sync_service_->SetSyncAllowedByPlatform(allowed); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsSyncFeatureActive( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->IsSyncFeatureActive(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsSyncDisabledByEnterprisePolicy( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->HasDisableReason( | 
 |       syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsEngineInitialized( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->IsEngineInitialized(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsTransportStateActive( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetTransportState() == | 
 |          syncer::SyncService::TransportState::ACTIVE; | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetSetupInProgress( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     jboolean in_progress) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   if (in_progress) { | 
 |     if (!sync_blocker_) { | 
 |       sync_blocker_ = sync_service_->GetSetupInProgressHandle(); | 
 |     } | 
 |   } else { | 
 |     sync_blocker_.reset(); | 
 |   } | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsFirstSetupComplete( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsFirstSetupComplete(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetFirstSetupComplete( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     jint source) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   sync_service_->GetUserSettings()->SetFirstSetupComplete( | 
 |       static_cast<syncer::SyncFirstSetupCompleteSource>(source)); | 
 | } | 
 |  | 
 | ScopedJavaLocalRef<jintArray> ProfileSyncServiceAndroid::GetActiveDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   syncer::ModelTypeSet types = sync_service_->GetActiveDataTypes(); | 
 |   return JNI_ProfileSyncService_ModelTypeSetToJavaIntArray(env, types); | 
 | } | 
 |  | 
 | ScopedJavaLocalRef<jintArray> ProfileSyncServiceAndroid::GetChosenDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   // TODO(crbug/950874): introduce UserSelectableType in java code, then remove | 
 |   // workaround here and in SetChosenDataTypes(). | 
 |   syncer::UserSelectableTypeSet types = | 
 |       sync_service_->GetUserSettings()->GetSelectedTypes(); | 
 |   syncer::ModelTypeSet model_types; | 
 |   for (syncer::UserSelectableType type : types) { | 
 |     model_types.Put(syncer::UserSelectableTypeToCanonicalModelType(type)); | 
 |   } | 
 |   return JNI_ProfileSyncService_ModelTypeSetToJavaIntArray(env, model_types); | 
 | } | 
 |  | 
 | ScopedJavaLocalRef<jintArray> ProfileSyncServiceAndroid::GetPreferredDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   syncer::ModelTypeSet types = sync_service_->GetPreferredDataTypes(); | 
 |   return JNI_ProfileSyncService_ModelTypeSetToJavaIntArray(env, types); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetChosenDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     jboolean sync_everything, | 
 |     const JavaParamRef<jintArray>& model_type_array) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   std::vector<int> types_vector; | 
 |   base::android::JavaIntArrayToIntVector(env, model_type_array, &types_vector); | 
 |   syncer::ModelTypeSet model_types; | 
 |   for (size_t i = 0; i < types_vector.size(); i++) { | 
 |     model_types.Put(static_cast<syncer::ModelType>(types_vector[i])); | 
 |   } | 
 |   syncer::UserSelectableTypeSet selected_types; | 
 |   for (syncer::UserSelectableType type : syncer::UserSelectableTypeSet::All()) { | 
 |     if (model_types.Has(syncer::UserSelectableTypeToCanonicalModelType(type))) { | 
 |       selected_types.Put(type); | 
 |     } | 
 |   } | 
 |   sync_service_->GetUserSettings()->SetSelectedTypes(sync_everything, | 
 |                                                      selected_types); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsCustomPassphraseAllowed( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsCustomPassphraseAllowed(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsEncryptEverythingEnabled( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsEncryptEverythingEnabled(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsPassphraseRequiredForPreferredDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings() | 
 |       ->IsPassphraseRequiredForPreferredDataTypes(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsTrustedVaultKeyRequired( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsTrustedVaultKeyRequired(); | 
 | } | 
 |  | 
 | jboolean | 
 | ProfileSyncServiceAndroid::IsTrustedVaultKeyRequiredForPreferredDataTypes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings() | 
 |       ->IsTrustedVaultKeyRequiredForPreferredDataTypes(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsUsingExplicitPassphrase( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsUsingExplicitPassphrase(); | 
 | } | 
 |  | 
 | jint ProfileSyncServiceAndroid::GetPassphraseType( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return static_cast<unsigned>( | 
 |       sync_service_->GetUserSettings()->GetPassphraseType()); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetEncryptionPassphrase( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     const JavaParamRef<jstring>& passphrase) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   std::string key = ConvertJavaStringToUTF8(env, passphrase); | 
 |   sync_service_->GetUserSettings()->SetEncryptionPassphrase(key); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::SetDecryptionPassphrase( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     const JavaParamRef<jstring>& passphrase) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   std::string key = ConvertJavaStringToUTF8(env, passphrase); | 
 |   return sync_service_->GetUserSettings()->SetDecryptionPassphrase(key); | 
 | } | 
 |  | 
 | jlong ProfileSyncServiceAndroid::GetExplicitPassphraseTime( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   base::Time passphrase_time = | 
 |       sync_service_->GetUserSettings()->GetExplicitPassphraseTime(); | 
 |   return passphrase_time.ToJavaTime(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::GetAllNodes( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj, | 
 |     const JavaParamRef<jobject>& callback) { | 
 |   base::android::ScopedJavaGlobalRef<jobject> java_callback; | 
 |   java_callback.Reset(env, callback); | 
 |   sync_service_->GetAllNodesForDebugging( | 
 |       base::BindOnce(&NativeGetAllNodesCallback, java_callback)); | 
 | } | 
 |  | 
 | jint ProfileSyncServiceAndroid::GetAuthError(JNIEnv* env, | 
 |                                              const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetAuthError().state(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::HasUnrecoverableError( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->HasUnrecoverableError(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::RequiresClientUpgrade( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->RequiresClientUpgrade(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::SetDecoupledFromAndroidMasterSync( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   sync_service_->SetDecoupledFromAndroidMasterSync(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::GetDecoupledFromAndroidMasterSync( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetDecoupledFromAndroidMasterSync(); | 
 | } | 
 |  | 
 | base::android::ScopedJavaLocalRef<jobject> | 
 | ProfileSyncServiceAndroid::GetAuthenticatedAccountInfo( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   CoreAccountInfo account_info = sync_service_->GetAuthenticatedAccountInfo(); | 
 |   return account_info.IsEmpty() | 
 |              ? nullptr | 
 |              : ConvertToJavaCoreAccountInfo(env, account_info); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::IsAuthenticatedAccountPrimary( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->IsAuthenticatedAccountPrimary(); | 
 | } | 
 |  | 
 | jboolean | 
 | ProfileSyncServiceAndroid::IsPassphrasePromptMutedForCurrentProductVersion( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   return sync_service_->GetUserSettings() | 
 |       ->IsPassphrasePromptMutedForCurrentProductVersion(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid:: | 
 |     MarkPassphrasePromptMutedForCurrentProductVersion( | 
 |         JNIEnv* env, | 
 |         const JavaParamRef<jobject>& obj) { | 
 |   sync_service_->GetUserSettings() | 
 |       ->MarkPassphrasePromptMutedForCurrentProductVersion(); | 
 | } | 
 |  | 
 | jboolean ProfileSyncServiceAndroid::HasKeepEverythingSynced( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>&) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   return sync_service_->GetUserSettings()->IsSyncEverythingEnabled(); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::RecordKeyRetrievalTrigger( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj, | 
 |     jint trigger) { | 
 |   syncer::RecordKeyRetrievalTrigger( | 
 |       static_cast<syncer::KeyRetrievalTriggerForUMA>(trigger)); | 
 | } | 
 |  | 
 | // Functionality only available for testing purposes. | 
 |  | 
 | jlong ProfileSyncServiceAndroid::GetProfileSyncServiceForTest( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   return reinterpret_cast<intptr_t>(sync_service_); | 
 | } | 
 |  | 
 | jlong ProfileSyncServiceAndroid::GetLastSyncedTimeForTest( | 
 |     JNIEnv* env, | 
 |     const JavaParamRef<jobject>& obj) { | 
 |   base::Time last_sync_time = sync_service_->GetLastSyncedTimeForDebugging(); | 
 |   return static_cast<jlong>( | 
 |       (last_sync_time - base::Time::UnixEpoch()).InMicroseconds()); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::OverrideNetworkForTest( | 
 |     const syncer::CreateHttpPostProviderFactory& | 
 |         create_http_post_provider_factory_cb) { | 
 |   sync_service_->OverrideNetworkForTest(create_http_post_provider_factory_cb); | 
 | } | 
 |  | 
 | void ProfileSyncServiceAndroid::TriggerRefresh( | 
 |     JNIEnv* env, | 
 |     const base::android::JavaParamRef<jobject>& obj) { | 
 |   // Only allowed to trigger refresh/schedule nudges for protocol types, things | 
 |   // like PROXY_TABS are not allowed. | 
 |   sync_service_->TriggerRefresh(syncer::ProtocolTypes()); | 
 | } | 
 |  | 
 | static jlong JNI_ProfileSyncService_Init(JNIEnv* env, | 
 |                                          const JavaParamRef<jobject>& obj) { | 
 |   ProfileSyncServiceAndroid* profile_sync_service_android = | 
 |       new ProfileSyncServiceAndroid(env, obj); | 
 |   if (profile_sync_service_android->Init()) { | 
 |     return reinterpret_cast<intptr_t>(profile_sync_service_android); | 
 |   } | 
 |   delete profile_sync_service_android; | 
 |   return 0; | 
 | } |