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 package org.chromium.chrome.browser.sync;
6 
7 import androidx.annotation.Nullable;
8 import androidx.annotation.VisibleForTesting;
9 
10 import org.json.JSONArray;
11 import org.json.JSONException;
12 
13 import org.chromium.base.ThreadUtils;
14 import org.chromium.base.annotations.CalledByNative;
15 import org.chromium.base.annotations.NativeMethods;
16 import org.chromium.components.signin.base.GoogleServiceAuthError;
17 import org.chromium.components.sync.KeyRetrievalTriggerForUMA;
18 import org.chromium.components.sync.ModelType;
19 import org.chromium.components.sync.PassphraseType;
20 
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.concurrent.CopyOnWriteArrayList;
25 
26 /**
27  * JNI wrapper for the native ProfileSyncService.
28  *
29  * This class mostly makes calls to native and contains a minimum of business logic. It is only
30  * usable from the UI thread as the native ProfileSyncService requires its access to be on the
31  * UI thread. See components/sync/driver/profile_sync_service.h for more details.
32  */
33 public class ProfileSyncService {
34 
35     /**
36      * Listener for the underlying sync status.
37      */
38     public interface SyncStateChangedListener {
39         // Invoked when the status has changed.
syncStateChanged()40         public void syncStateChanged();
41     }
42 
43     private static final int[] ALL_SELECTABLE_TYPES = new int[] {
44         ModelType.AUTOFILL,
45         ModelType.BOOKMARKS,
46         ModelType.PASSWORDS,
47         ModelType.PREFERENCES,
48         ModelType.PROXY_TABS,
49         ModelType.TYPED_URLS
50     };
51 
52     private static ProfileSyncService sProfileSyncService;
53     private static boolean sInitialized;
54 
55     // Sync state changes more often than listeners are added/removed, so using CopyOnWrite.
56     private final List<SyncStateChangedListener> mListeners =
57             new CopyOnWriteArrayList<SyncStateChangedListener>();
58 
59     /**
60      * Native ProfileSyncServiceAndroid object. Cannot be final because it is initialized in
61      * {@link init()}.
62      */
63     private long mNativeProfileSyncServiceAndroid;
64 
65     private int mSetupInProgressCounter;
66 
67     /**
68      * Retrieves or creates the ProfileSyncService singleton instance. Returns null if sync is
69      * disabled (via flag or variation).
70      *
71      * Can only be accessed on the main thread.
72      */
73     @Nullable
get()74     public static ProfileSyncService get() {
75         ThreadUtils.assertOnUiThread();
76         if (!sInitialized) {
77             sProfileSyncService = new ProfileSyncService();
78             if (sProfileSyncService.mNativeProfileSyncServiceAndroid == 0) {
79                 sProfileSyncService = null;
80             }
81             sInitialized = true;
82         }
83         return sProfileSyncService;
84     }
85 
86     /**
87      * Overrides the initialization for tests. The tests should call resetForTests() at shutdown.
88      */
89     @VisibleForTesting
overrideForTests(ProfileSyncService profileSyncService)90     public static void overrideForTests(ProfileSyncService profileSyncService) {
91         ThreadUtils.assertOnUiThread();
92         sProfileSyncService = profileSyncService;
93         sInitialized = true;
94     }
95 
96     /**
97      * Resets the ProfileSyncService instance. Calling get() next time will initialize with a new
98      * instance.
99      */
100     @VisibleForTesting
resetForTests()101     public static void resetForTests() {
102         sInitialized = false;
103         sProfileSyncService = null;
104     }
105 
ProfileSyncService()106     protected ProfileSyncService() {
107         init();
108     }
109 
110     /**
111      * This is called pretty early in our application. Avoid any blocking operations here. init()
112      * is a separate function to enable a test subclass of ProfileSyncService to completely stub out
113      * ProfileSyncService.
114      */
init()115     protected void init() {
116         ThreadUtils.assertOnUiThread();
117 
118         // This may cause us to create ProfileSyncService even if sync has not
119         // been set up, but ProfileSyncService won't actually start until
120         // credentials are available.
121         mNativeProfileSyncServiceAndroid =
122                 ProfileSyncServiceJni.get().init(ProfileSyncService.this);
123     }
124 
125     /**
126      * Checks if the sync engine is initialized.
127      *
128      * @return true if the sync engine is initialized.
129      */
isEngineInitialized()130     public boolean isEngineInitialized() {
131         return ProfileSyncServiceJni.get().isEngineInitialized(
132                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
133     }
134 
135     /**
136      * Checks whether sync machinery is active.
137      *
138      * @return true if the transport state is active.
139      */
140     @VisibleForTesting
isTransportStateActive()141     public boolean isTransportStateActive() {
142         return ProfileSyncServiceJni.get().isTransportStateActive(
143                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
144     }
145 
146     /**
147      * Checks whether Sync-the-feature can (attempt to) start. This means that there is a primary
148      * account and no disable reasons. Note that the Sync machinery may start up in transport-only
149      * mode even if this is false.
150      *
151      * @return true if Sync can start, false otherwise.
152      */
canSyncFeatureStart()153     public boolean canSyncFeatureStart() {
154         return ProfileSyncServiceJni.get().canSyncFeatureStart(
155                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
156     }
157 
158     /**
159      * Checks whether Sync-the-feature is currently active. Note that Sync-the-transport may be
160      * active even if this is false.
161      *
162      * @return true if Sync is active, false otherwise.
163      */
isSyncActive()164     public boolean isSyncActive() {
165         return ProfileSyncServiceJni.get().isSyncActive(
166                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
167     }
168 
getAuthError()169     public @GoogleServiceAuthError.State int getAuthError() {
170         int authErrorCode = ProfileSyncServiceJni.get().getAuthError(
171                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
172         if (authErrorCode < 0 || authErrorCode >= GoogleServiceAuthError.State.NUM_ENTRIES) {
173             throw new IllegalArgumentException("No state for code: " + authErrorCode);
174         }
175         return authErrorCode;
176     }
177 
178     /**
179      * Checks whether Sync is disabled by enterprise policy (through prefs) or account policy
180      * received from the sync server.
181      *
182      * @return true if Sync is disabled, false otherwise.
183      */
isSyncDisabledByEnterprisePolicy()184     public boolean isSyncDisabledByEnterprisePolicy() {
185         return ProfileSyncServiceJni.get().isSyncDisabledByEnterprisePolicy(
186                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
187     }
188 
hasUnrecoverableError()189     public boolean hasUnrecoverableError() {
190         return ProfileSyncServiceJni.get().hasUnrecoverableError(
191                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
192     }
193 
requiresClientUpgrade()194     public boolean requiresClientUpgrade() {
195         return ProfileSyncServiceJni.get().requiresClientUpgrade(
196                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
197     }
198 
setDecoupledFromAndroidMasterSync()199     public void setDecoupledFromAndroidMasterSync() {
200         ProfileSyncServiceJni.get().setDecoupledFromAndroidMasterSync(
201                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
202     }
203 
getDecoupledFromAndroidMasterSync()204     public boolean getDecoupledFromAndroidMasterSync() {
205         return ProfileSyncServiceJni.get().getDecoupledFromAndroidMasterSync(
206                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
207     }
208 
isAuthenticatedAccountPrimary()209     public boolean isAuthenticatedAccountPrimary() {
210         return ProfileSyncServiceJni.get().isAuthenticatedAccountPrimary(
211                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
212     }
213 
214     /**
215      * Gets the set of data types that are "preferred" in sync. Those are the
216      * chosen ones (see getChosenDataTypes), plus any that are implied by them.
217      *
218      * This is unaffected by whether sync is on.
219      *
220      * @return Set of preferred data types.
221      */
getPreferredDataTypes()222     public Set<Integer> getPreferredDataTypes() {
223         int[] modelTypeArray = ProfileSyncServiceJni.get().getPreferredDataTypes(
224                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
225         return modelTypeArrayToSet(modelTypeArray);
226     }
227 
228     /**
229      * Gets the set of data types that are currently syncing.
230      *
231      * This is affected by whether sync is on.
232      *
233      * @return Set of active data types.
234      */
getActiveDataTypes()235     public Set<Integer> getActiveDataTypes() {
236         int[] activeDataTypes = ProfileSyncServiceJni.get().getActiveDataTypes(
237                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
238         return modelTypeArrayToSet(activeDataTypes);
239     }
240 
241     /**
242      * Gets the set of data types that are enabled in sync. This will always
243      * return a subset of syncer::UserSelectableTypes().
244      *
245      * This is unaffected by whether sync is on.
246      *
247      * @return Set of chosen types.
248      */
getChosenDataTypes()249     public Set<Integer> getChosenDataTypes() {
250         int[] modelTypeArray = ProfileSyncServiceJni.get().getChosenDataTypes(
251                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
252         return modelTypeArrayToSet(modelTypeArray);
253     }
254 
hasKeepEverythingSynced()255     public boolean hasKeepEverythingSynced() {
256         return ProfileSyncServiceJni.get().hasKeepEverythingSynced(
257                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
258     }
259 
260     /**
261      * Enables syncing for the passed data types.
262      *
263      * @param syncEverything Set to true if the user wants to sync all data types
264      *                       (including new data types we add in the future).
265      * @param enabledTypes   The set of types to enable. Ignored (can be null) if
266      *                       syncEverything is true.
267      */
setChosenDataTypes(boolean syncEverything, Set<Integer> enabledTypes)268     public void setChosenDataTypes(boolean syncEverything, Set<Integer> enabledTypes) {
269         ProfileSyncServiceJni.get().setChosenDataTypes(mNativeProfileSyncServiceAndroid,
270                 ProfileSyncService.this, syncEverything,
271                 syncEverything ? ALL_SELECTABLE_TYPES : modelTypeSetToArray(enabledTypes));
272     }
273 
setFirstSetupComplete(int syncFirstSetupCompleteSource)274     public void setFirstSetupComplete(int syncFirstSetupCompleteSource) {
275         ProfileSyncServiceJni.get().setFirstSetupComplete(mNativeProfileSyncServiceAndroid,
276                 ProfileSyncService.this, syncFirstSetupCompleteSource);
277     }
278 
isFirstSetupComplete()279     public boolean isFirstSetupComplete() {
280         return ProfileSyncServiceJni.get().isFirstSetupComplete(
281                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
282     }
283 
requestStart()284     public void requestStart() {
285         ProfileSyncServiceJni.get().requestStart(
286                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
287     }
288 
requestStop()289     public void requestStop() {
290         ProfileSyncServiceJni.get().requestStop(
291                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
292     }
293 
294     /**
295      * Checks whether syncing is requested by the user, i.e. the user has at least started a Sync
296      * setup flow, and has not disabled syncing in settings. Note that even if this is true, other
297      * reasons might prevent Sync from actually starting up.
298      *
299      * @return true if the user wants to sync, false otherwise.
300      */
isSyncRequested()301     public boolean isSyncRequested() {
302         return ProfileSyncServiceJni.get().isSyncRequested(
303                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
304     }
305 
306     /**
307      * Instances of this class keep sync paused until {@link #close} is called. Use
308      * {@link ProfileSyncService#getSetupInProgressHandle} to create. Please note that
309      * {@link #close} should be called on every instance of this class.
310      */
311     public final class SyncSetupInProgressHandle {
312         private boolean mClosed;
313 
SyncSetupInProgressHandle()314         private SyncSetupInProgressHandle() {
315             ThreadUtils.assertOnUiThread();
316             if (++mSetupInProgressCounter == 1) {
317                 setSetupInProgress(true);
318             }
319         }
320 
close()321         public void close() {
322             ThreadUtils.assertOnUiThread();
323             if (mClosed) return;
324             mClosed = true;
325 
326             assert mSetupInProgressCounter > 0;
327             if (--mSetupInProgressCounter == 0) {
328                 setSetupInProgress(false);
329             }
330         }
331     }
332 
333     /**
334      * Called by the UI to prevent changes in sync settings from taking effect while these settings
335      * are being modified by the user. When sync settings UI is no longer visible,
336      * {@link SyncSetupInProgressHandle#close} has to be invoked for sync settings to be applied.
337      * Sync settings will remain paused as long as there are unclosed objects returned by this
338      * method. Please note that the behavior of SyncSetupInProgressHandle is slightly different from
339      * the equivalent C++ object, as Java instances don't commit sync settings as soon as any
340      * instance of SyncSetupInProgressHandle is closed.
341      */
getSetupInProgressHandle()342     public SyncSetupInProgressHandle getSetupInProgressHandle() {
343         return new SyncSetupInProgressHandle();
344     }
345 
setSetupInProgress(boolean inProgress)346     private void setSetupInProgress(boolean inProgress) {
347         ProfileSyncServiceJni.get().setSetupInProgress(
348                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, inProgress);
349     }
350 
addSyncStateChangedListener(SyncStateChangedListener listener)351     public void addSyncStateChangedListener(SyncStateChangedListener listener) {
352         ThreadUtils.assertOnUiThread();
353         mListeners.add(listener);
354     }
355 
removeSyncStateChangedListener(SyncStateChangedListener listener)356     public void removeSyncStateChangedListener(SyncStateChangedListener listener) {
357         ThreadUtils.assertOnUiThread();
358         mListeners.remove(listener);
359     }
360 
361     /**
362      * Called when the state of the native sync engine has changed, so various
363      * UI elements can update themselves.
364      */
365     @CalledByNative
syncStateChanged()366     protected void syncStateChanged() {
367         for (SyncStateChangedListener listener : mListeners) {
368             listener.syncStateChanged();
369         }
370     }
371 
setSyncAllowedByPlatform(boolean allowed)372     public void setSyncAllowedByPlatform(boolean allowed) {
373         ProfileSyncServiceJni.get().setSyncAllowedByPlatform(
374                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, allowed);
375     }
376 
377     /**
378      * Returns the actual passphrase type being used for encryption. The sync engine must be
379      * running (isEngineInitialized() returns true) before calling this function.
380      * <p/>
381      * This method should only be used if you want to know the raw value. For checking whether
382      * we should ask the user for a passphrase, use isPassphraseRequiredForPreferredDataTypes().
383      */
getPassphraseType()384     public @PassphraseType int getPassphraseType() {
385         assert isEngineInitialized();
386         int passphraseType = ProfileSyncServiceJni.get().getPassphraseType(
387                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
388         if (passphraseType < 0 || passphraseType > PassphraseType.MAX_VALUE) {
389             throw new IllegalArgumentException();
390         }
391         return passphraseType;
392     }
393 
394     /**
395      * Returns true if the current explicit passphrase time is defined.
396      */
hasExplicitPassphraseTime()397     public boolean hasExplicitPassphraseTime() {
398         assert isEngineInitialized();
399         return ProfileSyncServiceJni.get().hasExplicitPassphraseTime(
400                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
401     }
402 
403     /**
404      * Returns the current explicit passphrase time in milliseconds since epoch.
405      */
getExplicitPassphraseTime()406     public long getExplicitPassphraseTime() {
407         assert isEngineInitialized();
408         return ProfileSyncServiceJni.get().getExplicitPassphraseTime(
409                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
410     }
411 
getSyncEnterGooglePassphraseBodyWithDateText()412     public String getSyncEnterGooglePassphraseBodyWithDateText() {
413         assert isEngineInitialized();
414         return ProfileSyncServiceJni.get().getSyncEnterGooglePassphraseBodyWithDateText(
415                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
416     }
417 
getSyncEnterCustomPassphraseBodyWithDateText()418     public String getSyncEnterCustomPassphraseBodyWithDateText() {
419         assert isEngineInitialized();
420         return ProfileSyncServiceJni.get().getSyncEnterCustomPassphraseBodyWithDateText(
421                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
422     }
423 
getCurrentSignedInAccountText()424     public String getCurrentSignedInAccountText() {
425         assert isEngineInitialized();
426         return ProfileSyncServiceJni.get().getCurrentSignedInAccountText(
427                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
428     }
429 
getSyncEnterCustomPassphraseBodyText()430     public String getSyncEnterCustomPassphraseBodyText() {
431         return ProfileSyncServiceJni.get().getSyncEnterCustomPassphraseBodyText(
432                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
433     }
434 
435     /**
436      * Checks if sync is currently set to use a custom passphrase. The sync engine must be running
437      * (isEngineInitialized() returns true) before calling this function.
438      *
439      * @return true if sync is using a custom passphrase.
440      */
isUsingSecondaryPassphrase()441     public boolean isUsingSecondaryPassphrase() {
442         assert isEngineInitialized();
443         return ProfileSyncServiceJni.get().isUsingSecondaryPassphrase(
444                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
445     }
446 
447     /**
448      * Checks if we need a passphrase to decrypt a currently-enabled data type. This returns false
449      * if a passphrase is needed for a type that is not currently enabled.
450      *
451      * @return true if we need a passphrase.
452      */
isPassphraseRequiredForPreferredDataTypes()453     public boolean isPassphraseRequiredForPreferredDataTypes() {
454         assert isEngineInitialized();
455         return ProfileSyncServiceJni.get().isPassphraseRequiredForPreferredDataTypes(
456                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
457     }
458 
459     /**
460      * Checks if trusted vault encryption keys are needed, independently of the currently-enabled
461      * data types.
462      *
463      * @return true if we need an encryption key.
464      */
isTrustedVaultKeyRequired()465     public boolean isTrustedVaultKeyRequired() {
466         assert isEngineInitialized();
467         return ProfileSyncServiceJni.get().isTrustedVaultKeyRequired(
468                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
469     }
470 
471     /**
472      * Checks if trusted vault encryption keys are needed to decrypt a currently-enabled data type.
473      *
474      * @return true if we need an encryption key for a type that is currently enabled.
475      */
isTrustedVaultKeyRequiredForPreferredDataTypes()476     public boolean isTrustedVaultKeyRequiredForPreferredDataTypes() {
477         assert isEngineInitialized();
478         return ProfileSyncServiceJni.get().isTrustedVaultKeyRequiredForPreferredDataTypes(
479                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
480     }
481 
482     /**
483      * Checks if encrypting all the data types is allowed.
484      *
485      * @return true if encrypting all data types is allowed, false if only passwords are allowed to
486      * be encrypted.
487      */
isEncryptEverythingAllowed()488     public boolean isEncryptEverythingAllowed() {
489         assert isEngineInitialized();
490         return ProfileSyncServiceJni.get().isEncryptEverythingAllowed(
491                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
492     }
493 
494     /**
495      * Checks if the user has chosen to encrypt all data types. Note that some data types (e.g.
496      * DEVICE_INFO) are never encrypted.
497      *
498      * @return true if all data types are encrypted, false if only passwords are encrypted.
499      */
isEncryptEverythingEnabled()500     public boolean isEncryptEverythingEnabled() {
501         assert isEngineInitialized();
502         return ProfileSyncServiceJni.get().isEncryptEverythingEnabled(
503                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
504     }
505 
setEncryptionPassphrase(String passphrase)506     public void setEncryptionPassphrase(String passphrase) {
507         assert isEngineInitialized();
508         ProfileSyncServiceJni.get().setEncryptionPassphrase(
509                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, passphrase);
510     }
511 
setDecryptionPassphrase(String passphrase)512     public boolean setDecryptionPassphrase(String passphrase) {
513         assert isEngineInitialized();
514         return ProfileSyncServiceJni.get().setDecryptionPassphrase(
515                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, passphrase);
516     }
517 
518     /**
519      * Returns whether this client has previously prompted the user for a
520      * passphrase error via the android system notifications.
521      *
522      * Can be called whether or not sync is initialized.
523      *
524      * @return Whether client has prompted for a passphrase error previously.
525      */
isPassphrasePrompted()526     public boolean isPassphrasePrompted() {
527         return ProfileSyncServiceJni.get().isPassphrasePrompted(
528                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
529     }
530 
531     /**
532      * Sets whether this client has previously prompted the user for a
533      * passphrase error via the android system notifications.
534      *
535      * Can be called whether or not sync is initialized.
536      *
537      * @param prompted whether the client has prompted the user previously.
538      */
setPassphrasePrompted(boolean prompted)539     public void setPassphrasePrompted(boolean prompted) {
540         ProfileSyncServiceJni.get().setPassphrasePrompted(
541                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, prompted);
542     }
543 
544     /**
545      * Sets the the machine tag used by session sync.
546      */
setSessionsId(String sessionTag)547     public void setSessionsId(String sessionTag) {
548         ThreadUtils.assertOnUiThread();
549         ProfileSyncServiceJni.get().setSyncSessionsId(
550                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, sessionTag);
551     }
552 
553     /**
554      * Gets the number of devices known to sync.
555      *
556      * @return number of syncing devices
557      */
getNumberOfSyncedDevices()558     public int getNumberOfSyncedDevices() {
559         return ProfileSyncServiceJni.get().getNumberOfSyncedDevices(
560                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
561     }
562 
563     /**
564      * Records TrustedVaultKeyRetrievalTrigger histogram.
565      */
recordKeyRetrievalTrigger(@eyRetrievalTriggerForUMA int keyRetrievalTrigger)566     public void recordKeyRetrievalTrigger(@KeyRetrievalTriggerForUMA int keyRetrievalTrigger) {
567         ProfileSyncServiceJni.get().recordKeyRetrievalTrigger(
568                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, keyRetrievalTrigger);
569     }
570 
571     @VisibleForTesting
getNativeProfileSyncServiceForTest()572     public long getNativeProfileSyncServiceForTest() {
573         return ProfileSyncServiceJni.get().getProfileSyncServiceForTest(
574                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
575     }
576 
577     /**
578      * Returns the time when the last sync cycle was completed.
579      *
580      * @return The difference measured in microseconds, between last sync cycle completion time
581      * and 1 January 1970 00:00:00 UTC.
582      */
583     @VisibleForTesting
getLastSyncedTimeForTest()584     public long getLastSyncedTimeForTest() {
585         return ProfileSyncServiceJni.get().getLastSyncedTimeForTest(
586                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
587     }
588 
589     @VisibleForTesting
triggerRefresh()590     public void triggerRefresh() {
591         ProfileSyncServiceJni.get().triggerRefresh(
592                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
593     }
594 
595     /**
596      * Callback for getAllNodes.
597      */
598     public static class GetAllNodesCallback {
599         private String mNodesString;
600 
601         // Invoked when getAllNodes completes.
onResult(String nodesString)602         public void onResult(String nodesString) {
603             mNodesString = nodesString;
604         }
605 
606         // Returns the result of GetAllNodes as a JSONArray.
607         @VisibleForTesting
getNodesAsJsonArray()608         public JSONArray getNodesAsJsonArray() throws JSONException {
609             return new JSONArray(mNodesString);
610         }
611     }
612 
613     /**
614      * Invokes the onResult method of the callback from native code.
615      */
616     @CalledByNative
onGetAllNodesResult(GetAllNodesCallback callback, String nodes)617     private static void onGetAllNodesResult(GetAllNodesCallback callback, String nodes) {
618         callback.onResult(nodes);
619     }
620 
621     /**
622      * Retrieves a JSON version of local Sync data via the native GetAllNodes method.
623      * This method is asynchronous; the result will be sent to the callback.
624      */
625     @VisibleForTesting
getAllNodes(GetAllNodesCallback callback)626     public void getAllNodes(GetAllNodesCallback callback) {
627         ProfileSyncServiceJni.get().getAllNodes(
628                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this, callback);
629     }
630 
modelTypeArrayToSet(int[] modelTypeArray)631     private static Set<Integer> modelTypeArrayToSet(int[] modelTypeArray) {
632         Set<Integer> modelTypeSet = new HashSet<Integer>();
633         for (int i = 0; i < modelTypeArray.length; i++) {
634             modelTypeSet.add(modelTypeArray[i]);
635         }
636         return modelTypeSet;
637     }
638 
modelTypeSetToArray(Set<Integer> modelTypeSet)639     private static int[] modelTypeSetToArray(Set<Integer> modelTypeSet) {
640         int[] modelTypeArray = new int[modelTypeSet.size()];
641         int i = 0;
642         for (int modelType : modelTypeSet) {
643             modelTypeArray[i++] = modelType;
644         }
645         return modelTypeArray;
646     }
647 
648     @NativeMethods
649     interface Natives {
init(ProfileSyncService caller)650         long init(ProfileSyncService caller);
651 
requestStart(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)652         void requestStart(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
requestStop(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)653         void requestStop(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setSyncAllowedByPlatform( long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean allowed)654         void setSyncAllowedByPlatform(
655                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean allowed);
setSyncSessionsId( long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String tag)656         void setSyncSessionsId(
657                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String tag);
getAuthError(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)658         int getAuthError(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
requiresClientUpgrade( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)659         boolean requiresClientUpgrade(
660                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setDecoupledFromAndroidMasterSync( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)661         void setDecoupledFromAndroidMasterSync(
662                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getDecoupledFromAndroidMasterSync( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)663         boolean getDecoupledFromAndroidMasterSync(
664                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isAuthenticatedAccountPrimary( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)665         boolean isAuthenticatedAccountPrimary(
666                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isEngineInitialized( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)667         boolean isEngineInitialized(
668                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isEncryptEverythingAllowed( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)669         boolean isEncryptEverythingAllowed(
670                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isEncryptEverythingEnabled( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)671         boolean isEncryptEverythingEnabled(
672                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isTransportStateActive( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)673         boolean isTransportStateActive(
674                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isPassphraseRequiredForPreferredDataTypes( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)675         boolean isPassphraseRequiredForPreferredDataTypes(
676                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isTrustedVaultKeyRequired( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)677         boolean isTrustedVaultKeyRequired(
678                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isTrustedVaultKeyRequiredForPreferredDataTypes( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)679         boolean isTrustedVaultKeyRequiredForPreferredDataTypes(
680                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isUsingSecondaryPassphrase( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)681         boolean isUsingSecondaryPassphrase(
682                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setDecryptionPassphrase( long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String passphrase)683         boolean setDecryptionPassphrase(
684                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String passphrase);
setEncryptionPassphrase( long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String passphrase)685         void setEncryptionPassphrase(
686                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller, String passphrase);
getPassphraseType(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)687         int getPassphraseType(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
hasExplicitPassphraseTime( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)688         boolean hasExplicitPassphraseTime(
689                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getExplicitPassphraseTime( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)690         long getExplicitPassphraseTime(
691                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getSyncEnterGooglePassphraseBodyWithDateText( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)692         String getSyncEnterGooglePassphraseBodyWithDateText(
693                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getSyncEnterCustomPassphraseBodyWithDateText( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)694         String getSyncEnterCustomPassphraseBodyWithDateText(
695                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getCurrentSignedInAccountText( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)696         String getCurrentSignedInAccountText(
697                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getSyncEnterCustomPassphraseBodyText( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)698         String getSyncEnterCustomPassphraseBodyText(
699                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getNumberOfSyncedDevices( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)700         int getNumberOfSyncedDevices(
701                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getActiveDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)702         int[] getActiveDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getChosenDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)703         int[] getChosenDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getPreferredDataTypes( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)704         int[] getPreferredDataTypes(
705                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setChosenDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean syncEverything, int[] modelTypeArray)706         void setChosenDataTypes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller,
707                 boolean syncEverything, int[] modelTypeArray);
triggerRefresh(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)708         void triggerRefresh(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setSetupInProgress(long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean inProgress)709         void setSetupInProgress(long nativeProfileSyncServiceAndroid, ProfileSyncService caller,
710                 boolean inProgress);
setFirstSetupComplete(long nativeProfileSyncServiceAndroid, ProfileSyncService caller, int syncFirstSetupCompleteSource)711         void setFirstSetupComplete(long nativeProfileSyncServiceAndroid, ProfileSyncService caller,
712                 int syncFirstSetupCompleteSource);
isFirstSetupComplete( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)713         boolean isFirstSetupComplete(
714                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isSyncRequested(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)715         boolean isSyncRequested(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
canSyncFeatureStart( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)716         boolean canSyncFeatureStart(
717                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isSyncActive(long nativeProfileSyncServiceAndroid, ProfileSyncService caller)718         boolean isSyncActive(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isSyncDisabledByEnterprisePolicy( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)719         boolean isSyncDisabledByEnterprisePolicy(
720                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
hasKeepEverythingSynced( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)721         boolean hasKeepEverythingSynced(
722                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
hasUnrecoverableError( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)723         boolean hasUnrecoverableError(
724                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
isPassphrasePrompted( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)725         boolean isPassphrasePrompted(
726                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
setPassphrasePrompted( long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean prompted)727         void setPassphrasePrompted(
728                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller, boolean prompted);
getProfileSyncServiceForTest( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)729         long getProfileSyncServiceForTest(
730                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getLastSyncedTimeForTest( long nativeProfileSyncServiceAndroid, ProfileSyncService caller)731         long getLastSyncedTimeForTest(
732                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
getAllNodes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller, GetAllNodesCallback callback)733         void getAllNodes(long nativeProfileSyncServiceAndroid, ProfileSyncService caller,
734                 GetAllNodesCallback callback);
recordKeyRetrievalTrigger(long nativeProfileSyncServiceAndroid, ProfileSyncService caller, int keyRetrievalTrigger)735         void recordKeyRetrievalTrigger(long nativeProfileSyncServiceAndroid,
736                 ProfileSyncService caller, int keyRetrievalTrigger);
737     }
738 }
739