diff --git a/BUILD.gn b/BUILD.gn index 4ff20d806864..1fd21a2704d4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -104,10 +104,6 @@ if (is_android) { sources = [ "$root_build_dir/brave_resources.pak", "$root_build_dir/brave_100_percent.pak", - "//brave/android/sync/android_sync.js", - "//brave/android/sync/android_sync_words.js", - "//brave/android/sync/crypto.js", - "//brave/components/brave_sync/extension/brave-sync-android/bundles/bundle.js", "//brave/LICENSE.html", ] deps = [ diff --git a/DEPS b/DEPS index 5bdd18f09953..05b62afc35e2 100644 --- a/DEPS +++ b/DEPS @@ -13,14 +13,6 @@ deps = { "vendor/bip39wally-core-native": "https://github.com/brave-intl/bip39wally-core-native.git@13bb40a215248cfbdd87d0a6b425c8397402e9e6", "vendor/bat-native-anonize": "https://github.com/brave-intl/bat-native-anonize.git@e3742ba3e8942eea9e4755d91532491871bd3116", "vendor/bat-native-tweetnacl": "https://github.com/brave-intl/bat-native-tweetnacl.git@800f9d40b7409239ff192e0be634764e747c7a75", - "components/brave_sync/extension/brave-sync": { - 'url': 'https://github.com/brave/sync.git@5da4fc903f9cf0a627bbca28b49fcb09bb479f88', - 'condition': 'not checkout_android', - }, - "components/brave_sync/extension/brave-sync-android": { - 'url': 'https://github.com/brave/sync.git@4098493496b19f46c33a66b8867c69ee6d1a4568', - 'condition': 'checkout_android', - }, "vendor/bat-native-usermodel": "https://github.com/brave-intl/bat-native-usermodel.git@865ba342737c09b13ee18e45b8ece5970bb77246", "vendor/challenge_bypass_ristretto_ffi": "https://github.com/brave-intl/challenge-bypass-ristretto-ffi.git@c396fb4eb9e9bf63b89ae5a0ec0b5f201d43c7c5", } @@ -45,20 +37,6 @@ hooks = [ 'condition': 'not checkout_android', 'action': ['vpython3', 'src/brave/script/download_rust_deps.py'], }, - { - # Build brave-sync - 'name': 'build_brave_sync', - 'pattern': '.', - 'action': ['python', 'src/brave/script/build-simple-js-bundle.py', '--repo_dir_path', 'src/brave/components/brave_sync/extension/brave-sync'], - 'condition': 'not checkout_android', - }, - { - # Build brave-sync android - 'name': 'build_brave_sync', - 'pattern': '.', - 'action': ['python', 'src/brave/script/build-simple-js-bundle.py', '--repo_dir_path', 'src/brave/components/brave_sync/extension/brave-sync-android'], - 'condition': 'checkout_android', - }, { 'name': 'generate_licenses', 'pattern': '.', diff --git a/android/brave_java_resources.gni b/android/brave_java_resources.gni index 4af28eb8056c..bf7e6692966d 100644 --- a/android/brave_java_resources.gni +++ b/android/brave_java_resources.gni @@ -651,7 +651,6 @@ brave_java_resources = [ "java/res/layout/fragment_search_engine_onboarding.xml", "java/res/layout/brave_rewards_spinnner_item_dropdown.xml", "java/res/layout/brave_rewards_grants_list_item.xml", - "java/res/layout/add_sync_device_name_dialog.xml", "java/res/layout/brave_rewards_donation_sent.xml", "java/res/layout/ntp_bottom_sheet.xml", "java/res/layout/brave_shields_scripts_blocked_switcher.xml", diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 9b9c03b82b1b..d504ef1bb7f8 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -31,9 +31,6 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/BraveRewardsUserWalletActivity.java", "../../brave/android/java/org/chromium/chrome/browser/BraveRewardsVerifyWalletActivity.java", "../../brave/android/java/org/chromium/chrome/browser/appmenu/BraveTabbedAppMenuPropertiesDelegate.java", - "../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkModel.java", - "../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUtils.java", - "../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkWorker.java", "../../brave/android/java/org/chromium/chrome/browser/document/BraveLauncherActivity.java", "../../brave/android/java/org/chromium/chrome/browser/externalnav/BraveExternalNavigationHandler.java", "../../brave/android/java/org/chromium/chrome/browser/help/BraveHelpAndFeedback.java", @@ -81,7 +78,6 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/partnercustomizations/CloseBraveManager.java", "../../brave/android/java/org/chromium/chrome/browser/preferences/BravePreferenceKeys.java", "../../brave/android/java/org/chromium/chrome/browser/preferences/BravePrefServiceBridge.java", - "../../brave/android/java/org/chromium/chrome/browser/preferences/BraveSyncScreensObserver.java", "../../brave/android/java/org/chromium/chrome/browser/preferences/website/BraveShieldsContentSettings.java", "../../brave/android/java/org/chromium/chrome/browser/preferences/website/BraveShieldsContentSettingsObserver.java", "../../brave/android/java/org/chromium/chrome/browser/privacy/settings/BravePrivacySettings.java", @@ -114,8 +110,8 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/site_settings/BraveSiteSettingsPreferencesBase.java", "../../brave/android/java/org/chromium/chrome/browser/site_settings/DesktopModePreferences.java", "../../brave/android/java/org/chromium/chrome/browser/site_settings/PlayYTVideoInBrowserPreferences.java", - "../../brave/android/java/org/chromium/chrome/browser/sync/BraveSyncService.java", - "../../brave/android/java/org/chromium/chrome/browser/sync/BraveSyncServiceObserver.java", + "../../brave/android/java/org/chromium/chrome/browser/sync/BraveSyncDevices.java", + "../../brave/android/java/org/chromium/chrome/browser/sync/settings/BraveManageSyncSettings.java", "../../brave/android/java/org/chromium/chrome/browser/toolbar/BraveHomeButton.java", "../../brave/android/java/org/chromium/chrome/browser/toolbar/bottom/BookmarksButton.java", "../../brave/android/java/org/chromium/chrome/browser/toolbar/bottom/BraveBottomToolbarConfiguration.java", @@ -124,6 +120,7 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/toolbar/bottom/BraveBrowsingModeBottomToolbarCoordinator.java", "../../brave/android/java/org/chromium/chrome/browser/toolbar/bottom/BraveSearchAccelerator.java", "../../brave/android/java/org/chromium/chrome/browser/toolbar/top/BraveToolbarLayout.java", +"../../brave/android/java/org/chromium/chrome/browser/ui/brave_tricks/checkbox_to_switch/CheckBoxPreference.java", "../../brave/android/java/org/chromium/chrome/browser/upgrade/BravePackageReplacedBroadcastReceiver.java", "../../brave/android/java/org/chromium/chrome/browser/upgrade/NotificationIntent.java", "../../brave/android/java/org/chromium/chrome/browser/util/BraveDbUtil.java", diff --git a/android/java/org/chromium/chrome/browser/BraveActivity.java b/android/java/org/chromium/chrome/browser/BraveActivity.java index 6e75d30ac2c6..48ed207e2ad9 100644 --- a/android/java/org/chromium/chrome/browser/BraveActivity.java +++ b/android/java/org/chromium/chrome/browser/BraveActivity.java @@ -230,29 +230,6 @@ public void finishNativeInitialization() { showBraveRateDialog(); } - @Override - public void addOrEditBookmark(final Tab tabToBookmark) { - long tempBookmarkId = BookmarkBridge.getUserBookmarkIdForTab(tabToBookmark); - final boolean bCreateBookmark = (BookmarkId.INVALID_ID == tempBookmarkId); - - super.addOrEditBookmark(tabToBookmark); - - final long bookmarkId = BookmarkBridge.getUserBookmarkIdForTab(tabToBookmark); - final BookmarkModel bookmarkModel = new BookmarkModel(); - - bookmarkModel.finishLoadingBookmarkModel(() -> { - // Gives up the bookmarking if the tab is being destroyed. - BookmarkId newBookmarkId = new BookmarkId(bookmarkId, BookmarkType.NORMAL); - if (!((TabImpl)tabToBookmark).isClosing() && ((TabImpl)tabToBookmark).isInitialized()) { - if (null != mBraveSyncWorker && null != newBookmarkId) { - mBraveSyncWorker.CreateUpdateBookmark(bCreateBookmark, bookmarkModel.getBookmarkById(newBookmarkId)); - bookmarkModel.destroy(); - } - } - bookmarkModel.destroy(); - }); - } - private void createNotificationChannel() { Context context = ContextUtils.getApplicationContext(); // Create the NotificationChannel, but only on API 26+ because diff --git a/android/java/org/chromium/chrome/browser/BraveSyncWorker.java b/android/java/org/chromium/chrome/browser/BraveSyncWorker.java old mode 100755 new mode 100644 index baa7a7fb1b42..407ddf238dba --- a/android/java/org/chromium/chrome/browser/BraveSyncWorker.java +++ b/android/java/org/chromium/chrome/browser/BraveSyncWorker.java @@ -5,3173 +5,166 @@ package org.chromium.chrome.browser; -import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.os.Build; -import android.os.Looper; -import android.util.Base64; -import android.util.JsonReader; -import android.util.JsonToken; -import android.webkit.JavascriptInterface; -import org.chromium.base.annotations.JNINamespace; -import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; -import org.chromium.components.bookmarks.BookmarkId; -import org.chromium.components.bookmarks.BookmarkType; -import org.chromium.components.url_formatter.UrlFormatter; -import org.chromium.chrome.browser.bookmarks.BookmarkModel; -import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; -import org.chromium.chrome.browser.bookmarks.BraveBookmarkModel; -import org.chromium.chrome.browser.bookmarks.BraveBookmarkUtils; -import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim; -import org.chromium.chrome.browser.preferences.BraveSyncScreensObserver; -import org.chromium.chrome.browser.WebContentsFactory; -import org.chromium.content_public.browser.JavascriptInjector; -import org.chromium.content_public.browser.WebContents; -import org.chromium.content_public.browser.LoadUrlParams; -import org.chromium.components.embedder_support.view.ContentView; -import org.chromium.content.browser.ViewEventSinkImpl; -import org.chromium.ui.base.ViewAndroidDelegate; -import org.chromium.ui.base.WindowAndroid; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.task.PostTask; +import org.chromium.base.task.TaskTraits; -import java.lang.IllegalArgumentException; import java.lang.Runnable; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Random; -import java.util.Scanner; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.UnsupportedEncodingException; - @JNINamespace("chrome::android") public class BraveSyncWorker { public static final String TAG = "SYNC"; - public static final String PREF_NAME = "SyncPreferences"; - private static final String PREF_LAST_FETCH_NAME = "TimeLastFetch"; - private static final String PREF_LATEST_DEVICE_RECORD_TIMESTAMPT_NAME = "LatestDeviceRecordTime"; - private static final String PREF_LAST_TIME_SEND_NOT_SYNCED_NAME = "TimeLastSendNotSynced"; - public static final String PREF_DEVICE_ID = "DeviceId"; - public static final String PREF_BASE_ORDER = "BaseOrder"; - public static final String PREF_LAST_ORDER = "LastOrder"; - public static final String PREF_SEED = "Seed"; - public static final String PREF_SYNC_DEVICE_NAME = "SyncDeviceName"; - private static final int SYNC_SLEEP_ATTEMPTS_COUNT = 20; - private static final int INTERVAL_TO_FETCH_RECORDS = 1000 * 60; // Milliseconds - private static final int INTERVAL_TO_SEND_SYNC_RECORDS = 1000 * 60; // Milliseconds - private static final int INTERVAL_TO_REFETCH_RECORDS = 10000 * 60; // Milliseconds - private static final Long INTERVAL_RESEND_NOT_SYNCED = 1000L * 60L * 10L; // 10 minutes - private static final int SEND_RECORDS_COUNT_LIMIT = 1000; - private static final int FETCH_RECORDS_CHUNK_SIZE = 300; - private static final String PREF_SYNC_SWITCH = "sync_switch"; - private static final String PREF_SYNC_BOOKMARKS = "brave_sync_bookmarks"; - public static final String PREF_SYNC_TABS = "brave_sync_tabs"; - public static final String PREF_SYNC_HISTORY = "brave_sync_history"; - public static final String PREF_SYNC_AUTOFILL_PASSWORDS = "brave_sync_autofill_passwords"; - public static final String PREF_SYNC_PAYMENT_SETTINGS = "brave_sync_payment_settings"; - public static final String CREATE_RECORD = "0"; - public static final String UPDATE_RECORD = "1"; - public static final String DELETE_RECORD = "2"; - private static final int ATTEMPTS_BEFORE_SENDING_NOT_SYNCED_RECORDS = 1; - - private final SharedPreferences mSharedPreferences; - - private static final String ANDROID_SYNC_JS = "android_sync.js"; - private static final String BUNDLE_JS = "bundle.js"; - private static final String CRYPTO_JS = "crypto.js"; - private static final String ANDROID_SYNC_WORDS_JS = "android_sync_words.js"; - - private static final String ORIGINAL_SEED_KEY = "originalSeed"; - private static final String DEVICES_NAMES = "devicesNames"; - private static final String ORPHAN_BOOKMARKS = "orphanBookmarks"; - private static final String THIS_DEVICE_OBJECT_ID = "thisDeviceObjectId"; - public static final int NICEWARE_WORD_COUNT = 16; - public static final int BIP39_WORD_COUNT = 24; - - private SyncThread mSyncThread; - private SendSyncDataThread mSendSyncDataThread; private Context mContext; - private boolean mStopThread; - private SyncIsReady mSyncIsReady; - - private String mSeed; - private String mDeviceId; - private String mDeviceName; - private String mApiVersion; - private String mBaseOrder; - private String mLastOrder; - //private String mServerUrl = "https://sync-staging.brave.com"; - private String mServerUrl = "https://sync.brave.com"; private String mDebug = "true"; - private long mTimeLastFetch; // In milliseconds - private long mTimeLastFetchExecuted; // In milliseconds - private String mLatestRecordTimeStampt = ""; - private boolean mFetchInProgress; - private BookmarkId mDefaultFolder; - private BraveBookmarkModel mNewBookmarkModel; - private boolean mInterruptSyncSleep; - - private BraveSyncScreensObserver mSyncScreensObserver; - - private ArrayList mOrphanBookmarks = new ArrayList(); - - private WebContents mWebContents; - private JavascriptInjector mWebContentsInjector; - private ViewEventSinkImpl mViewEventSink; - private WebContents mJSWebContents; - private JavascriptInjector mJSWebContentsInjector; - private ViewEventSinkImpl mJSViewEventSink; - private boolean mReorderBookmarks; - private int mAttepmtsBeforeSendingNotSyncedRecords = ATTEMPTS_BEFORE_SENDING_NOT_SYNCED_RECORDS; - private String mBulkBookmarkOperations = ""; - private String mLatestFetchRequest = ""; - - enum NotSyncedRecordsOperation { - GetItems, AddItems, DeleteItems - } - - public static class SyncRecordType { - public static final String BOOKMARKS = "BOOKMARKS"; - public static final String HISTORY = "HISTORY_SITES"; - public static final String PREFERENCES = "PREFERENCES"; - - public static String GetRecordTypeJSArray(String recordType) { - if (recordType.isEmpty() || (!recordType.equals(BOOKMARKS) && - !recordType.equals(HISTORY) && !recordType.equals(PREFERENCES))) { - assert false; - } - return "['" + recordType + "']"; - } - } - - public static class SyncObjectData { - public static final String BOOKMARK = "bookmark"; - public static final String HISTORY_SITE = "historySite"; - public static final String SITE_SETTING = "siteSetting"; - public static final String DEVICE = "device"; - } - - class SyncIsReady { - - public boolean mFetchRecordsReady; - public boolean mResolveRecordsReady; - public boolean mSendRecordsReady; - public boolean mDeleteUserReady; - public boolean mDeleteCategoryReady; - public boolean mDeleteSiteSettingsReady; - public boolean mReady; - public boolean mShouldResetSync; - - public SyncIsReady() { - mFetchRecordsReady = false; - mResolveRecordsReady = false; - mSendRecordsReady = false; - mDeleteUserReady = false; - mDeleteCategoryReady = false; - mDeleteSiteSettingsReady = false; - mReady = false; - mShouldResetSync = false; - } - - public boolean IsReady() { - return mReady && mFetchRecordsReady && mResolveRecordsReady - && mSendRecordsReady && mDeleteUserReady && mDeleteCategoryReady - && mDeleteSiteSettingsReady && !mShouldResetSync; - } - - public void Reset() { - mFetchRecordsReady = false; - mResolveRecordsReady = false; - mSendRecordsReady = false; - mDeleteUserReady = false; - mDeleteCategoryReady = false; - mDeleteSiteSettingsReady = false; - mReady = false; - } - } - - class BookmarkInternal { - public String mUrl = ""; - public String mTitle = ""; - public String mCustomTitle = ""; - public String mParentFolderObjectId = ""; - public boolean mIsFolder; - public long mLastAccessedTime; - public long mCreationTime; - public String mFavIcon = ""; - public String mOrder = ""; - - public BookmarkInternal() { - mIsFolder = false; - mLastAccessedTime = 0; - mCreationTime = 0; - } - public JSONObject toJSONObject() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("url", mUrl); - jsonObject.put("title", mTitle); - jsonObject.put("customTitle", mCustomTitle); - jsonObject.put("parentFolderObjectId", mParentFolderObjectId); - jsonObject.put("isFolder", mIsFolder); - jsonObject.put("lastAccessedTime", mLastAccessedTime); - jsonObject.put("creationTime", mCreationTime); - jsonObject.put("favIcon", mFavIcon); - jsonObject.put("order", mOrder); - } catch (JSONException e) { - Log.e(TAG, "BookmarkInternal toJSONObject error: " + e); - } - return jsonObject; - } - } + private long mNativeBraveSyncWorker; - private BookmarkInternal BookmarkInternalFromJSONObject(JSONObject jsonObject) { - BookmarkInternal bookmarkInternal = new BookmarkInternal(); - try { - if (jsonObject.has("url")) { - bookmarkInternal.mUrl = jsonObject.getString("url"); - } - if (jsonObject.has("title")) { - bookmarkInternal.mTitle = jsonObject.getString("title"); - } - if (jsonObject.has("customTitle")) { - bookmarkInternal.mCustomTitle = jsonObject.getString("customTitle"); - } - if (jsonObject.has("parentFolderObjectId")) { - bookmarkInternal.mParentFolderObjectId = jsonObject.getString("parentFolderObjectId"); - } - if (jsonObject.has("isFolder")) { - bookmarkInternal.mIsFolder = jsonObject.getBoolean("isFolder"); - } - if (jsonObject.has("lastAccessedTime")) { - bookmarkInternal.mLastAccessedTime = jsonObject.getLong("lastAccessedTime"); - } - if (jsonObject.has("creationTime")) { - bookmarkInternal.mCreationTime = jsonObject.getLong("creationTime"); - } - if (jsonObject.has("favIcon")) { - bookmarkInternal.mFavIcon = jsonObject.getString("favIcon"); - } - if (jsonObject.has("order")) { - bookmarkInternal.mOrder = jsonObject.getString("order"); - } - } catch (JSONException e) { - Log.e(TAG, "BookmarkInternalFromJSONObject error: " + e); - } - return bookmarkInternal; + @CalledByNative + private void setNativePtr(long nativePtr) { + assert mNativeBraveSyncWorker == 0; + mNativeBraveSyncWorker = nativePtr; } - public class OrderedBookmark implements Comparable { - private BookmarkItem bookmark; - private String order; - - public OrderedBookmark(BookmarkItem bookmark, String order){ - this.bookmark = bookmark; - this.order = order; - } - - public BookmarkItem Bookmark() { - return bookmark; - } - - @Override - public int compareTo(OrderedBookmark compare) { - if (order.isEmpty() || compare.order.isEmpty()) { - Log.e(TAG, "Incorrect bookmark order"); - // This should not happen - assert false; - return 0; - } - String[] thisNumbers = order.split("\\."); - String[] compareNumbers = compare.order.split("\\."); - int maxSize = thisNumbers.length > compareNumbers.length ? compareNumbers.length : thisNumbers.length; - for (int i = 0; i < maxSize; i++) { - if (Integer.parseInt(thisNumbers[i]) > Integer.parseInt(compareNumbers[i])) { - return 1; - } else if (Integer.parseInt(thisNumbers[i]) < Integer.parseInt(compareNumbers[i])){ - return -1; - } - } - // It means we have equal start parts(ex. 2.2.1.1 vs 2.2.1) - if (thisNumbers.length > compareNumbers.length) { - return -1; - } else if (compareNumbers.length > thisNumbers.length) { - return 1; - } - Log.e(TAG, "Bookmark compare improper state"); - Log.e(TAG, "order == " + order); - Log.e(TAG, "compare.order == " + compare.order); - // This should not happen - assert false; - return 0; + private void Init() { + if (mNativeBraveSyncWorker == 0) { + nativeInit(); } } - public class ResolvedRecordToApply implements Comparable { - public ResolvedRecordToApply(String objectId, String action, BookmarkInternal bookMarkInternal, String deviceName, String deviceId, long syncTime) { - mObjectId = objectId; - mAction = action; - mBookmarkInternal = bookMarkInternal; - mDeviceName = deviceName; - mDeviceId = deviceId; - mSyncTime = syncTime; - } - - public String mObjectId; - public String mAction; - public BookmarkInternal mBookmarkInternal; - public String mDeviceName; - public String mDeviceId; - public long mSyncTime; - - @Override - public int compareTo(ResolvedRecordToApply compare) { - if (mSyncTime > compare.mSyncTime) { - return 1; - } else if (mSyncTime < compare.mSyncTime) { - return -1; - } else { - return 0; - } - } - - public JSONObject toJSONObject() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("objectId", mObjectId); - jsonObject.put("action", mAction); - jsonObject.put("deviceName", mDeviceName); - jsonObject.put("deviceId", mDeviceId); - jsonObject.put("syncTime", mSyncTime); - if (mBookmarkInternal != null) { - jsonObject.put("bookmarkInternal", mBookmarkInternal.toJSONObject()); - } - } catch (JSONException e) { - Log.e(TAG, "ResolvedRecordToApply toJSONObject error: " + e); - } - return jsonObject; - } + @Override + protected void finalize() { + Destroy(); } - private ResolvedRecordToApply ResolvedRecordToApplyFromJSONObject(JSONObject jsonObject) { - String objectId = ""; - String action = ""; - String deviceName = ""; - String deviceId = ""; - long syncTime = 0; - BookmarkInternal bookmarkInternal = null; - try { - if (jsonObject.has("objectId")) { - objectId = jsonObject.getString("objectId"); - } - if (jsonObject.has("action")) { - action = jsonObject.getString("action"); - } - if (jsonObject.has("deviceName")) { - deviceName = jsonObject.getString("deviceName"); - } - if (jsonObject.has("deviceId")) { - deviceId = jsonObject.getString("deviceId"); - } - if (jsonObject.has("syncTime")) { - syncTime = jsonObject.getLong("syncTime"); - } - if (jsonObject.has("bookmarkInternal")) { - String bookmark = jsonObject.getString("bookmarkInternal"); - JSONObject jsonBookmark = new JSONObject(bookmark); - bookmarkInternal = BookmarkInternalFromJSONObject(jsonBookmark); - } - } catch (JSONException e) { - Log.e(TAG, "ResolvedRecordToApplyFromJSONObject error: " + e); + private void Destroy() { + if (mNativeBraveSyncWorker != 0) { + nativeDestroy(mNativeBraveSyncWorker); + mNativeBraveSyncWorker = 0; } - return new ResolvedRecordToApply(objectId, action, bookmarkInternal, deviceName, deviceId, syncTime); } - public BraveSyncWorker(Context context) { - mStopThread = false; - mSeed = null; - mDeviceId = null; - mDeviceName = null; - mApiVersion = "0"; - mBaseOrder = null; - mLastOrder = null; - mReorderBookmarks = false; mContext = context; - mTimeLastFetch = 0; - mTimeLastFetchExecuted = 0; - mFetchInProgress = false; - mNewBookmarkModel = null; - mInterruptSyncSleep = false; - mWebContents = null; - mWebContentsInjector = null; - mViewEventSink = null; - mJSWebContents = null; - mJSWebContentsInjector = null; - mJSViewEventSink = null; - mSharedPreferences = ContextUtils.getAppSharedPreferences(); - mSyncIsReady = new SyncIsReady(); - mSendSyncDataThread = new SendSyncDataThread(); - if (null != mSendSyncDataThread) { - mSendSyncDataThread.start(); - } - mSyncThread = new SyncThread(); - if (null != mSyncThread) { - mSyncThread.start(); - } - GetDefaultFolderId(); - } - - private String convertStreamToString(InputStream is) { - Scanner s = new Scanner(is).useDelimiter("\\A"); - return s.hasNext() ? s.next() : ""; - } - - public void Stop() { - mStopThread = true; - if (null != mNewBookmarkModel) { - mNewBookmarkModel.destroy(); - mNewBookmarkModel = null; - } - if (mSyncThread != null) { - mSyncThread.interrupt(); - mSyncThread = null; - } - if (mSendSyncDataThread != null) { - mSendSyncDataThread.interrupt(); - mSendSyncDataThread = null; - } - new Thread() { - @Override - public void run() { - nativeClear(); - } - }.start(); - } - - public void CreateUpdateDeleteBookmarks(String action, BookmarkItem[] bookmarks, final boolean addIdsToNotSynced, - final boolean isInitialSync) { - assert null != bookmarks; - if (null == bookmarks || 0 == bookmarks.length || !SyncHasBeenSetup() || !IsSyncBookmarksEnabled()) { - return; - } - - // alexeyb: this means we had acquired mNewBookmarkModel - // and we cannot acquire mNewBookmarkModel in GetBookmarkIdRunnable - // because we will wait GetBookmarkIdRunnable completion - // acuiring of mNewBookmarkModel happens above on call-tree - // in SendAllLocalBookmarks on initial sync - final boolean newBookmarkModelAcquiredByThisRunnableWaiter = isInitialSync; - - final String actionFinal = action; - final HashSet processedFolderIds = new HashSet(); - final long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - final List bookmarksParentFolders = new ArrayList(); - boolean uiThread = (Looper.myLooper() == Looper.getMainLooper()); - if (!actionFinal.equals(DELETE_RECORD)) { - // Fill parent folders recursively, if it's not delete operation - for (int i = 0; i < bookmarks.length; i++) { - long processedId = bookmarks[i].getParentId().getId(); - if (defaultFolderId == processedId) { - continue; - } - int currentSize = bookmarksParentFolders.size(); - if (!processedFolderIds.contains(processedId)) { - BookmarkItem item = !uiThread ? GetBookmarkItemByLocalId(String.valueOf(processedId), newBookmarkModelAcquiredByThisRunnableWaiter) : - BookmarkItemByBookmarkId(processedId, newBookmarkModelAcquiredByThisRunnableWaiter); - while (item != null && !item.getTitle().isEmpty()) { - processedFolderIds.add(processedId); - bookmarksParentFolders.add(currentSize, item); - processedId = item.getParentId().getId(); - if (processedFolderIds.contains(processedId)) { - break; - } - if (defaultFolderId == processedId) { - break; - } - item = !uiThread ? GetBookmarkItemByLocalId(String.valueOf(processedId), newBookmarkModelAcquiredByThisRunnableWaiter) : - BookmarkItemByBookmarkId(processedId, newBookmarkModelAcquiredByThisRunnableWaiter); - } - } - } - } - final BookmarkItem[] bookmarksFinal = bookmarks; - - new Thread() { - @Override - public void run() { - if (!SyncHasBeenSetup()) { - return; - } - - ArrayList ids = new ArrayList(); - StringBuilder bookmarkRequest = new StringBuilder(""); - boolean comesFromPreviousSeed = false; - if (isInitialSync) { - String originalSeed = GetObjectId(ORIGINAL_SEED_KEY); - if (originalSeed.equals(mSeed)) { - comesFromPreviousSeed = true; - } - } - if (actionFinal.equals(DELETE_RECORD)) { - // On delete we just process delete items - formRequestForBookmarks(bookmarksFinal, processedFolderIds, comesFromPreviousSeed, actionFinal, true, bookmarkRequest, ids); - } else { - // On other cases we process parent folders first - formRequestForParrentFolders(bookmarksParentFolders, isInitialSync, comesFromPreviousSeed, bookmarkRequest, ids); - formRequestForBookmarks(bookmarksFinal, processedFolderIds, comesFromPreviousSeed, actionFinal, false, bookmarkRequest, ids); - } - if (bookmarkRequest.length() == 0) { - // Nothing to send - return; - } - //Log.i(TAG, "!!!bookmarkRequest == " + bookmarkRequest); - SendSyncRecords(SyncRecordType.BOOKMARKS, bookmarkRequest, actionFinal, ids); - } - - private void formRequestForParrentFolders(List bookmarksParentFolders, boolean isInitialSync, boolean comesFromPreviousSeed, - StringBuilder bookmarkRequest, ArrayList ids) { - for (BookmarkItem bookmarkFolder : bookmarksParentFolders) { - String localId = String.valueOf(bookmarkFolder.getId().getId()); - String objectId = GetObjectId(localId); - if (!isInitialSync && !objectId.isEmpty() - || isInitialSync && comesFromPreviousSeed) { - continue; - } - - bookmarkRequest.append(formRequestByBookmarkItem(bookmarkFolder, bookmarkRequest.length() <= 1, CREATE_RECORD, defaultFolderId, comesFromPreviousSeed)); - if (addIdsToNotSynced) { - ids.add(localId); - } - } - } - - private void formRequestForBookmarks(BookmarkItem[] bookmarksFinal, HashSet processedFolderIds, boolean comesFromPreviousSeed, String actionFinal, boolean deleteOperation, - StringBuilder bookmarkRequest, ArrayList ids) { - if (deleteOperation) { - // Delete operation we perform in reverse order - for (int i = bookmarksFinal.length - 1; i >=0; i--) { - bookmarkRequest.append(formRequestByBookmarkItem(bookmarksFinal[i], bookmarkRequest.length() <= 1, actionFinal, defaultFolderId, comesFromPreviousSeed)); - if (addIdsToNotSynced) { - ids.add(String.valueOf(bookmarksFinal[i].getId().getId())); - } - } - } else { - for (int i = 0; i < bookmarksFinal.length; i++) { - if (bookmarksFinal[i].isFolder() && processedFolderIds.contains(bookmarksFinal[i].getId().getId())) { - continue; - } - bookmarkRequest.append(formRequestByBookmarkItem(bookmarksFinal[i], bookmarkRequest.length() <= 1, actionFinal, defaultFolderId, comesFromPreviousSeed)); - if (addIdsToNotSynced) { - ids.add(String.valueOf(bookmarksFinal[i].getId().getId())); - } - } - } - } - - private StringBuilder formRequestByBookmarkItem(BookmarkItem bookmarkItem, boolean firstRecord, String action, - long defaultFolderId, boolean comesFromPreviousSeed) { - StringBuilder bookmarkRequest = new StringBuilder(""); - String localId = String.valueOf(bookmarkItem.getId().getId()); - String objectId = GetObjectId(localId); - boolean objectExist = !objectId.isEmpty(); - if (!objectExist && action.equals(DELETE_RECORD)) { - // Do not create an object on delete - return bookmarkRequest; - } - if (objectExist && isInitialSync && comesFromPreviousSeed) { - return new StringBuilder(""); - } - if (!objectExist) { - objectId = GenerateObjectId(localId); - } - if (!firstRecord) { - bookmarkRequest.append(", "); - } - String order = GetBookmarkOrder(localId, !objectExist); - if (order.isEmpty()) { - Log.e(TAG, "formRequestByBookmarkItem empty order"); - assert false; - } - long parentId = bookmarkItem.getParentId().getId(); - bookmarkRequest.append(CreateRecord(objectId, SyncObjectData.BOOKMARK, action, mDeviceId, 0)); - bookmarkRequest.append(CreateBookmarkRecord(bookmarkItem.getUrl(), - bookmarkItem.getTitle(), bookmarkItem.isFolder(), - parentId, "", "", 0, 0, "", order)); - bookmarkRequest.append("}"); - if (!objectExist) { - //Log.i(TAG, "Saving object [" + bookmarkItem.getId().getId() + ", " + bookmarkItem.isFolder() + ", " + order + "]: " + objectId); - SaveObjectId(String.valueOf(bookmarkItem.getId().getId()), objectId, order, true); - // alexeyb - dont do reorder here - // when device is connected to sync and already has some bookmarks, - // code in formRequestByBookmarkItem gets order for current bookmarkItem - // and some bookmarks will not have order - // but ReorderBookmarks expects all items have the order - // either disable ReorderBookmarks below or make it ready to accept empty orders - - // alexeyb: on initial sync if device already has some bookmarks, - // code in formRequestByBookmarkItem gets order for current bookmarkItem - // and some bookmarks will not have order - // but ReorderBookmarks expects all items have the order - // other way is to make ReorderBookmarks accept empty orders - if (!isInitialSync) { - ReorderBookmarks(); - } - } - // We will delete the objectId when we ensure that records were transferred - /*else if (action.equals(DELETE_RECORD)) { - nativeDeleteByLocalId(localId); - }*/ - - return bookmarkRequest; - } - }.start(); - } - - public void DeleteBookmarks(BookmarkItem[] bookmarks) { - if (!IsSyncEnabled()) { - if (0 == mTimeLastFetch && 0 == mTimeLastFetchExecuted) { - return; - } - } - CreateUpdateDeleteBookmarks(DELETE_RECORD, bookmarks, true, false); - } - - public void CreateUpdateBookmark(boolean bCreate, BookmarkItem bookmarkItem) { - if (!IsSyncEnabled()) { - if (0 == mTimeLastFetch && 0 == mTimeLastFetchExecuted) { - return; - } - } - BookmarkItem[] bookmarks = new BookmarkItem[1]; - bookmarks[0] = bookmarkItem; - CreateUpdateDeleteBookmarks((bCreate ? CREATE_RECORD : UPDATE_RECORD), bookmarks, true, false); - } - - private StringBuilder CreateRecord(String objectId, String objectData, String action, String deviceId, long syncTime) { - StringBuilder record = new StringBuilder("{ action: "); - record.append(action).append(", "); - record.append("deviceId: [").append(deviceId).append("], "); - record.append("objectId: [").append(objectId).append("], "); - record.append("objectData: '").append(objectData).append("', "); - record.append("syncTimestamp: ").append(syncTime).append(", "); - - return record; - } - - private StringBuilder CreateDeviceCreationRecord(String deviceName, String objectId, String action, String deviceId) { - //Log.i(TAG, "CreateDeviceCreationRecord: " + deviceName); - assert !deviceName.isEmpty(); - if (deviceName.isEmpty()) { - return new StringBuilder(deviceName); - } - StringBuilder record = new StringBuilder("{ action: ").append(action).append(", "); - record.append("deviceId: [").append(deviceId).append("], "); - record.append("objectId: [").append(objectId).append("], "); - record.append(SyncObjectData.DEVICE).append(": { name: \"").append(replaceUnsupportedCharacters(deviceName)).append("\"}}"); - - //Log.i(TAG, "!!!device record == " + record); - return record; - } - - private String replaceUnsupportedCharacters(String in) { - return in.replace("\\", "\\\\").replace("\"", "\\\""); - } - - private String UrlEncode(String url) { - try { - String urlEncoded = URLEncoder.encode(url, "utf-8"); - return urlEncoded; - } catch (UnsupportedEncodingException ex) { - return url; - } - } - - private StringBuilder CreateBookmarkRecord(String url, String title, boolean isFolder, long parentFolderId, - String parentFolderObjectId, String customTitle, long lastAccessedTime, long creationTime, String favIcon, - String order) { - StringBuilder bookmarkRequest = new StringBuilder("bookmark:"); - bookmarkRequest.append("{ site:"); - bookmarkRequest.append("{ location: \"").append(UrlEncode(url)).append("\", "); - if (!isFolder) { - bookmarkRequest.append("title: \"").append(replaceUnsupportedCharacters(title)).append("\", "); - bookmarkRequest.append("customTitle: \"").append(replaceUnsupportedCharacters(customTitle)).append("\", "); - } else { - bookmarkRequest.append("title: \"\", "); - if (!customTitle.isEmpty()) { - bookmarkRequest.append("customTitle: \"").append(replaceUnsupportedCharacters(customTitle)).append("\", "); - } else { - bookmarkRequest.append("customTitle: \"").append(replaceUnsupportedCharacters(title)).append("\", "); - } - } - bookmarkRequest.append("favicon: \"").append(UrlEncode(favIcon)).append("\", "); - bookmarkRequest.append("lastAccessedTime: ").append(lastAccessedTime).append(", "); - bookmarkRequest.append("creationTime: ").append(creationTime).append("}, "); - bookmarkRequest.append("isFolder: ").append(isFolder).append(", "); - bookmarkRequest.append("order: \"").append(order).append("\", "); - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - String parentObjectId = parentFolderObjectId; - if (defaultFolderId != parentFolderId) { - parentObjectId = "[" + GetObjectId(String.valueOf(parentFolderId)) + "]"; - assert !parentObjectId.isEmpty(); - } - if (parentObjectId.isEmpty() || parentObjectId.length() <= 2) { - parentObjectId = "null"; - } - bookmarkRequest.append("parentFolderObjectId: ").append(parentObjectId).append("}"); - - return bookmarkRequest; - } - - private StringBuilder CreateDeviceRecord(String deviceName) { - StringBuilder deviceRequest = new StringBuilder("device:"); - deviceRequest.append("{ name:\"").append(replaceUnsupportedCharacters(deviceName)).append("\"}"); - - return deviceRequest; - } - - private String GetDeviceNameByObjectId(String objectId) { - String object = nativeGetObjectIdByLocalId(DEVICES_NAMES); - if (object.isEmpty()) { - return ""; - } - - String res = ""; - try { - //Log.i(TAG, "GetDeviceNameByObjectId: trying to read JSON: " + object); - JSONObject result = new JSONObject(object); - JSONArray devices = result.getJSONArray("devices"); - for (int i = 0; i < devices.length(); i++) { - JSONObject device = devices.getJSONObject(i); - String currentObject = device.getString("objectId"); - if (currentObject.equals(objectId)) { - res = device.getString("name"); - break; - } - } - } catch (JSONException e) { - Log.e(TAG, "GetDeviceNameByObjectId JSONException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "GetDeviceNameByObjectId IllegalStateException error " + e); - } - - //Log.i(TAG, "!!!GetDeviceNameByObjectId res == " + res); - - return res; - } - - private String GetDeviceObjectIdByLocalId(String localId) { - String object = nativeGetObjectIdByLocalId(DEVICES_NAMES); - if (object.isEmpty()) { - return ""; - } - - String res = ""; - try { - //Log.i(TAG, "GetDeviceObjectIdByLocalId: trying to read JSON: " + object); - JSONObject result = new JSONObject(object); - JSONArray devices = result.getJSONArray("devices"); - for (int i = 0; i < devices.length(); i++) { - JSONObject device = devices.getJSONObject(i); - String currentObject = device.getString("deviceId"); - if (currentObject.equals(localId)) { - res = device.getString("objectId"); - break; - } - } - } catch (JSONException e) { - Log.e(TAG, "GetDeviceObjectIdByLocalId JSONException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "GetDeviceObjectIdByLocalId IllegalStateException error " + e); - } - - //Log.i(TAG, "!!!GetDeviceObjectIdByLocalId res == " + res); - - return res; - } - - public ArrayList GetAllDevices() { - ArrayList result_devices = new ArrayList(); - - String object = nativeGetObjectIdByLocalId(DEVICES_NAMES); - if (object.isEmpty()) { - return result_devices; - } - - JsonReader reader = null; - try { - //Log.i(TAG, "GetAllDevices: trying to read JSON: " + object); - JSONObject result = new JSONObject(object); - JSONArray devices = result.getJSONArray("devices"); - for (int i = 0; i < devices.length(); i++) { - JSONObject device = devices.getJSONObject(i); - String deviceName = device.getString("name"); - String currentObject = device.getString("objectId"); - String deviceId = device.getString("deviceId"); - result_devices.add(new ResolvedRecordToApply(currentObject, "0", null, deviceName, deviceId, 0)); - } - } catch (JSONException e) { - Log.e(TAG, "GetAllDevices JSONException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "GetAllDevices IllegalStateException error " + e); - } - return result_devices; - } - - private String GetBookmarkOrder(String localId) { - try { - String objectId = nativeGetObjectIdByLocalId(localId); - if (objectId.isEmpty()) { - return ""; - } - JSONArray bookmarkArray = new JSONArray(objectId); - JSONObject bookmark = bookmarkArray.getJSONObject(0); - if (!bookmark.has("order")) { - Log.e(TAG, "Could not find order for bookmark: " + objectId); - return ""; - } - String order = bookmark.getString("order"); - return order; - } catch (JSONException e) { - Log.e(TAG, "Could not get order for bookmark: " + e); - return ""; - } - } - - private String GetObjectId(String localId) { - String objectId = nativeGetObjectIdByLocalId(localId); - if (0 == objectId.length()) { - return objectId; - } - JsonReader reader = null; - String res = ""; - try { - reader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(objectId.getBytes()), "UTF-8")); - reader.beginArray(); - while (reader.hasNext()) { - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("objectId")) { - res = reader.nextString(); - } else { - reader.skipValue(); - } - } - reader.endObject(); - } - reader.endArray(); - } catch (UnsupportedEncodingException e) { - Log.e(TAG, "GetObjectId UnsupportedEncodingException error " + e); - } catch (IOException e) { - Log.e(TAG, "GetObjectId IOException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "GetObjectId IllegalStateException error " + e); - } finally { - if (null != reader) { - try { - reader.close(); - } catch (IOException e) { - } - } - } - return res; - } - - private void SaveObjectId(String localId, String objectId, String order, boolean saveObjectId) { - String objectIdJSON = "[{\"objectId\": \"" + objectId + "\", \"order\": \"" + order + "\", \"apiVersion\": \"" + mApiVersion + "\"}]"; - if (!saveObjectId) { - nativeSaveObjectId(localId, objectIdJSON, ""); - } else { - nativeSaveObjectId(localId, objectIdJSON, objectId); - } - } - - private String GenerateObjectIdInternal() { - String res = ""; - // Generates 16 random 8 bits numbers - Random random = new Random(); - for (int i = 0; i < 16; i++) { - if (i != 0) { - res += ", "; - } - try { - res += String.valueOf(random.nextInt(256)); - } catch (IllegalArgumentException exc) { - res = ""; - Log.e(TAG, "ObjectId generation exception " + exc); - } - } - - return res; - } - - private String GenerateObjectId(String localId) { - String res = GetObjectId(localId); - if (0 != res.length()) { - return res; - } - res = GenerateObjectIdInternal(); - return res; - } - - private void ResetSyncWebContents() { - synchronized (mSyncIsReady) { - mSyncIsReady.mShouldResetSync = true; - ThreadUtils.runOnUiThreadBlocking( - new Runnable() { - @Override - public void run() { - ResetSyncWebContentsImpl(); - } - } - ); - } - } + Init(); + (new MigrationFromV1()).MigrateFromSyncV1(); + } + + private class MigrationFromV1 { + // Deprecated + public static final String PREF_NAME = "SyncPreferences"; + private static final String PREF_LAST_FETCH_NAME = "TimeLastFetch"; + private static final String PREF_LATEST_DEVICE_RECORD_TIMESTAMPT_NAME = + "LatestDeviceRecordTime"; + private static final String PREF_LAST_TIME_SEND_NOT_SYNCED_NAME = "TimeLastSendNotSynced"; + public static final String PREF_DEVICE_ID = "DeviceId"; + public static final String PREF_BASE_ORDER = "BaseOrder"; + public static final String PREF_LAST_ORDER = "LastOrder"; + public static final String PREF_SEED = "Seed"; + public static final String PREF_SYNC_DEVICE_NAME = "SyncDeviceName"; + private static final String PREF_SYNC_SWITCH = "sync_switch"; + private static final String PREF_SYNC_BOOKMARKS = "brave_sync_bookmarks"; + public static final String PREF_SYNC_TABS = "brave_sync_tabs"; // never used + public static final String PREF_SYNC_HISTORY = "brave_sync_history"; // never used + public static final String PREF_SYNC_AUTOFILL_PASSWORDS = + "brave_sync_autofill_passwords"; // never used + public static final String PREF_SYNC_PAYMENT_SETTINGS = + "brave_sync_payment_settings"; // never used + + private boolean HaveSyncV1Prefs() { + SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - private void ResetSyncWebContentsImpl() { - if (mSyncIsReady.mShouldResetSync) { - if (null != mWebContentsInjector) { - mWebContentsInjector.removeInterface("injectedObject"); - } - if (null != mWebContents) { - mWebContents.destroy(); + String deviceId = sharedPref.getString(PREF_DEVICE_ID, null); + if (null == deviceId) { + return false; } - mWebContents = null; - mViewEventSink = null; - mWebContentsInjector = null; - mSyncIsReady.mShouldResetSync = false; + return true; } - } - private void TrySync() { - try { - synchronized (mSyncIsReady) { - ResetSyncWebContentsImpl(); - if (null == mWebContents) { - mWebContents = WebContentsFactory.createWebContents(false, true); - if (null != mWebContents) { - ContentView cv = ContentView.createContentView(mContext, mWebContents); - mWebContents.initialize(null, ViewAndroidDelegate.createBasicDelegate(cv), cv, new WindowAndroid(mContext), WebContents.createDefaultInternalsHolder()); - mViewEventSink = ViewEventSinkImpl.from(mWebContents); - if (null != mViewEventSink) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - initContenViewCore(); - } else { - getWebContentsInjector().addPossiblyUnsafeInterface(new JsObject(), "injectedObject", null); - } - - String toLoad = ""; - } catch (IOException exc) { - Log.e(TAG, "Load script exception: " + exc); - } - LoadUrlParams loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(toLoad, "text/html", false, "file:///android_asset/", null); - loadUrlParams.setCanLoadLocalResources(true); - mWebContents.getNavigationController().loadUrl(loadUrlParams); + private void DeleteSyncV1Prefs() { + SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.clear().apply(); + } + + private void DeleteSyncV1LevelDb() { + nativeDestroyV1LevelDb(); + } + + public void MigrateFromSyncV1() { + // Do all migration work in file IO thread because we may need to + // read shared preferences and delete level db + PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { + if (HaveSyncV1Prefs()) { + Log.i(TAG, "Found sync v1 data, doing migration"); + DeleteSyncV1Prefs(); + DeleteSyncV1LevelDb(); + // Mark sync v1 was enabled to trigger informers + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + nativeMarkSyncV1WasEnabledAndMigrated(); } - } + }); } - } - } catch (Exception exc) { - // Ignoring sync exception, we will try it on a next loop execution - Log.e(TAG, "TrySync exception: " + exc); + }); } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - private void initContenViewCore() { - getWebContentsInjector().addPossiblyUnsafeInterface(new JsObject(), "injectedObject", JavascriptInterface.class); - } - - private void CallScript(StringBuilder strCall) { - ThreadUtils.runOnUiThread(new EjectedRunnable(strCall)); - } + }; - private void GotInitData() { - String deviceId = (null == mDeviceId ? null : "[" + mDeviceId + "]"); - String seed = (null == mSeed ? null : "[" + mSeed + "]"); - if (0 == (mContext.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) { - mDebug = "false"; - } - CallScript(new StringBuilder(String.format("javascript:callbackList['got-init-data'](null, %1$s, %2$s, {apiVersion: '%3$s', serverUrl: '%4$s', debug: %5$s})", seed, deviceId, mApiVersion, mServerUrl, mDebug))); + public String GetCodephrase() { + return nativeGetSyncCodeWords(mNativeBraveSyncWorker); } - private void SaveInitData(String arg1, String arg2) { - if (null == arg1 || null == arg2) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError("Incorrect args for SaveInitData"); - } - } - if (null != arg1 && !arg1.isEmpty()) { - mSeed = arg1; - } - mDeviceId = arg2; - //Log.i(TAG, "!!!deviceId == " + mDeviceId); - //Log.i(TAG, "!!!seed == " + mSeed); - // Save seed and deviceId in preferences - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(PREF_DEVICE_ID, mDeviceId); - if (null != mSeed && !mSeed.isEmpty()) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSeedReceived(mSeed, false, true); - } - editor.putString(PREF_SEED, mSeed); - } - editor.apply(); - SetSyncEnabled(true); + public void SaveCodephrase(String codephrase) { + nativeSaveCodeWords(mNativeBraveSyncWorker, codephrase); } - public void SendSyncRecords(String recordType, StringBuilder recordsJSON, String action, ArrayList ids) { - if (!SyncHasBeenSetup()) { - return; - } - synchronized (mSendSyncDataThread) { - SaveGetDeleteNotSyncedRecords(recordType, action, ids, NotSyncedRecordsOperation.AddItems); - if (recordType.equals(SyncRecordType.BOOKMARKS)) { - // Collect bookmarks to send them in a bulk request - if (!mBulkBookmarkOperations.isEmpty()) { - mBulkBookmarkOperations += ","; - } - mBulkBookmarkOperations += recordsJSON; - } else { - StringBuilder script = new StringBuilder("javascript:callbackList['send-sync-records'](null, '"); - script.append(recordType).append("'"); - script.append(", ").append(recordsJSON).append(")"); - CallScript(script); - } - } + public String GetSeedHexFromWords(String codephrase) { + return nativeGetSeedHexFromWords(codephrase); } - private void SendBulkBookmarks() { - synchronized (mSendSyncDataThread) { - if (!mSyncIsReady.IsReady() || mBulkBookmarkOperations.length() == 0) { - return; - } - StringBuilder script = new StringBuilder("javascript:callbackList['send-sync-records'](null, '"); - script.append(SyncRecordType.BOOKMARKS).append("'"); - script.append(", [").append(mBulkBookmarkOperations).append("])"); - CallScript(script); - mAttepmtsBeforeSendingNotSyncedRecords = ATTEMPTS_BEFORE_SENDING_NOT_SYNCED_RECORDS; - mBulkBookmarkOperations = ""; - } + public String GetWordsFromSeedHex(String seedHex) { + return nativeGetWordsFromSeedHex(seedHex); } - @SuppressWarnings("unchecked") - private ArrayList GetNotSyncedRecords(String recordId) { - ArrayList existingList = new ArrayList(); - try { - String currentArray = GetObjectId(recordId); - if (!currentArray.isEmpty()) { - byte[] data = Base64.decode(currentArray, Base64.DEFAULT); - ObjectInputStream ois = new ObjectInputStream( - new ByteArrayInputStream(data)); - existingList = (ArrayList)ois.readObject(); - ois.close(); - } - } catch (IOException ioe) { - } catch (ClassNotFoundException e) { - } - - return existingList; + public void RequestSync() { + nativeRequestSync(mNativeBraveSyncWorker); } - private void SaveNotSyncedRecords(String recordId, ArrayList existingList) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(existingList); - oos.close(); - SaveObjectId(recordId, Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT), "", false); - } catch (IOException ioe) { - Log.e(TAG, "Failed to SaveNotSyncedRecords: " + ioe); - } + public boolean IsFirstSetupComplete() { + return nativeIsFirstSetupComplete(mNativeBraveSyncWorker); } - private synchronized ArrayList SaveGetDeleteNotSyncedRecords(String recordType, String action, ArrayList ids, NotSyncedRecordsOperation operation) { - if (NotSyncedRecordsOperation.GetItems != operation && 0 == ids.size()) { - return null; - } - String recordId = recordType + action; - ArrayList existingList = GetNotSyncedRecords(recordId); - if (NotSyncedRecordsOperation.GetItems == operation) { - return existingList; - } else if (NotSyncedRecordsOperation.AddItems == operation) { - for (String id: ids) { - if (!existingList.contains(id)) { - existingList.add(id); - } - } - } else if (NotSyncedRecordsOperation.DeleteItems == operation) { - boolean listChanged = false; - boolean clearLocalDb = action.equals(DELETE_RECORD); - for (String id: ids) { - boolean itemRemoved = existingList.remove(id); - if (!listChanged) { - listChanged = itemRemoved; - } - // Delete corresponding objectIds - if (clearLocalDb) { - nativeDeleteByLocalId(id); - } - } - if (!listChanged) { - return null; - } - } - - SaveNotSyncedRecords(recordId, existingList); - - return null; + public void FinalizeSyncSetup() { + nativeFinalizeSyncSetup(mNativeBraveSyncWorker); } - public void SetUpdateDeleteDeviceName(String action, String deviceName, String deviceId, String objectId) { - if (action.equals(CREATE_RECORD)) { - objectId = GetObjectId(THIS_DEVICE_OBJECT_ID); - if (0 == objectId.length()) { - objectId = GenerateObjectIdInternal(); - SaveObjectId(THIS_DEVICE_OBJECT_ID, objectId, "", false); - } - } - assert !objectId.isEmpty(); - if (objectId.isEmpty()) { - return; - } - StringBuilder request = new StringBuilder("["); - request.append(CreateDeviceCreationRecord(deviceName, objectId, action, deviceId)).append("]"); - ArrayList ids = new ArrayList(); - ids.add(deviceId); - //Log.i(TAG, "!!!device operation request: " + request.toString()); - SendSyncRecords(SyncRecordType.PREFERENCES, request, action, ids); + public void ResetSync() { + nativeResetSync(mNativeBraveSyncWorker); } - private void SendAllLocalBookmarks() { - if (null == mNewBookmarkModel) { - return; - } - synchronized (mNewBookmarkModel) - { - // Grab current existing bookmarksIds to sync them - List localBookmarks = GetBookmarkItems(); - if (null != localBookmarks) { - //Log.i(TAG, "!!!localBookmarks.size() == " + localBookmarks.size()); - int listSize = localBookmarks.size(); - for (int i = 0; i < listSize; i += SEND_RECORDS_COUNT_LIMIT) { - List subList = localBookmarks.subList(i, Math.min(listSize, i + SEND_RECORDS_COUNT_LIMIT)); - CreateUpdateDeleteBookmarks(CREATE_RECORD, subList.toArray(new BookmarkItem[subList.size()]), true, true); - } - } - } - } + private native void nativeInit(); + private native void nativeDestroy(long nativeBraveSyncWorker); - private Long GetLatestDeviceRecordTime() { - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - Long latestDeviceRecordTimeL = sharedPref.getLong(PREF_LATEST_DEVICE_RECORD_TIMESTAMPT_NAME, 0); - return latestDeviceRecordTimeL; - } + private native void nativeDestroyV1LevelDb(); + private native void nativeMarkSyncV1WasEnabledAndMigrated(); - private void SetLatestDeviceRecordTime(String latestDeviceRecordTime) { - try { - Long latestDeviceRecordTimeL = Long.parseLong(latestDeviceRecordTime); - // Save last fetch time in preferences - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putLong(PREF_LATEST_DEVICE_RECORD_TIMESTAMPT_NAME, latestDeviceRecordTimeL); - editor.apply(); - } catch (NumberFormatException e) { - } - } + private native String nativeGetSyncCodeWords(long nativeBraveSyncWorker); + private native void nativeRequestSync(long nativeBraveSyncWorker); - private void FetchSyncRecords(String lastRecordFetchTime, String category) { - synchronized (mSyncThread) { - if (!mSyncIsReady.IsReady()) { - //Log.i(TAG, "!!!Sync is not ready"); - return; - } - //Log.i(TAG, "!!!in FetchSyncRecords lastRecordFetchTime == " + lastRecordFetchTime); - if (0 == mTimeLastFetch && 0 == mTimeLastFetchExecuted) { - // It is the very first time of the sync start - // Set device name - if (null == mDeviceName || mDeviceName.isEmpty()) { - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - mDeviceName = sharedPref.getString(PREF_SYNC_DEVICE_NAME, ""); - } - SetUpdateDeleteDeviceName(CREATE_RECORD, mDeviceName, mDeviceId, ""); - SendAllLocalBookmarks(); - // Initial fetch of devices only - CallScript(new StringBuilder(String.format("javascript:callbackList['fetch-sync-records'](null, %1$s, %2$s, %3$s)", - SyncRecordType.GetRecordTypeJSArray(SyncRecordType.PREFERENCES), 0, FETCH_RECORDS_CHUNK_SIZE))); - try { - Thread.sleep(BraveSyncWorker.INTERVAL_TO_FETCH_RECORDS); - } catch (InterruptedException e) { - Log.w(TAG, "Fetch waiting was interrupted: " + e); - } - } - Calendar currentTime = Calendar.getInstance(); - if (currentTime.getTimeInMillis() - mTimeLastFetchExecuted <= INTERVAL_TO_FETCH_RECORDS && lastRecordFetchTime.isEmpty()) { - return; - } - mInterruptSyncSleep = false; - mLatestFetchRequest = (lastRecordFetchTime.isEmpty() ? String.valueOf(mTimeLastFetch) : lastRecordFetchTime); + private native String nativeGetSeedHexFromWords(String passphrase); + private native String nativeGetWordsFromSeedHex(String seedHex); + private native void nativeSaveCodeWords(long nativeBraveSyncWorker, String passphrase); - // We have no yet option to turn on/off sync categories, always sync both - // preferences and bookmarks. - // Call them separately - if (category.isEmpty() || SyncRecordType.BOOKMARKS.equals(category)) { - CallScript(new StringBuilder(String.format("javascript:callbackList['fetch-sync-records'](null, %1$s, %2$s, %3$s)", - SyncRecordType.GetRecordTypeJSArray(SyncRecordType.BOOKMARKS), mLatestFetchRequest, FETCH_RECORDS_CHUNK_SIZE))); - } + private native void nativeFinalizeSyncSetup(long nativeBraveSyncWorker); - if (category.isEmpty() || SyncRecordType.PREFERENCES.equals(category)) { - Long latestDeviceRecordTime = GetLatestDeviceRecordTime(); - CallScript(new StringBuilder(String.format("javascript:callbackList['fetch-sync-records'](null, %1$s, %2$s, %3$s)", - SyncRecordType.GetRecordTypeJSArray(SyncRecordType.PREFERENCES), latestDeviceRecordTime, FETCH_RECORDS_CHUNK_SIZE))); - } - - mTimeLastFetchExecuted = currentTime.getTimeInMillis(); - if (!lastRecordFetchTime.isEmpty()) { - try { - mTimeLastFetch = Long.parseLong(lastRecordFetchTime); - // Save last fetch time in preferences - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putLong(PREF_LAST_FETCH_NAME, mTimeLastFetch); - editor.apply(); - } catch (NumberFormatException e) { - } - } - } - } - - public StringBuilder GetExistingObjects(String categoryName, String recordsJSON, String latestRecordTimeStampt, boolean isTruncated) { - if (null == categoryName || null == recordsJSON) { - return new StringBuilder(""); - } - if (!SyncRecordType.BOOKMARKS.equals(categoryName) && !SyncRecordType.PREFERENCES.equals(categoryName)) { - // TODO sync for other categories - return new StringBuilder(""); - } - - if (latestRecordTimeStampt != null && !latestRecordTimeStampt.isEmpty() - && SyncRecordType.PREFERENCES.equals(categoryName)) { - SetLatestDeviceRecordTime(latestRecordTimeStampt); - } - - mFetchInProgress = true; - if (SyncRecordType.BOOKMARKS.equals(categoryName)) { - mLatestRecordTimeStampt = latestRecordTimeStampt; - } - - StringBuilder res = new StringBuilder(""); - /*if (recordsJSON.length() > 2 && SyncRecordType.BOOKMARKS.equals(categoryName)) { - Log.i(TAG, "!!!in GetExistingObjects: " + latestRecordTimeStampt + ": " + isTruncated + ": " + recordsJSON); - }*/ - - // Debug - /*int iPos = recordsJSON.indexOf("NewFolder3"); - if (-1 != iPos) { - if (iPos + 2000 > recordsJSON.length()) { - Log.i(TAG, "!!!GetExistingObjects == " + recordsJSON.substring(iPos)); - } else { - Log.i(TAG, "!!!GetExistingObjects == " + recordsJSON.substring(iPos, iPos + 2000)); - } - if (iPos > 500) { - if (iPos + 1500 > recordsJSON.length()) { - Log.i(TAG, "!!!GetExistingObjects == " + recordsJSON.substring(iPos - 500)); - } else { - Log.i(TAG, "!!!GetExistingObjects == " + recordsJSON.substring(iPos - 500, iPos + 1500)); - } - } - }*/ - /*iPos = recordsJSON.indexOf("\"objectId\":{\"0\":26,\"1\":251", iPos + 1); - if (-1 != iPos) { - if (iPos + 2000 > recordsJSON.length()) { - Log.i(TAG, "!!!GetExistingObjects1 == " + recordsJSON.substring(iPos)); - } else { - Log.i(TAG, "!!!GetExistingObjects1 == " + recordsJSON.substring(iPos, iPos + 2000)); - } - if (iPos > 500) { - if (iPos + 1500 > recordsJSON.length()) { - Log.i(TAG, "!!!GetExistingObjects1 == " + recordsJSON.substring(iPos - 500)); - } else { - Log.i(TAG, "!!!GetExistingObjects1 == " + recordsJSON.substring(iPos - 500, iPos + 1500)); - } - } - }*/ - //Log.i(TAG, "!!!recordsJSON == " + recordsJSON); - /*int iPos = recordsJSON.indexOf("Bobrina"); - if (-1 != iPos) { - Log.i(TAG, "!!!record == " + recordsJSON.substring(iPos, iPos + 2000)); - if (iPos > 500) { - Log.i(TAG, "!!!record1 == " + recordsJSON.substring(iPos - 500, iPos + 1500)); - } - }*/ - /*int step = 2000; - int count = 0; - for (;;) { - int endIndex = count * step + step; - if (endIndex > recordsJSON.length() - 1) { - endIndex = recordsJSON.length() - 1; - } - String substr = recordsJSON.substring(count * step, endIndex); - Log.i(TAG, "!!!substr == " + substr); - if (endIndex != count * step + step) { - break; - } - count++; - }*/ - // - - HashMap> syncedRecordsMap = new HashMap>(); - List bookmarksRecords = new ArrayList(); - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - JsonReader reader = null; - try { - reader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(recordsJSON.getBytes()), "UTF-8")); - reader.beginArray(); - while (reader.hasNext()) { - StringBuilder action = new StringBuilder(CREATE_RECORD); - StringBuilder objectId = new StringBuilder(""); - StringBuilder deviceId = new StringBuilder(""); - StringBuilder objectData = new StringBuilder(""); - BookmarkInternal bookmarkInternal = null; - StringBuilder deviceName = new StringBuilder(""); - long syncTime = 0; - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("action")) { - action = GetAction(reader); - } else if (name.equals("deviceId")) { - deviceId = GetDeviceId(reader); - } else if (name.equals("objectId")) { - objectId = GetObjectIdJSON(reader); - } else if (name.equals(SyncObjectData.BOOKMARK)) { - bookmarkInternal = GetBookmarkRecord(reader); - } else if (name.equals(SyncObjectData.DEVICE)) { - deviceName = GetDeviceName(reader); - } else if (name.equals("objectData")) { - objectData = GetObjectDataJSON(reader); - } else if (name.equals("syncTimestamp")) { - syncTime = reader.nextLong(); - } else { - reader.skipValue(); - } - } - reader.endObject(); - if (null == bookmarkInternal && 0 == deviceName.length()) { - continue; - } - StringBuilder serverRecord = new StringBuilder("["); - StringBuilder localRecord = new StringBuilder(""); - if (null != bookmarkInternal) { - bookmarksRecords.add(new ResolvedRecordToApply(objectId.toString(), action.toString(), bookmarkInternal, deviceName.toString(), deviceId.toString(), syncTime)); - } else { - serverRecord.append(CreateRecord(objectId.toString(), SyncObjectData.DEVICE, - action.toString(), deviceId.toString(), syncTime)).append(CreateDeviceRecord(deviceName.toString())).append(" }"); - String localDeviceName = GetDeviceNameByObjectId(objectId.toString()); - if (!localDeviceName.isEmpty()) { - localRecord.append(CreateRecord(objectId.toString(), SyncObjectData.DEVICE, CREATE_RECORD, - mDeviceId, syncTime)).append(CreateDeviceRecord(localDeviceName)).append(" }]"); - } - if (0 == res.length()) { - res.append("["); - } else { - res.append(", "); - } - res.append(serverRecord).append(", ").append(0 != localRecord.length() ? localRecord : "null]"); - // Mark the record as sucessfully sent - ArrayList value = syncedRecordsMap.get(action.toString()); - if (null == value) { - value = new ArrayList(); - } - value.add(deviceId.toString()); - syncedRecordsMap.put(action.toString(), value); - } - } - reader.endArray(); - } catch (UnsupportedEncodingException e) { - Log.e(TAG, "GetExistingObjects UnsupportedEncodingException error " + e); - } catch (IOException e) { - Log.e(TAG, "GetExistingObjects IOException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "GetExistingObjects IllegalStateException error " + e); - } catch (IllegalArgumentException exc) { - Log.e(TAG, "GetExistingObjects generation exception " + exc); - } finally { - if (null != reader) { - try { - reader.close(); - } catch (IOException e) { - } - } - } - Collections.sort(bookmarksRecords); - for (ResolvedRecordToApply bookmarkRecord: bookmarksRecords) { - if (bookmarkRecord.mBookmarkInternal == null) { - assert false; - continue; - } - StringBuilder serverRecord = new StringBuilder("["); - StringBuilder localRecord = new StringBuilder(""); - String localId = nativeGetLocalIdByObjectId(bookmarkRecord.mObjectId.toString()); - serverRecord.append(CreateRecord(bookmarkRecord.mObjectId, SyncObjectData.BOOKMARK, - bookmarkRecord.mAction, bookmarkRecord.mDeviceId, bookmarkRecord.mSyncTime)).append(CreateBookmarkRecord(bookmarkRecord.mBookmarkInternal.mUrl, - bookmarkRecord.mBookmarkInternal.mTitle, bookmarkRecord.mBookmarkInternal.mIsFolder, defaultFolderId, "[" + bookmarkRecord.mBookmarkInternal.mParentFolderObjectId + "]", - bookmarkRecord.mBookmarkInternal.mCustomTitle, bookmarkRecord.mBookmarkInternal.mLastAccessedTime, bookmarkRecord.mBookmarkInternal.mCreationTime, - bookmarkRecord.mBookmarkInternal.mFavIcon, bookmarkRecord.mBookmarkInternal.mOrder)).append(" }"); - BookmarkItem bookmarkItem = GetBookmarkItemByLocalId(localId, false); - if (null != bookmarkItem) { - String order = GetBookmarkOrder(localId, false); - // TODO pass always CREATE_RECORD, it means action is create - long parentId = bookmarkItem.getParentId().getId(); - localRecord.append(CreateRecord(bookmarkRecord.mObjectId, SyncObjectData.BOOKMARK, CREATE_RECORD, mDeviceId, bookmarkRecord.mSyncTime)) - .append(CreateBookmarkRecord(bookmarkItem.getUrl(), bookmarkItem.getTitle(), - bookmarkItem.isFolder(), parentId, "", "", 0, 0, "", order)).append(" }]"); - } - // Mark the record as sucessfully sent - ArrayList value = syncedRecordsMap.get(bookmarkRecord.mAction.toString()); - if (null == value) { - value = new ArrayList(); - } - value.add(localId); - syncedRecordsMap.put(bookmarkRecord.mAction.toString(), value); - // Ignore records which needs resolve, but which came from our device - // No need to reapply them, and also they can confuse the sync lib records merger - if (!this.mDeviceId.equals(bookmarkRecord.mDeviceId)) { - if (0 == res.length()) { - res.append("["); - } else { - res.append(", "); - } - res.append(serverRecord).append(", ").append(0 != localRecord.length() ? localRecord : "null]"); - } - } - if (0 != res.length()) { - res.append("]"); - } - if (!isTruncated) { - // We finished fetch in chunks; - //Log.i(TAG, "!!!finished fetch in chunks: " + categoryName); - mLatestRecordTimeStampt = ""; - } - for (Map.Entry> entry : syncedRecordsMap.entrySet()) { - SaveGetDeleteNotSyncedRecords(categoryName, entry.getKey(), entry.getValue(), NotSyncedRecordsOperation.DeleteItems); - } - // - //Log.i(TAG, "!!!GetExistingObjects res == " + res); - /*int step = 2000; - int count = 0; - for (;;) { - int endIndex = count * step + step; - if (endIndex > res.length() - 1) { - endIndex = res.length() - 1; - } - String substr = res.substring(count * step, endIndex); - Log.i(TAG, "!!!substr == " + substr); - if (endIndex != count * step + step) { - break; - } - count++; - }*/ - // - - //Log.i(TAG, "!!!res == " + res.toString()); - return res; - } - - private ArrayList GetBookmarkItemsByLocalIds(ArrayList localIds, String action) { - if (0 == localIds.size()) { - return new ArrayList(); - } - try { - ArrayList localIdsLong = new ArrayList(); - for (String id: localIds) { - localIdsLong.add(Long.parseLong(id)); - } - GetBookmarkItemsByLocalIdsRunnable bookmarkRunnable = new GetBookmarkItemsByLocalIdsRunnable(localIdsLong, action); - if (null == bookmarkRunnable) { - return new ArrayList(); - } - synchronized (bookmarkRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - } - } - - return bookmarkRunnable.mBookmarkItems; - } catch (NumberFormatException e) { - Log.e(TAG, "NumberFormatException: " + e); - } - - return null; - } - - private BookmarkItem GetBookmarkItemByLocalId(String localId, boolean newBookmarkModelAcquired) { - if (0 == localId.length()) { - return null; - } - try { - long llocalId = Long.parseLong(localId); - GetBookmarkIdRunnable bookmarkRunnable = new GetBookmarkIdRunnable(llocalId); - if (null == bookmarkRunnable) { - return null; - } - synchronized (bookmarkRunnable) - { - if (newBookmarkModelAcquired) { - bookmarkRunnable.SetNewBookmarkModelAcquiredByThisRunnableWaiter(); - } - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "GetBookmarkItemByLocalId error: " + e); - } - } - - return bookmarkRunnable.mBookmarkItem; - } catch (NumberFormatException e) { - Log.e(TAG, "GetBookmarkItemByLocalId error: " + e); - } - - return null; - } - - public void SendResolveSyncRecords(String categoryName, StringBuilder existingRecords) { - if (!mSyncIsReady.IsReady() - || null == categoryName || null == existingRecords - || 0 == categoryName.length()) { - return; - } - if (0 == existingRecords.length()) { - existingRecords.append("[]"); - } - StringBuilder script = new StringBuilder("javascript:callbackList['resolve-sync-records'](null, '"); - script.append(categoryName).append("'"); - script.append(", ").append(existingRecords).append(")"); - - CallScript(script); - } - - private void DeleteBookmarkByLocalId(String localId) { - if (0 == localId.length()) { - return; - } - try { - long llocalId = Long.parseLong(localId); - DeleteBookmarkRunnable bookmarkRunnable = new DeleteBookmarkRunnable(llocalId); - if (null == bookmarkRunnable) { - return; - } - synchronized (bookmarkRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - } - } - nativeDeleteByLocalId(localId); - if (null != bookmarkRunnable.mBookmarksItems) { - for (BookmarkItem item: bookmarkRunnable.mBookmarksItems) { - String itemLocalId = String.valueOf(item.getId().getId()); - nativeDeleteByLocalId(itemLocalId); - } - } - } catch (NumberFormatException e) { - } - - return; - } - - class DeleteBookmarkRunnable implements Runnable { - private long mBookmarkId; - public List mBookmarksItems; - - public DeleteBookmarkRunnable(long bookmarkId) { - mBookmarkId = bookmarkId; - } - - @Override - public void run() { - BookmarkId bookmarkId = new BookmarkId(mBookmarkId, BookmarkType.NORMAL); - if (bookmarkId == null) { - Log.e(TAG, "bookmarkId == null"); - } - if (null != mNewBookmarkModel && null != bookmarkId) { - synchronized (mNewBookmarkModel) { - // Get children to clean local leveldb, all children are deleted recursively - BookmarkItem bookmarkRoot = mNewBookmarkModel.getBookmarkById(bookmarkId); - mBookmarksItems = getBookmarksForFolder(mNewBookmarkModel, bookmarkRoot); - // Delete children bookmarks - for (BookmarkItem bookmark : mBookmarksItems) { - if (!bookmark.isFolder()) { - mNewBookmarkModel.deleteBookmarkSilently(bookmark.getId()); - } - } - // Delete children bookmark folders - for (BookmarkItem bookmark : mBookmarksItems) { - if (bookmark.isFolder()) { - mNewBookmarkModel.deleteBookmarkSilently(bookmark.getId()); - } - } - // Delete root bookmark - if (bookmarkRoot == null) { - Log.e(TAG, "Failed to find root bookmark: " + bookmarkId); - } else { - mNewBookmarkModel.deleteBookmarkSilently(bookmarkId); - } - } - } - - synchronized (this) - { - this.notify(); - } - } - } - - private void EditBookmarkByLocalId(String localId, String url, String title, String parentLocalId, String objectId, String order) { - if (0 == localId.length()) { - return; - } - try { - long llocalId = Long.parseLong(localId); - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - long lparentLocalId = defaultFolderId; - if (!parentLocalId.isEmpty()) { - lparentLocalId = Long.parseLong(parentLocalId); - } - EditBookmarkRunnable bookmarkRunnable = new EditBookmarkRunnable(llocalId, url, title, lparentLocalId); - if (null == bookmarkRunnable) { - return; - } - synchronized (bookmarkRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "EditBookmarkByLocalId error: " + e); - } - } - } catch (NumberFormatException e) { - Log.e(TAG, "EditBookmarkByLocalId error: " + e); - } - String oldOrder = GetBookmarkOrder(localId); - SaveObjectId(localId, objectId, order, true); - if (!oldOrder.equals(order)) { - mReorderBookmarks = true; - } - return; - } - - private void AddBookmark(String url, String title, boolean isFolder, String objectId, String parentLocalId, String order) { - try { - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - long lparentLocalId = defaultFolderId; - if (!parentLocalId.isEmpty()) { - lparentLocalId = Long.parseLong(parentLocalId); - } - AddBookmarkRunnable bookmarkRunnable = new AddBookmarkRunnable(url, title, isFolder, lparentLocalId); - if (null == bookmarkRunnable) { - return; - } - synchronized (bookmarkRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "AddBookmark error: " + e); - } - } - if (null != bookmarkRunnable.mBookmarkId) { - SaveObjectId(String.valueOf(bookmarkRunnable.mBookmarkId.getId()), objectId, order, true); - mReorderBookmarks = true; - } - } catch (NumberFormatException e) { - Log.e(TAG, "AddBookmark error: " + e); - } - } - - private List GetBookmarkItems() { - try { - GetBookmarkItemsRunnable bookmarkRunnable = new GetBookmarkItemsRunnable(); - if (null == bookmarkRunnable) { - return null; - } - synchronized (bookmarkRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(bookmarkRunnable); - - // Wait until runnable is finished - try { - bookmarkRunnable.wait(); - } catch (InterruptedException e) { - } - } - - return bookmarkRunnable.mBookmarksItems; - } catch (NumberFormatException e) { - } - - return null; - } - - class GetBookmarkItemsRunnable implements Runnable { - private List mBookmarksItems; - - public GetBookmarkItemsRunnable() { - } - - @Override - public void run() { - if (null != mNewBookmarkModel && null != mDefaultFolder) { - mBookmarksItems = getBookmarksForFolder(mNewBookmarkModel, mNewBookmarkModel.getBookmarkById(mDefaultFolder)); - } - - synchronized (this) - { - this.notify(); - } - } - } - - private List getBookmarksForFolder(BookmarkModel newBookmarkModel, BookmarkItem parent) { - List res = new ArrayList(); - if (null == parent || !parent.isFolder()) { - return res; - } - res = newBookmarkModel.getBookmarksForFolder(parent.getId()); - List newList = new ArrayList(); - for (BookmarkItem item : res) { - if (!item.isFolder()) { - continue; - } - newList.addAll(getBookmarksForFolder(newBookmarkModel, item)); - } - res.addAll(newList); - - return res; - } - - public void ResolvedSyncRecords(String categoryName, String recordsJSON) { - //Log.i(TAG, "!!!in ResolvedSyncRecords"); - if (null == categoryName || null == recordsJSON) { - assert false; - return; - } - if (!SyncRecordType.BOOKMARKS.equals(categoryName) && !SyncRecordType.PREFERENCES.equals(categoryName)) { - // TODO sync for other categories - assert false; - return; - } - - // Debug - /*int iPos = recordsJSON.indexOf("Vim Commands"); - if (-1 != iPos) { - if (iPos + 2000 > recordsJSON.length()) { - Log.i(TAG, "!!!Resolvedrecord == " + recordsJSON.substring(iPos)); - } else { - Log.i(TAG, "!!!Resolvedrecord == " + recordsJSON.substring(iPos, iPos + 2000)); - } - if (iPos > 500) { - if (iPos + 1500 > recordsJSON.length()) { - Log.i(TAG, "!!!Resolvedrecord == " + recordsJSON.substring(iPos - 500)); - } else { - Log.i(TAG, "!!!Resolvedrecord == " + recordsJSON.substring(iPos - 500, iPos + 1500)); - } - } - }*/ - // - /*if (recordsJSON.length() > 3) { - Log.i(TAG, "ResolvedSyncRecords!!!recordsJSON = " + recordsJSON); - }*/ - /*String[] records = recordsJSON.split("action"); - for (int i = 0; i < records.length; i++) { - Log.i(TAG, "!!!record[" + i + "]" + records[i]); - }*/ - // - if (SyncRecordType.BOOKMARKS.equals(categoryName)) { - SetExtensiveBookmarkOperation(true); - } - List devicesRecords = new ArrayList(); - List bookmarksRecords = new ArrayList(); - long syncTime = 0; - JsonReader reader = null; - try { - reader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(recordsJSON.getBytes()), "UTF-8")); - reader.beginArray(); - while (reader.hasNext()) { - String objectId = ""; - String action = CREATE_RECORD; - BookmarkInternal bookmarkInternal = null; - String deviceName = ""; - String deviceId = ""; - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("action")) { - action = GetAction(reader).toString(); - } else if (name.equals("deviceId")) { - deviceId = GetDeviceId(reader).toString(); - } else if (name.equals("objectId")) { - objectId = GetObjectIdJSON(reader).toString(); - } else if (name.equals(SyncObjectData.BOOKMARK)) { - bookmarkInternal = GetBookmarkRecord(reader); - } else if (name.equals(SyncObjectData.DEVICE)) { - deviceName = GetDeviceName(reader).toString(); - } else if (name.equals("syncTimestamp")) { - syncTime = reader.nextLong(); - } - else { - reader.skipValue(); - } - } - reader.endObject(); - if (null == bookmarkInternal && deviceName.isEmpty()) { - continue; - } - if (null != bookmarkInternal && (action.equals(DELETE_RECORD) || !bookmarkInternal.mTitle.isEmpty() || !bookmarkInternal.mCustomTitle.isEmpty())) { - bookmarksRecords.add(new ResolvedRecordToApply(objectId, action, bookmarkInternal, "", "", syncTime)); - } else if (!deviceName.isEmpty()) { - devicesRecords.add(new ResolvedRecordToApply(objectId, action, null, deviceName, deviceId, syncTime)); - } else { - Log.e(TAG, "Unknown state"); - assert false; - } - } - reader.endArray(); - } catch (UnsupportedEncodingException e) { - Log.e(TAG, "ResolvedSyncRecords UnsupportedEncodingException error " + e); - } catch (IOException e) { - Log.e(TAG, "ResolvedSyncRecords IOException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "ResolvedSyncRecords IllegalStateException error " + e); - } catch (IllegalArgumentException exc) { - Log.e(TAG, "ResolvedSyncRecords generation exception " + exc); - } finally { - if (null != reader) { - try { - reader.close(); - } catch (IOException e) { - } - } - } - Collections.sort(bookmarksRecords); - for (ResolvedRecordToApply bookmarkRecord: bookmarksRecords) { - BookmarkResolver(bookmarkRecord); - } - DeviceResolver(devicesRecords); - if (SyncRecordType.BOOKMARKS.equals(categoryName)) { - SetExtensiveBookmarkOperation(false); - } - if (mLatestRecordTimeStampt.isEmpty()) { - mTimeLastFetch = mTimeLastFetchExecuted; - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putLong(PREF_LAST_FETCH_NAME, mTimeLastFetch); - editor.apply(); - mFetchInProgress = false; - SendNotSyncedRecords(); - if (SyncRecordType.BOOKMARKS.equals(categoryName) && mReorderBookmarks) { - ReorderBookmarks(); - mReorderBookmarks = false; - } - } else { - FetchSyncRecords(mLatestFetchRequest, categoryName); - } - } - - private void ReorderBookmarks() { - // Bookmarks reodering will be triggered once fetch operation is finished - // So no need in it during fetch - if (null == mNewBookmarkModel || mFetchInProgress) { - return; - } - synchronized (mNewBookmarkModel) { - List localBookmarks = GetBookmarkItems(); - List orderedBookmarks = new ArrayList(); - for (BookmarkItem bookmark : localBookmarks) { - String order = GetBookmarkOrder(String.valueOf(bookmark.getId().getId())); - if (order.isEmpty()) { - Log.w(TAG, "ReorderBookmarks skipping bookmark due to empty order for " + bookmark.getId().getId()); - continue; - } - OrderedBookmark orderedBookmark = new OrderedBookmark(bookmark, order); - orderedBookmarks.add(orderedBookmark); - } - Collections.sort(orderedBookmarks); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - synchronized (mNewBookmarkModel) { - for (OrderedBookmark orderedBookmark : orderedBookmarks) { - mNewBookmarkModel.moveBookmark(orderedBookmark.Bookmark().getId(), orderedBookmark.Bookmark().getParentId()); - } - } - } - }); - } - } - - public boolean SyncBookmarkModelIsReady() { - return mNewBookmarkModel != null; - } - - public void SyncedMoveBookmark(BookmarkId bookmarkId, BookmarkId newParentId) { - if (null == mNewBookmarkModel) { - return; - } - synchronized (mNewBookmarkModel) { - mNewBookmarkModel.moveBookmark(bookmarkId, newParentId); - } - } - - void SaveLastSendNotSyncedTime(Long lastTimeSendNotSynced) { - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putLong(PREF_LAST_TIME_SEND_NOT_SYNCED_NAME, lastTimeSendNotSynced); - editor.apply(); - } - - Long LoadLastSendNotSyncedTime() { - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - Long lastSendNotSyncedTime = sharedPref.getLong(PREF_LAST_TIME_SEND_NOT_SYNCED_NAME, 0); - return lastSendNotSyncedTime; - } - - private void SendNotSyncedRecords() { - Long lastSendNotSyncedTime = LoadLastSendNotSyncedTime(); - Long currentTime = Calendar.getInstance().getTimeInMillis(); - - if (currentTime - lastSendNotSyncedTime < INTERVAL_RESEND_NOT_SYNCED) { - return; - } - SaveLastSendNotSyncedTime(currentTime); - synchronized (mSendSyncDataThread) { - // Make sure we don't have pending send bookmarks operations - if (mBulkBookmarkOperations.length() == 0 && mAttepmtsBeforeSendingNotSyncedRecords-- <= 0) { - ProcessNotSyncedRecords(SyncRecordType.BOOKMARKS, CREATE_RECORD); - ProcessNotSyncedRecords(SyncRecordType.BOOKMARKS, UPDATE_RECORD); - ProcessNotSyncedRecords(SyncRecordType.BOOKMARKS, DELETE_RECORD); - } - } - // Process preferences (aka devices) - ProcessNotSyncedRecords(SyncRecordType.PREFERENCES, CREATE_RECORD); - ProcessNotSyncedRecords(SyncRecordType.PREFERENCES, UPDATE_RECORD); - ProcessNotSyncedRecords(SyncRecordType.PREFERENCES, DELETE_RECORD); - } - - private void ProcessNotSyncedRecords(String categoryName, String action) { - ArrayList ids = SaveGetDeleteNotSyncedRecords(categoryName, action, new ArrayList(), NotSyncedRecordsOperation.GetItems); - if (categoryName.equals(SyncRecordType.BOOKMARKS)) { - ArrayList items = GetBookmarkItemsByLocalIds(ids, action); - BookmarkItem[] itemsArray = new BookmarkItem[items.size()]; - itemsArray = items.toArray(itemsArray); - CreateUpdateDeleteBookmarks(action, itemsArray, false, false); - } else if (categoryName.equals(SyncRecordType.PREFERENCES)) { - for (String id : ids) { - String objectId = GetDeviceObjectIdByLocalId(id); - String deviceName = GetDeviceNameByObjectId(objectId); - SetUpdateDeleteDeviceName(action, deviceName, id, objectId); - } - } else { - // Other categories are not handled at the momemt - assert false; - } - } - - private void DeviceResolver(List resolvedRecords) { - //Log.i(TAG, "DeviceResolver: resolvedRecords.size(): " + resolvedRecords.size()); - assert null != resolvedRecords; - - if (0 == resolvedRecords.size() && - (mSyncScreensObserver == null || !mSyncScreensObserver.shouldLoadDevices())) { - // When there are no changes in devices from sync cloud, but devices - // page is currently opened in sync settings, reload in anyway devices list - return; - } - - String object = nativeGetObjectIdByLocalId(DEVICES_NAMES); - - List existingRecords = new ArrayList(); - if (!object.isEmpty()) { - try { - JSONObject result = new JSONObject(object); - JSONArray devices = result.getJSONArray("devices"); - for (int i = 0; i < devices.length(); i++) { - JSONObject device = devices.getJSONObject(i); - String deviceName = device.getString("name"); - String currentObject = device.getString("objectId"); - String deviceId = device.getString("deviceId"); - existingRecords.add(new ResolvedRecordToApply(currentObject, "0", null, deviceName, deviceId, 0)); - } - } catch (JSONException e) { - Log.e(TAG, "DeviceResolver JSONException error " + e); - } catch (IllegalStateException e) { - Log.e(TAG, "DeviceResolver IllegalStateException error " + e); - } - } - - for (ResolvedRecordToApply resolvedRecord: resolvedRecords) { - assert !resolvedRecord.mDeviceName.isEmpty(); - boolean exist = false; - ResolvedRecordToApply existingRecordToRemove = null; - for (ResolvedRecordToApply existingRecord: existingRecords) { - if (existingRecord.mObjectId.equals(resolvedRecord.mObjectId)) { - if (resolvedRecord.mAction.equals(DELETE_RECORD)) { - existingRecordToRemove = existingRecord; - } else if (resolvedRecord.mAction.equals(UPDATE_RECORD)) { - existingRecord.mDeviceName = resolvedRecord.mDeviceName; - } - exist = true; - break; - } - } - if (null != existingRecordToRemove) { - if (existingRecordToRemove.mDeviceId.equals(mDeviceId)) { - // We deleted current device, so need to reset sync - //Log.i(TAG, "DeviceResolver reset sync for " + resolvedRecord.mDeviceName); - ResetSync(); - } - //Log.i(TAG, "DeviceResolver remove from list device " + resolvedRecord.mDeviceName); - existingRecords.remove(existingRecordToRemove); - } - if (!exist && !resolvedRecord.mAction.equals(DELETE_RECORD)) { - // TODO add to the list - existingRecords.add(resolvedRecord); - } - } - // TODO add or remove devices in devices list - JSONObject result = new JSONObject(); - try { - JSONArray devices = new JSONArray(); - for (ResolvedRecordToApply existingRecord: existingRecords) { - JSONObject device = new JSONObject(); - device.put("name", replaceUnsupportedCharacters(existingRecord.mDeviceName)); - device.put("objectId", existingRecord.mObjectId); - device.put("deviceId", existingRecord.mDeviceId); - devices.put(device); - } - result.put("devices", devices); - } catch (JSONException e) { - Log.e(TAG, "DeviceResolver JSONException error " + e); - } - nativeSaveObjectId(DEVICES_NAMES, result.toString(), ""); - if (null != mSyncScreensObserver && !mSyncIsReady.mShouldResetSync) { - mSyncScreensObserver.onDevicesAvailable(); - } - } - - private boolean BookmarkResolver(ResolvedRecordToApply resolvedRecord) { - // Return true if we need to skip that folder - if (resolvedRecord == null || resolvedRecord.mBookmarkInternal == null) { - assert false; - return false; - } - String localId = nativeGetLocalIdByObjectId(resolvedRecord.mObjectId); - if (localId.isEmpty() && resolvedRecord.mAction.equals(DELETE_RECORD)) { - // Just skip that item as it is not locally and was deleted - return true; - } - String parentLocalId = nativeGetLocalIdByObjectId(resolvedRecord.mBookmarkInternal.mParentFolderObjectId); - if (!resolvedRecord.mBookmarkInternal.mParentFolderObjectId.isEmpty() && parentLocalId.isEmpty()) { - PushOrphanBookmark(resolvedRecord); - // Orphan bookmark will be applied once its parent pops up - return true; - } - if (0 != localId.length()) { - if (resolvedRecord.mAction.equals(UPDATE_RECORD)) { - EditBookmarkByLocalId(localId, resolvedRecord.mBookmarkInternal.mUrl, - (resolvedRecord.mBookmarkInternal.mCustomTitle.isEmpty() ? resolvedRecord.mBookmarkInternal.mTitle : resolvedRecord.mBookmarkInternal.mCustomTitle), - parentLocalId, resolvedRecord.mObjectId, resolvedRecord.mBookmarkInternal.mOrder); - } else if (resolvedRecord.mAction.equals(DELETE_RECORD)) { - DeleteBookmarkByLocalId(localId); - } else { - //assert false; - // Ignore of adding an existing object - } - } else { - AddBookmark(resolvedRecord.mBookmarkInternal.mUrl, - (resolvedRecord.mBookmarkInternal.mCustomTitle.isEmpty() ? resolvedRecord.mBookmarkInternal.mTitle : resolvedRecord.mBookmarkInternal.mCustomTitle), - resolvedRecord.mBookmarkInternal.mIsFolder, resolvedRecord.mObjectId, parentLocalId, resolvedRecord.mBookmarkInternal.mOrder); - if (resolvedRecord.mBookmarkInternal.mIsFolder) { - // Check for orphan children - List orphanBookmarksRecords = PopOrphanBookmarksForParent(resolvedRecord.mObjectId); - for (ResolvedRecordToApply bookmarkRecord: orphanBookmarksRecords) { - BookmarkResolver(bookmarkRecord); - } - } - } - - return false; - } - - public void DeleteSyncUser() { - // TODO - } - - public void DeleteSyncCategory() { - // TODO - } - - public void DeleteSyncSiteSettings() { - // TODO - } - - private StringBuilder GetAction(JsonReader reader) throws IOException { - if (null == reader) { - return new StringBuilder(CREATE_RECORD); - } - int action = reader.nextInt(); - if (1 == action) { - return new StringBuilder(UPDATE_RECORD); - } else if (2 == action) { - return new StringBuilder(DELETE_RECORD); - } - - return new StringBuilder(CREATE_RECORD); - } - - private StringBuilder GetDeviceId(JsonReader reader) throws IOException { - StringBuilder deviceId = new StringBuilder(""); - if (null == reader) { - return deviceId; - } - - if (JsonToken.BEGIN_OBJECT == reader.peek()) { - reader.beginObject(); - while (reader.hasNext()) { - reader.nextName(); - if (0 != deviceId.length()) { - deviceId.append(", "); - } - deviceId.append(reader.nextString()); - } - reader.endObject(); - } else { - reader.beginArray(); - while (reader.hasNext()) { - if (0 != deviceId.length()) { - deviceId.append(", "); - } - deviceId.append(reader.nextInt()); - } - reader.endArray(); - } - - return deviceId; - } - - private StringBuilder GetObjectIdJSON(JsonReader reader) throws IOException { - StringBuilder objectId = new StringBuilder(""); - if (null == reader) { - return objectId; - } - - JsonToken objectType = reader.peek(); - if (JsonToken.BEGIN_OBJECT == reader.peek()) { - reader.beginObject(); - while (reader.hasNext()) { - reader.nextName(); - if (0 != objectId.length()) { - objectId.append(", "); - } - objectId.append(reader.nextInt()); - } - reader.endObject(); - } else if (JsonToken.BEGIN_ARRAY == reader.peek()) { - reader.beginArray(); - while (reader.hasNext()) { - if (0 != objectId.length()) { - objectId.append(", "); - } - objectId.append(reader.nextInt()); - } - reader.endArray(); - } else if (JsonToken.NULL == reader.peek()) { - reader.nextNull(); - } else { - assert false; - //objectId = String.valueOf(reader.nextInt()); - } - - return objectId; - } - - private StringBuilder GetObjectDataJSON(JsonReader reader) throws IOException { - if (null == reader) { - return new StringBuilder(""); - } - - return new StringBuilder(reader.nextString()); - } - - private BookmarkInternal GetBookmarkRecord(JsonReader reader) throws IOException { - BookmarkInternal bookmarkInternal = new BookmarkInternal(); - if (null == reader || null == bookmarkInternal) { - return null; - } - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("site")) { - reader.beginObject(); - while (reader.hasNext()) { - name = reader.nextName(); - if (name.equals("location")) { - bookmarkInternal.mUrl = reader.nextString(); - } else if (name.equals("title")) { - bookmarkInternal.mTitle = reader.nextString(); - } else if (name.equals("customTitle")) { - bookmarkInternal.mCustomTitle = reader.nextString(); - } else if (name.equals("lastAccessedTime")) { - bookmarkInternal.mLastAccessedTime = reader.nextLong(); - } else if (name.equals("creationTime")) { - bookmarkInternal.mCreationTime = reader.nextLong(); - } else if (name.equals("favicon")) { - bookmarkInternal.mFavIcon = reader.nextString(); - } else { - assert false; - reader.skipValue(); - } - } - reader.endObject(); - } else if (name.equals("isFolder")) { - if (JsonToken.BOOLEAN == reader.peek()) { - bookmarkInternal.mIsFolder = reader.nextBoolean(); - } else { - bookmarkInternal.mIsFolder = (reader.nextInt() != 0); - } - } else if (name.equals("order")) { - bookmarkInternal.mOrder = reader.nextString(); - } else if (name.equals("parentFolderObjectId")) { - bookmarkInternal.mParentFolderObjectId = GetObjectIdJSON(reader).toString(); - } - else { - reader.skipValue(); - } - } - reader.endObject(); - - return bookmarkInternal; - } - - private StringBuilder GetDeviceName(JsonReader reader) throws IOException { - StringBuilder res = new StringBuilder(""); - - if (null == reader) { - return res; - } - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("name")) { - res.append(reader.nextString()); - } else { - reader.skipValue(); - } - } - reader.endObject(); - - return res; - } - - class EjectedRunnable implements Runnable { - private StringBuilder mJsToExecute; - - public EjectedRunnable(StringBuilder jsToExecute) { - mJsToExecute = jsToExecute; - mJsToExecute.insert(0, "javascript:(function() { "); - mJsToExecute.append(" })()"); - } - - @Override - public void run() { - synchronized (mSyncIsReady) { - if (null == mWebContents || null == mJsToExecute) { - Log.e(TAG, "mWebContents is null"); - return; - } - mWebContents.getNavigationController().loadUrl(new LoadUrlParams(mJsToExecute.toString())); - } - } - } - - class GetBookmarkItemsByLocalIdsRunnable implements Runnable { - public ArrayList mBookmarkItems; - private ArrayList mBookmarkIds; - private String mAction; - - public GetBookmarkItemsByLocalIdsRunnable(ArrayList bookmarkIds, String action) { - mBookmarkIds = bookmarkIds; - mAction = action; - mBookmarkItems = new ArrayList(); - } - - @Override - public void run() { - if (null != mBookmarkIds) { - for (Long id: mBookmarkIds) { - BookmarkItem bookmarkItem = BookmarkItemByBookmarkId(id, /*newBookmarkModelAcquiredByThisRunnableWaiter*/false); - if (null != bookmarkItem) { - mBookmarkItems.add(bookmarkItem); - } else if (mAction.equals(DELETE_RECORD)) { - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - mBookmarkItems.add(BraveBookmarkModel.createBookmarkItem(id, BookmarkType.NORMAL, "", "", false, - defaultFolderId, BookmarkType.NORMAL, true, true)); - } - } - } - - synchronized (this) - { - this.notify(); - } - } - } - - class GetBookmarkIdRunnable implements Runnable { - public BookmarkItem mBookmarkItem; - private long mBookmarkId; - private boolean mNewBookmarkModelAcquiredByThisRunnableWaiter; - - public GetBookmarkIdRunnable(long bookmarkId) { - mBookmarkId = bookmarkId; - mBookmarkItem = null; - } - - public void SetNewBookmarkModelAcquiredByThisRunnableWaiter() { - mNewBookmarkModelAcquiredByThisRunnableWaiter = true; - } - - @Override - public void run() { - mBookmarkItem = BookmarkItemByBookmarkId(mBookmarkId, mNewBookmarkModelAcquiredByThisRunnableWaiter); - - synchronized (this) - { - this.notify(); - } - } - } - - private BookmarkItem BookmarkItemByBookmarkId(long lBookmarkId, boolean newBookmarkModelAcquiredByThisRunnableWaiter) { - BookmarkItem bookmarkItem = null; - BookmarkId bookmarkId = new BookmarkId(lBookmarkId, BookmarkType.NORMAL); - if (null != mNewBookmarkModel && null != bookmarkId) { - // alexeyb: - // In this case it is safe to ignore acquiring of mNewBookmarkModel - // because it is acquired by caller and the caller does not do - // anything until GetBookmarkIdRunnable completes. - // In any other cases `newBookmarkModelAcquiredByThisRunnableWaiter` - // should be used with complete understanding what is going on and - // why it is safe. - if (false == newBookmarkModelAcquiredByThisRunnableWaiter) { - synchronized (mNewBookmarkModel) { - if (mNewBookmarkModel.doesBookmarkExist(bookmarkId)) { - bookmarkItem = mNewBookmarkModel.getBookmarkById(bookmarkId); - } - } - } else { - if (mNewBookmarkModel.doesBookmarkExist(bookmarkId)) { - bookmarkItem = mNewBookmarkModel.getBookmarkById(bookmarkId); - } - } - } - - return bookmarkItem; - } - - class SetExtensiveBookmarkOperationRunnable implements Runnable { - private boolean mExtensiveOperation; - - public SetExtensiveBookmarkOperationRunnable(boolean extensiveOperation) { - mExtensiveOperation = extensiveOperation; - } - - @Override - public void run() { - if (null != mNewBookmarkModel && mNewBookmarkModel.isBookmarkModelLoaded()) { - if (!mExtensiveOperation) { - mNewBookmarkModel.extensiveBookmarkChangesEnded(); - } else { - mNewBookmarkModel.extensiveBookmarkChangesBeginning(); - } - } - - synchronized (this) - { - this.notify(); - } - } - } - - private void SetExtensiveBookmarkOperation(boolean extensiveOperation) { - SetExtensiveBookmarkOperationRunnable extensiveOperationRunnable = new SetExtensiveBookmarkOperationRunnable(extensiveOperation); - if (null == extensiveOperationRunnable) { - return; - } - synchronized (extensiveOperationRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(extensiveOperationRunnable); - - // Wait until runnable is finished - try { - extensiveOperationRunnable.wait(); - } catch (InterruptedException e) { - } - } - } - - class GetDefaultFolderIdRunnable implements Runnable { - public GetDefaultFolderIdRunnable() { - } - - @Override - public void run() { - GetDefaultFolderIdInUIThread(); - - synchronized (this) - { - this.notify(); - } - } - } - - private void GetDefaultFolderId() { - if (Looper.myLooper() == Looper.getMainLooper()) { - GetDefaultFolderIdInUIThread(); - - return; - } - - GetDefaultFolderIdRunnable folderIdRunnable = new GetDefaultFolderIdRunnable(); - if (null == folderIdRunnable) { - return; - } - synchronized (folderIdRunnable) - { - // Execute code on UI thread - ThreadUtils.runOnUiThread(folderIdRunnable); - - // Wait until runnable is finished - try { - folderIdRunnable.wait(); - } catch (InterruptedException e) { - } - } - } - - private void GetDefaultFolderIdInUIThread() { - if (null == mNewBookmarkModel) { - mNewBookmarkModel = new BraveBookmarkModel(); - } - if (null != mNewBookmarkModel) { - // Partner bookmarks need to be loaded explicitly so that BookmarkModel can be loaded. - PartnerBookmarksShim.kickOffReading(mContext); - mNewBookmarkModel.finishLoadingBookmarkModel(new Runnable() { - @Override - public void run() { - BookmarkId bookmarkId = mNewBookmarkModel.getMobileFolderId(); - - mDefaultFolder = bookmarkId; - } - }); - } - } - - class EditBookmarkRunnable implements Runnable { - private long mBookmarkId; - private String mUrl; - private String mTitle; - private long mParentLocalId; - - public EditBookmarkRunnable(long bookmarkId, String url, String title, long parentLocalId) { - mBookmarkId = bookmarkId; - mUrl = url; - mTitle = title; - mParentLocalId = parentLocalId; - } - - @Override - public void run() { - BookmarkId parentBookmarkId = null; - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - if (defaultFolderId != mParentLocalId) { - parentBookmarkId = new BookmarkId(mParentLocalId, BookmarkType.NORMAL); - } else { - parentBookmarkId = mDefaultFolder; - assert mDefaultFolder != null; - } - BookmarkId bookmarkId = new BookmarkId(mBookmarkId, BookmarkType.NORMAL); - if (null != mNewBookmarkModel && null != bookmarkId) { - synchronized (mNewBookmarkModel) { - if (mNewBookmarkModel.doesBookmarkExist(bookmarkId)) { - BookmarkItem bookmarkItem = mNewBookmarkModel.getBookmarkById(bookmarkId); - if (null != bookmarkItem) { - if (!bookmarkItem.getTitle().equals(mTitle)) { - mNewBookmarkModel.setBookmarkTitle(bookmarkId, mTitle); - } - if (!mUrl.isEmpty() && bookmarkItem.isUrlEditable()) { - String fixedUrl = UrlFormatter.fixupUrl(mUrl).getSpec(); - if (null != fixedUrl && !fixedUrl.equals(bookmarkItem.getTitle())) { - mNewBookmarkModel.setBookmarkUrl(bookmarkId, fixedUrl); - } - } - if (bookmarkItem.getParentId().getId() != mParentLocalId) { - mNewBookmarkModel.moveBookmark(bookmarkId, parentBookmarkId); - } - } - } - } - } - - synchronized (this) - { - this.notify(); - } - } - } - - class AddBookmarkRunnable implements Runnable { - private BookmarkId mBookmarkId; - private String mUrl; - private String mTitle; - private boolean misFolder; - private long mParentLocalId; - - public AddBookmarkRunnable(String url, String title, boolean isFolder, long parentLocalId) { - mUrl = url; - mTitle = title; - misFolder = isFolder; - mParentLocalId = parentLocalId; - } - - @Override - public void run() { - BookmarkId parentBookmarkId = null; - long defaultFolderId = (null != mDefaultFolder ? mDefaultFolder.getId() : 0); - if (defaultFolderId != mParentLocalId) { - parentBookmarkId = new BookmarkId(mParentLocalId, BookmarkType.NORMAL); - } else { - parentBookmarkId = mDefaultFolder; - } - if (null != mNewBookmarkModel) { - synchronized (mNewBookmarkModel) { - if (!misFolder) { - mBookmarkId = BraveBookmarkUtils.addBookmarkSilently(mContext, mNewBookmarkModel, mTitle, mUrl, parentBookmarkId); - } else { - mBookmarkId = mNewBookmarkModel.addFolder(parentBookmarkId, 0, mTitle); - } - } - } - - synchronized (this) - { - this.notify(); - } - } - } - - public boolean IsSyncEnabled() { - boolean prefSyncDefault = false; - boolean prefSync = mSharedPreferences.getBoolean( - PREF_SYNC_SWITCH, prefSyncDefault); - return prefSync; - } - - public void SetSyncEnabled(boolean syncEnabled) { - mSharedPreferences.edit().putBoolean(PREF_SYNC_SWITCH, syncEnabled).apply(); - } - - public boolean IsSyncBookmarksEnabled() { - boolean prefSyncBookmarksDefault = true; - boolean prefSyncBookmarks = mSharedPreferences.getBoolean( - PREF_SYNC_BOOKMARKS, prefSyncBookmarksDefault); - return prefSyncBookmarks; - } - - public void SetSyncBookmarksEnabled(boolean syncBookmarksEnabled) { - mSharedPreferences.edit().putBoolean(PREF_SYNC_BOOKMARKS, syncBookmarksEnabled).apply(); - } - - class SyncThread extends Thread { - @Override - public void run() { - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - mTimeLastFetch = sharedPref.getLong(PREF_LAST_FETCH_NAME, 0); - mDeviceId = sharedPref.getString(PREF_DEVICE_ID, null); - mDeviceName = sharedPref.getString(PREF_SYNC_DEVICE_NAME, null); - mBaseOrder = sharedPref.getString(PREF_BASE_ORDER, null); - mLastOrder = sharedPref.getString(PREF_LAST_ORDER, null); - InitOrphanBookmarks(); - - for (;;) { - try { - if (IsSyncEnabled()) { - InitSync(false, false); - Calendar currentTime = Calendar.getInstance(); - long timeLastFetch = currentTime.getTimeInMillis(); - if (!mFetchInProgress || timeLastFetch - mTimeLastFetchExecuted > INTERVAL_TO_REFETCH_RECORDS) { - mFetchInProgress = false; - FetchSyncRecords("", ""); - } - } - for (int i = 0; i < BraveSyncWorker.SYNC_SLEEP_ATTEMPTS_COUNT; i++) { - if (i == BraveSyncWorker.SYNC_SLEEP_ATTEMPTS_COUNT / 2) { - // SZ: preventing from page been frozen, we do that on the middle of the loop - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - synchronized (mSyncIsReady) { - if (null != mWebContents) { - mWebContents.onHide(); - mWebContents.onShow(); - } - if (mJSWebContents != null) { - mJSWebContents.onHide(); - mJSWebContents.onShow(); - } - } - } - }); - } - Thread.sleep(BraveSyncWorker.INTERVAL_TO_FETCH_RECORDS / BraveSyncWorker.SYNC_SLEEP_ATTEMPTS_COUNT); - if (mInterruptSyncSleep) { - break; - } - } - } - catch(Exception exc) { - // Just ignore it if we cannot sync - Log.e(TAG, "Sync loop exception: " + exc); - } - if (mStopThread) { - break; - } - } - } - } - - class SendSyncDataThread extends Thread { - @Override - public void run() { - for (;;) { - try { - Thread.sleep(BraveSyncWorker.INTERVAL_TO_SEND_SYNC_RECORDS); - if (IsSyncEnabled() && mSyncIsReady.mReady) { - SendBulkBookmarks(); - } - } catch (InterruptedException e) { - Log.w(TAG, "Send sync data thread interrupted: " + e); - } - if (mStopThread) { - break; - } - } - } - } - - public void ResetSync() { - ResetSyncWebContents(); - SetSyncEnabled(false); - mSyncIsReady.Reset(); - mSyncIsReady.mShouldResetSync = true; - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.remove(PREF_LAST_FETCH_NAME); - editor.remove(PREF_DEVICE_ID); - editor.remove(PREF_BASE_ORDER); - editor.remove(PREF_LAST_ORDER); - editor.remove(PREF_SEED); - editor.remove(PREF_SYNC_DEVICE_NAME); - editor.apply(); - final String seed = mSeed; - mSeed = null; - mDeviceId = null; - mDeviceName = null; - mBaseOrder = null; - mLastOrder = null; - mTimeLastFetch = 0; - mTimeLastFetchExecuted = 0; - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onResetSync(); - } - new Thread() { - @Override - public void run() { - nativeResetSync(ORIGINAL_SEED_KEY); - nativeResetSync(SyncRecordType.BOOKMARKS + CREATE_RECORD); - nativeResetSync(SyncRecordType.BOOKMARKS + UPDATE_RECORD); - nativeResetSync(SyncRecordType.BOOKMARKS + DELETE_RECORD); - nativeResetSync(SyncRecordType.PREFERENCES + CREATE_RECORD); - nativeResetSync(SyncRecordType.PREFERENCES + UPDATE_RECORD); - nativeResetSync(SyncRecordType.PREFERENCES + DELETE_RECORD); - nativeResetSync(DEVICES_NAMES); - nativeResetSync(ORPHAN_BOOKMARKS); - nativeResetSync(THIS_DEVICE_OBJECT_ID); - mOrphanBookmarks.clear(); - SaveObjectId(ORIGINAL_SEED_KEY, seed, "", true); - // TODO for other categories type - } - }.start(); - } - - public void InitSync(boolean calledFromUIThread, boolean startNewChain) { - if (!startNewChain) { - // Here we already supposed to get existing seed - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - if (null == mSeed || mSeed.isEmpty()) { - mSeed = sharedPref.getString(PREF_SEED, null); - } - if (null == mSeed || mSeed.isEmpty()) { - return; - } - } - // Init sync WebView - if (!calledFromUIThread) { - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - TrySync(); - } - }); - } else { - TrySync(); - } - } - - class JsObject { - @JavascriptInterface - public void handleMessage(String message, String arg1, String arg2, String arg3, boolean arg4) { - if (!message.equals("sync-debug")) { - Log.i(TAG, "!!!message == " + message); - } - switch (message) { - case "get-init-data": - break; - case "got-init-data": - GotInitData(); - break; - case "save-init-data": - SaveInitData(arg1, arg2); - break; - case "sync-debug": - if (null != arg1) { - Log.i(TAG, "!!!sync-debug: " + arg1); - } - break; - case "fetch-sync-records": - mSyncIsReady.mFetchRecordsReady = true; - break; - case "resolve-sync-records": - mSyncIsReady.mResolveRecordsReady = true; - break; - case "resolved-sync-records": - ResolvedSyncRecords(arg1, arg2); - break; - case "send-sync-records": - mSyncIsReady.mSendRecordsReady = true; - break; - case "delete-sync-user": - mSyncIsReady.mDeleteUserReady = true; - break; - case "deleted-sync-user": - break; - case "delete-sync-category": - mSyncIsReady.mDeleteCategoryReady = true; - break; - case "delete-sync-site-settings": - mSyncIsReady.mDeleteSiteSettingsReady = true; - break; - case "sync-ready": - if (mBaseOrder == null || mBaseOrder.isEmpty()) { - // Get sync order prefix - CallScript(new StringBuilder(String.format("javascript:callbackList['get-bookmarks-base-order'](null, %1$s, 'android')", mDeviceId))); - } else { - StartSync(); - } - break; - case "get-existing-objects": - SendResolveSyncRecords(arg1, GetExistingObjects(arg1, arg2, arg3, arg4)); - break; - case "get-bookmarks-base-order": - break; - case "save-bookmarks-base-order": - assert arg1 != null; - // Save base order before sending local bookmarks - mBaseOrder = arg1; - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(PREF_BASE_ORDER, mBaseOrder); - editor.apply(); - StartSync(); - break; - case "get-bookmark-order": - break; - case "save-bookmark-order": - //Log.i(TAG, "!!!save-bookmark-order1 arg1 == " + arg1 + ", arg2 == " + arg2 + ", arg3 == " + arg3); - break; - case "sync-setup-error": - Log.e(TAG, "sync-setup-error , !!!arg1 == " + arg1 + ", arg2 == " + arg2); - if (!SyncHasBeenSetup()) { - // We need to reset state before the next attempt to set up sync - ResetSync(); - } else { - // We need to reset web contents to recreate it when network is up again - ResetSyncWebContents(); - } - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError(arg1); - } - break; - default: - Log.w(TAG, "!!!message == " + message + ", !!!arg1 == " + arg1 + ", arg2 == " + arg2); - break; - } - } - } - - class JsObjectWordsToBytes { - @JavascriptInterface - public void cryptoOutput(String result) { - if (null == result || 0 == result.length()) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError("Incorrect crypto output"); - } - return; - } - - JsonReader reader = null; - String seed = ""; - try { - JSONObject data = new JSONObject(result); - Iterator it = data.keys(); - // Pick up keys to sort them, as it's not always returned in proper order - // We use Integer for proper sorting, as strings are sorted incorrectly - ArrayList keys = new ArrayList(); - while (it.hasNext()) { - String key = it.next(); - keys.add(Integer.parseInt(key)); - } - Collections.sort(keys); - // Get data by sorted keys - for (Integer key : keys) { - String value = data.getString(Integer.toString(key)); - if (0 != seed.length()) { - seed += ","; - } - seed += value; - } - } catch (JSONException e) { - Log.e(TAG, "cryptoOutput JSONException error " + e); - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError("cryptoOutput JSONException error " + e); - } - } - //Log.i(TAG, "!!!seed == " + seed); - - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSeedReceived(seed, true, false); - } - } - - @JavascriptInterface - public void cryptoOutputCodeWords(String result) { - if (null == result || 0 == result.length()) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError("Incorrect crypto output for code words"); - } - return; - } - - String[] codeWords = result.replace('\"', ' ').trim().split(" "); - - if (NICEWARE_WORD_COUNT != codeWords.length && BIP39_WORD_COUNT != codeWords.length) { - Log.e(TAG, "Incorrect number of code words"); - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError("Incorrect number of code words"); - } - return; - } - - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onCodeWordsReceived(codeWords); - } - } - - @JavascriptInterface - public void cryptoOutputError(String error) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError(error); - } - } - } - - public void InitJSWebView(BraveSyncScreensObserver syncScreensObserver) { - try { - synchronized (mSyncIsReady) { - if (null == mJSWebContents) { - mJSWebContents = WebContentsFactory.createWebContents(false, true); - if (null != mJSWebContents) { - ContentView cv = ContentView.createContentView(mContext, mJSWebContents); - mJSWebContents.initialize(null, ViewAndroidDelegate.createBasicDelegate(cv), cv, new WindowAndroid(mContext), WebContents.createDefaultInternalsHolder()); - mJSViewEventSink = ViewEventSinkImpl.from(mJSWebContents); - if (null != mJSViewEventSink) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - initJSContenViewCore(); - } else { - getJSWebContentsInjector().addPossiblyUnsafeInterface(new JsObjectWordsToBytes(), "injectedObject", null); - } - - String toLoad = ""; - } catch (IOException exc) {} - LoadUrlParams loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(toLoad, "text/html", false, "file:///android_asset/", null); - loadUrlParams.setCanLoadLocalResources(true); - mJSWebContents.getNavigationController().loadUrl(loadUrlParams); - } - } - } - } - } catch (Exception exc) { - // Ignoring sync exception, we will try it on next loop execution - Log.e(TAG, "InitJSWebView exception: " + exc); - } - // Always overwrite observer since it's focused on specific activity - mSyncScreensObserver = syncScreensObserver; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - private void initJSContenViewCore() { - getJSWebContentsInjector().addPossiblyUnsafeInterface(new JsObjectWordsToBytes(), "injectedObject", JavascriptInterface.class); - } - - public void GetNumber(String[] words) { - synchronized (mSyncIsReady) { - if (null == mJSWebContents) { - return; - } - String wordsJSArray = ""; - for (int i = 0; i < words.length; i++) { - if (0 == i) { - wordsJSArray = "'"; - } else { - wordsJSArray += " "; - } - wordsJSArray += words[i]; - if (words.length - 1 == i) { - wordsJSArray += "'"; - } - } - //Log.i(TAG, "!!!words == " + wordsJSArray); - mJSWebContents.getNavigationController().loadUrl( - new LoadUrlParams("javascript:(function() { " + String.format("javascript:getBytesFromWords(%1$s)", wordsJSArray) + " })()")); - } - } - - private JavascriptInjector getWebContentsInjector() { - synchronized (mSyncIsReady) { - if (mWebContentsInjector == null) { - mWebContentsInjector = JavascriptInjector.fromWebContents(mWebContents); - } - return mWebContentsInjector; - } - } - - private JavascriptInjector getJSWebContentsInjector() { - synchronized (mSyncIsReady) { - if (mJSWebContentsInjector == null) { - mJSWebContentsInjector = JavascriptInjector.fromWebContents(mJSWebContents); - } - return mJSWebContentsInjector; - } - } - - public void GetCodeWords() { - synchronized (mSyncIsReady) { - if (null == mJSWebContents) { - Log.e(TAG, "Error on receiving code words. JSWebContents is null."); - return; - } - if (null == mSeed || mSeed.isEmpty()) { - Log.e(TAG, "Error on receiving code words. Seed is empty."); - return; - } - mJSWebContents.getNavigationController().loadUrl( - new LoadUrlParams("javascript:(function() { " + String.format("javascript:getCodeWordsFromSeed([%1$s])", mSeed) + " })()")); - } - } - - public void InterruptSyncSleep() { - mInterruptSyncSleep = true; - } - - private String GetBookmarkOrder(String localId, boolean generateIfEmpty) { - String currentOrder = GetBookmarkOrder(localId); - if (!currentOrder.isEmpty() || !generateIfEmpty) { - return currentOrder; - } - if (mLastOrder == null || mLastOrder.isEmpty()) { - assert mBaseOrder != null; - // It is the very first element - mLastOrder = mBaseOrder + "1"; - } else { - assert !mLastOrder.isEmpty(); - String[] numbers = mLastOrder.split("\\."); - assert numbers.length > 0; - int newLastNumber = Integer.parseInt(numbers[numbers.length - 1]) + 1; - mLastOrder = numbers[0] + "."; - for (int i = 1; i < numbers.length - 1; i++) { - mLastOrder += numbers[i] + "."; - } - mLastOrder += newLastNumber; - } - SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(PREF_LAST_ORDER, mLastOrder); - editor.apply(); - return mLastOrder; - } - - private void StartSync() { - mSyncIsReady.mReady = true; - new Thread() { - @Override - public void run() { - FetchSyncRecords("", ""); - } - }.start(); - } - - private void PushOrphanBookmark(ResolvedRecordToApply record) { - synchronized (mOrphanBookmarks) { - mOrphanBookmarks.add(record); - SaveOrphanBookmarks(); - } - } - - private ArrayList PopOrphanBookmarksForParent(String parentId) { - ArrayList result = new ArrayList(); - synchronized (mOrphanBookmarks) { - boolean saveOrphanBookmarks = false; - for (int i = 0; i < mOrphanBookmarks.size(); i++) { - if (mOrphanBookmarks.get(i).mBookmarkInternal == null) { - assert false; - continue; - } - if (mOrphanBookmarks.get(i).mBookmarkInternal.mParentFolderObjectId.equals(parentId)) { - result.add(mOrphanBookmarks.remove(i--)); - saveOrphanBookmarks = true; - } - } - if (saveOrphanBookmarks) { - SaveOrphanBookmarks(); - } - } - return result; - } - - private void InitOrphanBookmarks() { - synchronized (mOrphanBookmarks) { - String object = nativeGetObjectIdByLocalId(ORPHAN_BOOKMARKS); - if (object.isEmpty()) { - return; - } - try { - JSONObject result = new JSONObject(object); - JSONArray orphans = result.getJSONArray("orphans"); - for (int i = 0; i < orphans.length(); i++) { - JSONObject orphan = orphans.getJSONObject(i); - mOrphanBookmarks.add(ResolvedRecordToApplyFromJSONObject(orphan)); - } - } catch (JSONException e) { - Log.e(TAG, "InitOrphanBookmarks error: " + e); - } - } - } - - private void SaveOrphanBookmarks() { - JSONObject result = new JSONObject(); - try { - JSONArray orphans = new JSONArray(); - for (ResolvedRecordToApply orphan: mOrphanBookmarks) { - orphans.put(orphan.toJSONObject()); - } - result.put("orphans", orphans); - } catch (JSONException e) { - Log.e(TAG, "SaveOrphanBookmarks error: " + e); - } - nativeSaveObjectId(ORPHAN_BOOKMARKS, result.toString(), ""); - } - - private boolean SyncHasBeenSetup() { - // If base order is null or empty, it means that sync hasn't been set up yet - return mBaseOrder != null && !mBaseOrder.isEmpty(); - } + private native boolean nativeIsFirstSetupComplete(long nativeBraveSyncWorker); - private native String nativeGetObjectIdByLocalId(String localId); - private native String nativeGetLocalIdByObjectId(String objectId); - private native void nativeSaveObjectId(String localId, String objectIdJSON, String objectId); - private native void nativeDeleteByLocalId(String localId); - private native void nativeClear(); - private native void nativeResetSync(String key); - } + private native void nativeResetSync(long nativeBraveSyncWorker); +} diff --git a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkModel.java b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkModel.java deleted file mode 100644 index e34ffae34f54..000000000000 --- a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkModel.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.bookmarks; - -import org.chromium.chrome.browser.bookmarks.BookmarkBridge; -import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; -import org.chromium.components.bookmarks.BookmarkId; - -// see org.brave.bytecode.BraveBookmarkModelClassAdapter -public class BraveBookmarkModel extends BookmarkModel { - - public void deleteBookmarkSilently(BookmarkId bookmark) { - assert null != bookmark; - deleteBookmark(bookmark); - } - - public void extensiveBookmarkChangesBeginning() { - assert false; - } - - public void extensiveBookmarkChangesEnded() { - assert false; - } - - public static BookmarkItem createBookmarkItem(long id, int type, String title, String url, - boolean isFolder, long parentId, int parentIdType, boolean isEditable, - boolean isManaged) { - assert false; - return null; - } - - /** - * Calls {@link BookmarkBridge#moveBookmark(BookmarkId, BookmarkId, int)} for the given - * bookmark. The bookmark is appended at the end. Call that method from Brave's sync only - */ - public void moveBookmark(BookmarkId bookmarkId, BookmarkId newParentId) { - assert isBookmarkModelLoaded(); - if (!isBookmarkModelLoaded()) { - return; - } - int appendedIndex = getChildCount(newParentId); - moveBookmark(bookmarkId, newParentId, appendedIndex); - } -} diff --git a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUtils.java b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUtils.java deleted file mode 100644 index f228501be425..000000000000 --- a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.bookmarks; - -import android.content.Context; - -import org.chromium.components.bookmarks.BookmarkId; - -public class BraveBookmarkUtils extends BookmarkUtils { - - /** - * Adds a bookmark with the given title and url to the provided parent. Provides - * no visual feedback that a bookmark has been added. - * - * @param title The title of the bookmark. - * @param url The URL of the new bookmark. - * @param parent The parentId of the bookmark - */ - public static BookmarkId addBookmarkSilently( - Context context, BookmarkModel bookmarkModel, String title, String url, BookmarkId parent) { - if (parent == null || !bookmarkModel.doesBookmarkExist(parent)) { - parent = bookmarkModel.getDefaultFolder(); - } - - return bookmarkModel.addBookmark(parent, bookmarkModel.getChildCount(parent), title, url); - } - -} diff --git a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkWorker.java b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkWorker.java deleted file mode 100644 index 78e2aa7281d1..000000000000 --- a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkWorker.java +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.bookmarks; - -import org.chromium.chrome.browser.BraveActivity; -import org.chromium.chrome.browser.BraveRewardsHelper; -import org.chromium.chrome.browser.BraveSyncWorker; -import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; -import org.chromium.components.bookmarks.BookmarkId; - -import java.util.ArrayList; -import java.util.List; - -public class BraveBookmarkWorker { - public static void CreateUpdateBookmark(boolean bCreate, BookmarkItem bookmarkItem) { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.CreateUpdateBookmark(bCreate, bookmarkItem); - } - } - - public static void moveBookmarks(List bookmarkIds, BookmarkId newParentId, - BookmarkModel bookmarkModel) { - BookmarkItem[] bookmarksToMove = new BookmarkItem[bookmarkIds.size()]; - for (int i = 0; i < bookmarkIds.size(); ++i) { - bookmarksToMove[i] = bookmarkModel.getBookmarkById(bookmarkIds.get(i)); - } - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.CreateUpdateDeleteBookmarks( - BraveSyncWorker.UPDATE_RECORD, bookmarksToMove, true, false); - } - } - - public static void syncDeletedBookmarks(List bookmarks) { - if (bookmarks == null || bookmarks.size() == 0) { - return; - } - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.DeleteBookmarks( - bookmarks.toArray(new BookmarkItem[bookmarks.size()])); - } - } - - public static List GetChildren(BookmarkItem parent, BookmarkModel bookmarkModel) { - List res = new ArrayList(); - if (!parent.isFolder()) { - return res; - } - res = bookmarkModel.getBookmarksForFolder(parent.getId()); - List newList = new ArrayList(); - for (BookmarkItem item : res) { - if (!item.isFolder()) { - continue; - } - newList.addAll(bookmarkModel.getBookmarksForFolder(item.getId())); - } - res.addAll(newList); - - return res; - } -} diff --git a/android/java/org/chromium/chrome/browser/preferences/BraveSyncScreensObserver.java b/android/java/org/chromium/chrome/browser/preferences/BraveSyncScreensObserver.java deleted file mode 100644 index 9bdcae06cd29..000000000000 --- a/android/java/org/chromium/chrome/browser/preferences/BraveSyncScreensObserver.java +++ /dev/null @@ -1,40 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.preferences; - -/** - * Allows monitoring of JavaScript results. - */ -public interface BraveSyncScreensObserver { - /** - * Informs when the words code provided is incorrect - */ - public void onSyncError(String message); - - /** - * Informs when the seed in received - */ - public void onSeedReceived(String seed, boolean fromCodeWords, boolean afterInitialization); - - /** - * Informs when the code words are received - */ - public void onCodeWordsReceived(String[] codeWords); - - /** - * Informs when the list of devices is available - */ - public void onDevicesAvailable(); - - /** - * Informs when the sync is reset - */ - public void onResetSync(); - - /** - * Returns true if sync settings with devices list is currently shown - */ - public boolean shouldLoadDevices(); -} diff --git a/android/java/org/chromium/chrome/browser/settings/BraveSyncScreensPreference.java b/android/java/org/chromium/chrome/browser/settings/BraveSyncScreensPreference.java index 474ebe84dc22..02abd8b14671 100644 --- a/android/java/org/chromium/chrome/browser/settings/BraveSyncScreensPreference.java +++ b/android/java/org/chromium/chrome/browser/settings/BraveSyncScreensPreference.java @@ -22,18 +22,18 @@ import android.hardware.Camera; import android.os.Build; import android.os.Bundle; -import android.os.CountDownTimer; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.support.v7.widget.AppCompatImageView; import android.text.Editable; import android.text.SpannableString; +import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.util.DisplayMetrics; import android.view.LayoutInflater; -import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; @@ -69,1155 +69,883 @@ import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.BraveActivity; -import org.chromium.chrome.browser.BraveRewardsHelper; import org.chromium.chrome.browser.BraveSyncWorker; -// TODO(sergz): Uncomment when we fully migrate on sync v2. Had a headache -// that pref calls should be called from UI thread only. It would lead -// to significant changes in the current javascript based BraveSyncWorker -// import org.chromium.chrome.browser.preferences.BravePrefServiceBridge; -import org.chromium.chrome.browser.preferences.BraveSyncScreensObserver; import org.chromium.chrome.browser.qrreader.BarcodeTracker; import org.chromium.chrome.browser.qrreader.BarcodeTrackerFactory; import org.chromium.chrome.browser.qrreader.CameraSource; import org.chromium.chrome.browser.qrreader.CameraSourcePreview; import org.chromium.chrome.browser.settings.BravePreferenceFragment; import org.chromium.chrome.browser.settings.SettingsActivity; -import org.chromium.chrome.browser.sync.BraveSyncService; +import org.chromium.chrome.browser.settings.SettingsLauncher; +import org.chromium.chrome.browser.sync.BraveSyncDevices; +import org.chromium.chrome.browser.sync.settings.BraveManageSyncSettings; import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.base.DeviceFormFactor; import java.io.IOException; import java.lang.Runnable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; /** * Settings fragment that allows to control Sync functionality. */ public class BraveSyncScreensPreference extends BravePreferenceFragment - implements View.OnClickListener, SettingsActivity.OnBackPressedListener, - CompoundButton.OnCheckedChangeListener, BarcodeTracker.BarcodeGraphicTrackerCallback, - BraveSyncService.GetSettingsAndDevicesCallback { - - private static final String TAG = "SYNC"; - // Permission request codes need to be < 256 - private static final int RC_HANDLE_CAMERA_PERM = 2; - // Intent request code to handle updating play services if needed. - private static final int RC_HANDLE_GMS = 9001; - // For QR code generation - private static final int WHITE = 0xFFFFFFFF; - private static final int BLACK = 0xFF000000; - private static final int WIDTH = 300; - // For view sizes limit - private static final int MAX_WIDTH = 512; - private static final int MAX_HEIGHT = 1024; - // Wait time out - private static final int WAIT_TIMEOUT = 120000; - // Timeout to show cancel button while loading devices on sync chain creation - private static final int CANCEL_LOAD_BUTTON_TIMEOUT = 15*1000; - - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // private BraveSyncService mSyncService; - // private BraveSyncServiceObserver mSyncServiceObserver; - private BraveSyncScreensObserver mSyncScreensObserver; - private Switch mSyncSwitchBookmarks; - // The have a sync code button displayed in the Sync view. - private Button mScanChainCodeButton; - private Button mStartNewChainButton; - private Button mEnterCodeWordsButton; - private Button mDoneButton; - private Button mDoneLaptopButton; - private Button mUseCameraButton; - private Button mConfirmCodeWordsButton; - private ImageButton mMobileButton; - private ImageButton mLaptopButton; - private ImageButton mPasteButton; - private Button mCopyButton; - private Button mAddDeviceButton; - private Button mCancelLoadingButton; - private Timer mCancelLoadingButtonUpdater; - private Button mRemoveDeviceButton; - private Button mQRCodeButton; - private Button mCodeWordsButton; - // Brave Sync message text view - private TextView mBraveSyncTextViewInitial; - private TextView mBraveSyncTextViewSyncChainCode; - private TextView mBraveSyncTextViewAddMobileDevice; - private TextView mBraveSyncTextViewAddLaptop; - private TextView mBraveSyncWarningTextViewAddMobileDevice; - private TextView mBraveSyncWarningTextViewAddLaptop; - private TextView mBraveSyncTextDevicesTitle; - private TextView mBraveSyncWordCountTitle; - private TextView mBraveSyncAddDeviceCodeWords; - private CameraSource mCameraSource; - private CameraSourcePreview mCameraSourcePreview; - private String mDeviceName = ""; - private ListView mDevicesListView; - private ArrayAdapter mDevicesAdapter; - private List mDevicesList; - private ScrollView mScrollViewSyncInitial; - private ScrollView mScrollViewSyncChainCode; - private ScrollView mScrollViewSyncStartChain; - private ScrollView mScrollViewAddMobileDevice; - private ScrollView mScrollViewAddLaptop; - private ScrollView mScrollViewEnterCodeWords; - private ScrollView mScrollViewSyncDone; - private LayoutInflater mInflater; - private ImageView mQRCodeImage; - private CountDownTimer mTimeoutTimer; - private LinearLayout mLayoutSyncStartChain; - private EditText mCodeWords; - private FrameLayout mLayoutMobile; - private FrameLayout mLayoutLaptop; - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - // Checks the orientation of the screen - if (newConfig.orientation != Configuration.ORIENTATION_UNDEFINED - && null != mCameraSourcePreview) { - mCameraSourcePreview.stop(); - try { - startCameraSource(); - } catch (SecurityException exc) { - } - } - adjustImageButtons(newConfig.orientation); - } - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (ensureCameraPermission()) { - createCameraSource(true, false); - } - mInflater = inflater; - // Read which category we should be showing. - return mInflater.inflate(R.layout.brave_sync_layout, container, false); - } - - private boolean ensureCameraPermission() { - if (ActivityCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.CAMERA) - == PackageManager.PERMISSION_GRANTED){ - return true; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions( - new String[]{Manifest.permission.CAMERA}, RC_HANDLE_CAMERA_PERM); - } - - return false; - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String[] permissions, - int[] grantResults) { - if (requestCode != RC_HANDLE_CAMERA_PERM) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - return; - } - - if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // we have permission, so create the camerasource - createCameraSource(true, false); - - return; - } - - Log.e(TAG, "Permission not granted: results len = " + grantResults.length + - " Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)")); - // We still allow to enter words - //getActivity().onBackPressed(); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - getActivity().setTitle(R.string.sign_in_sync); - - // mDeviceName = BravePrefServiceBridge.getInstance().getSyncDeviceName(); - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - mDeviceName = sharedPref.getString(BraveSyncWorker.PREF_SYNC_DEVICE_NAME, ""); - - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - if (null == mSyncScreensObserver) { - mSyncScreensObserver = new BraveSyncScreensObserver() { - @Override - public void onSyncError(String message) { - try { - if (null == getActivity()) { - return; - } - if (null != message && !message.isEmpty()) { - if (message.equals("Credential server response 400. Signed request body of the client timestamp is required.")) { - message = getResources().getString(R.string.sync_requires_correct_time); - } - message = " [" + message + "]"; - } - final String messageFinal = (null == message) ? "" : message; - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - cancelTimeoutTimer(); - showEndDialog(getResources().getString(R.string.sync_device_failure) + messageFinal); - } - }); - } catch(Exception exc) { - Log.e(TAG, "onSyncError exception: " + exc); - } - } - - @Override - public void onSeedReceived(String seed, boolean fromCodeWords, boolean afterInitialization) { - try { - if (fromCodeWords) { - assert !afterInitialization; - if (!isBarCodeValid(seed, false)) { - showEndDialog(getResources().getString(R.string.sync_device_failure)); - } - //Log.i(TAG, "!!!received seed == " + seed); - // Save seed and deviceId in preferences - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(BraveSyncWorker.PREF_SEED, seed); - editor.apply(); - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - cancelTimeoutTimer(); - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.SetSyncEnabled(true); - mainActivity.mBraveSyncWorker.InitSync(true, false); - } - setAppropriateView(); - } - }); - } else if (afterInitialization) { - assert !fromCodeWords; - if (null != seed && !seed.isEmpty()) { - if ((null != mScrollViewAddMobileDevice) && (View.VISIBLE == mScrollViewAddMobileDevice.getVisibility())) { - String[] seeds = seed.split(","); - if (seeds.length != 32) { - Log.e(TAG, "Incorrect seed for QR code"); - } - String qrData = ""; - for (String s : seeds) { - String hex = Integer.toHexString(Integer.parseInt(s.trim(), 10)); - if (hex.length() == 1) { - hex = "0" + hex; - } - qrData += hex; - } - final String qrDataFinal = qrData; - //Log.i(TAG, "Generate QR with data: " + qrDataFinal); - new Thread(new Runnable() { - @Override - public void run() { - // Generate QR code - BitMatrix result; - try { - result = new MultiFormatWriter().encode(qrDataFinal, BarcodeFormat.QR_CODE, WIDTH, WIDTH, null); - } catch (WriterException e) { - Log.e(TAG, "QR code unsupported format: " + e); - return; - } - int w = result.getWidth(); - int h = result.getHeight(); - int[] pixels = new int[w * h]; - for (int y = 0; y < h; y++) { - int offset = y * w; - for (int x = 0; x < w; x++) { - pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; - } - } - Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, WIDTH, 0, 0, w, h); - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - cancelTimeoutTimer(); - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.SetSyncEnabled(true); - } - mQRCodeImage.setImageBitmap(bitmap); - mQRCodeImage.invalidate(); - } - }); - } - }).start(); - } else if ((null != mScrollViewAddLaptop) && (View.VISIBLE == mScrollViewAddLaptop.getVisibility())) { - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.GetCodeWords(); - } - } - }); - } - } - } else { - Log.e(TAG, "Unknown flag on receiving seed"); - assert false; - } - } catch(Exception exc) { - Log.e(TAG, "onSeedReceived exception: " + exc); - } - } - - @Override - public void onCodeWordsReceived(String[] codeWords) { - try { - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - cancelTimeoutTimer(); - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.SetSyncEnabled(true); - } - String words = ""; - for (int i = 0; i < codeWords.length; i++) { - words = words + " " + codeWords[i].trim(); - } - mBraveSyncAddDeviceCodeWords.setText(words.trim()); - } - }); - } catch(Exception exc) { - Log.e(TAG, "onCodeWordsReceived exception: " + exc); - } - } - - @Override - public void onDevicesAvailable() { - try { - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (View.VISIBLE != mScrollViewSyncDone.getVisibility()) { - Log.w(TAG, "No need to load devices for other pages"); - return; - } - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - String currentDeviceId = sharedPref.getString(BraveSyncWorker.PREF_DEVICE_ID, ""); - // Load other devices in chain - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - new Thread(new Runnable() { - @Override - public void run() { - ArrayList devices = mainActivity.mBraveSyncWorker.GetAllDevices(); - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - ViewGroup insertPoint = (ViewGroup) getView().findViewById(R.id.brave_sync_devices); - insertPoint.removeAllViews(); - cancelTimeoutTimer(); - int index = 0; - for (BraveSyncWorker.ResolvedRecordToApply device : devices) { - View separator = (View) mInflater.inflate(R.layout.menu_separator, null); - View listItemView = (View) mInflater.inflate(R.layout.brave_sync_device, null); - if (null != listItemView && null != separator && null != insertPoint) { - TextView textView = (TextView) listItemView.findViewById(R.id.brave_sync_device_text); - if (null != textView) { - textView.setText(device.mDeviceName); - } - AppCompatImageView deleteButton = (AppCompatImageView) listItemView.findViewById(R.id.brave_sync_remove_device); - if (null != deleteButton) { - if (currentDeviceId.equals(device.mDeviceId)) { - // Current device is deleted by button on the bottom - deleteButton.setVisibility(View.GONE); - if (null != textView) { - // Highlight curret device - textView.setTextColor(ApiCompatibilityUtils.getColor(getActivity().getResources(), R.color.brave_theme_color)); - String currentDevice = device.mDeviceName + " " + getResources().getString(R.string.brave_sync_this_device_text); - textView.setText(currentDevice); - } - if (null != mRemoveDeviceButton) { - mRemoveDeviceButton.setTag(device); - mRemoveDeviceButton.setVisibility(View.VISIBLE); - mRemoveDeviceButton.setEnabled(true); - } - } else { - deleteButton.setTag(device); - deleteButton.setOnClickListener(v -> { - BraveSyncWorker.ResolvedRecordToApply deviceToDelete = (BraveSyncWorker.ResolvedRecordToApply) v.getTag(); - deleteDeviceDialog(deviceToDelete.mDeviceName, deviceToDelete.mDeviceId, deviceToDelete.mObjectId, v); - }); - } - } - - insertPoint.addView(separator, index++); - insertPoint.addView(listItemView, index++); - } - } - if (index > 0) { - dismissCancelLoadingButton(); - mBraveSyncTextDevicesTitle.setText(getResources().getString(R.string.brave_sync_devices_title)); - View separator = (View) mInflater.inflate(R.layout.menu_separator, null); - if (null != insertPoint && null != separator) { - insertPoint.addView(separator, index++); - } - } - } - }); - } - }).start(); - } - } - }); - } catch(Exception exc) { - Log.e(TAG, "onDevicesAvailable exception: " + exc); - } - } - - @Override - public void onResetSync() { - try { - if (null == getActivity()) { - return; - } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - cancelTimeoutTimer(); - setAppropriateView(); - } - }); - } catch(Exception exc) { - Log.e(TAG, "onResetSync exception: " + exc); - } - } - - @Override - public boolean shouldLoadDevices() { - if (null == getActivity() || View.VISIBLE != mScrollViewSyncDone.getVisibility()) { - // No need to load devices for other pages - return false; - } - return true; - } - }; - } - mainActivity.mBraveSyncWorker.InitJSWebView(mSyncScreensObserver); - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // Initialize mSyncServiceObserver - // if (null != mSyncService) { - // if (null == mSyncServiceObserver) { - // mSyncServiceObserver = new BraveSyncServiceObserver() { - // @Override - // public void onSyncSetupError(String message) { - // try { - // if (null == getActivity()) { - // return; - // } - // if (null != message && !message.isEmpty()) { - // if (message.equals("Credential server response 400. Signed request body of the client timestamp is required.")) { - // message = getResources().getString(R.string.brave_sync_requires_correct_time); - // } - // message = " [" + message + "]"; - // } - // final String messageFinal = (null == message) ? "" : message; - // getActivity().runOnUiThread(new Runnable() { - // @Override - // public void run() { - // cancelTimeoutTimer(); - // showEndDialog(getResources().getString(R.string.brave_sync_device_failure) + messageFinal); - // } - // }); - // } catch(Exception exc) { - // Log.e(TAG, "onSyncSetupError exception: " + exc); - // } - // } - - // @Override - // public void onSyncStateChanged() { - // } - - // @Override - // public void onHaveSyncWords(String[] syncWords) { - // try { - // if (null == getActivity()) { - // return; - // } - // getActivity().runOnUiThread(new Runnable() { - // @Override - // public void run() { - // cancelTimeoutTimer(); - // mSyncService.onSetSyncEnabled(true); - // String words = ""; - // for (int i = 0; i < syncWords.length; i++) { - // words = words + " " + syncWords[i].trim(); - // } - // mBraveSyncAddDeviceCodeWords.setText(words.trim()); - // } - // }); - // } catch(Exception exc) { - // Log.e(TAG, "onCodeWordsReceived exception: " + exc); - // } - // } - // }; - // } - // } - - mSyncSwitchBookmarks = (Switch) getView().findViewById(R.id.sync_bookmarks_switch); - if (null != mSyncSwitchBookmarks) { - mSyncSwitchBookmarks.setOnCheckedChangeListener(this); - } - - mScrollViewSyncInitial = (ScrollView) getView().findViewById(R.id.view_sync_initial); - mScrollViewSyncChainCode = (ScrollView) getView().findViewById(R.id.view_sync_chain_code); - mScrollViewSyncStartChain = (ScrollView) getView().findViewById(R.id.view_sync_start_chain); - mScrollViewAddMobileDevice = (ScrollView) getView().findViewById(R.id.view_add_mobile_device); - mScrollViewAddLaptop = (ScrollView) getView().findViewById(R.id.view_add_laptop); - mScrollViewEnterCodeWords = (ScrollView) getView().findViewById(R.id.view_enter_code_words); - mScrollViewSyncDone = (ScrollView) getView().findViewById(R.id.view_sync_done); - - if (!DeviceFormFactor.isTablet()) { - clearBackground(mScrollViewSyncInitial); - clearBackground(mScrollViewSyncChainCode); - clearBackground(mScrollViewSyncStartChain); - clearBackground(mScrollViewAddMobileDevice); - clearBackground(mScrollViewAddLaptop); - clearBackground(mScrollViewEnterCodeWords); - clearBackground(mScrollViewSyncDone); - } - - mLayoutSyncStartChain = (LinearLayout) getView().findViewById(R.id.view_sync_start_chain_layout); - - mScanChainCodeButton = (Button) getView().findViewById(R.id.brave_sync_btn_scan_chain_code); - if (mScanChainCodeButton != null) { - mScanChainCodeButton.setOnClickListener(this); - } - - mStartNewChainButton = (Button) getView().findViewById(R.id.brave_sync_btn_start_new_chain); - if (mStartNewChainButton != null) { - mStartNewChainButton.setOnClickListener(this); - } + implements View.OnClickListener, SettingsActivity.OnBackPressedListener, + BarcodeTracker.BarcodeGraphicTrackerCallback, + BraveSyncDevices.DeviceInfoChangedListener { + public static final int BIP39_WORD_COUNT = 24; + private static final String TAG = "SYNC"; + // Permission request codes need to be < 256 + private static final int RC_HANDLE_CAMERA_PERM = 2; + // Intent request code to handle updating play services if needed. + private static final int RC_HANDLE_GMS = 9001; + // For QR code generation + private static final int WHITE = 0xFFFFFFFF; + private static final int BLACK = 0xFF000000; + private static final int WIDTH = 300; + // For view sizes limit + private static final int MAX_WIDTH = 512; + private static final int MAX_HEIGHT = 1024; + + // The have a sync code button displayed in the Sync view. + private Button mScanChainCodeButton; + private Button mStartNewChainButton; + private Button mEnterCodeWordsButton; + private Button mDoneButton; + private Button mDoneLaptopButton; + private Button mUseCameraButton; + private Button mConfirmCodeWordsButton; + private ImageButton mMobileButton; + private ImageButton mLaptopButton; + private ImageButton mPasteButton; + private Button mCopyButton; + private Button mAddDeviceButton; + private Button mRemoveDeviceButton; + private Button mShowCategoriesButton; + private Button mQRCodeButton; + private Button mCodeWordsButton; + // Brave Sync message text view + private TextView mBraveSyncTextViewInitial; + private TextView mBraveSyncTextViewSyncChainCode; + private TextView mBraveSyncTextViewAddMobileDevice; + private TextView mBraveSyncTextViewAddLaptop; + private TextView mBraveSyncWarningTextViewAddMobileDevice; + private TextView mBraveSyncWarningTextViewAddLaptop; + private TextView mBraveSyncTextDevicesTitle; + private TextView mBraveSyncWordCountTitle; + private TextView mBraveSyncAddDeviceCodeWords; + private CameraSource mCameraSource; + private CameraSourcePreview mCameraSourcePreview; + private String mDeviceName = ""; + private ListView mDevicesListView; + private ArrayAdapter mDevicesAdapter; + private List mDevicesList; + private ScrollView mScrollViewSyncInitial; + private ScrollView mScrollViewSyncChainCode; + private ScrollView mScrollViewSyncStartChain; + private ScrollView mScrollViewAddMobileDevice; + private ScrollView mScrollViewAddLaptop; + private ScrollView mScrollViewEnterCodeWords; + private ScrollView mScrollViewSyncDone; + private LayoutInflater mInflater; + private ImageView mQRCodeImage; + private LinearLayout mLayoutSyncStartChain; + private EditText mCodeWords; + private FrameLayout mLayoutMobile; + private FrameLayout mLayoutLaptop; + + @Override + public void deviceInfoChanged() { + onDevicesAvailable(); + } + boolean deviceInfoObserverSet = false; + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + // Checks the orientation of the screen + if (newConfig.orientation != Configuration.ORIENTATION_UNDEFINED + && null != mCameraSourcePreview) { + mCameraSourcePreview.stop(); + try { + startCameraSource(); + } catch (SecurityException exc) { + } + } + adjustImageButtons(newConfig.orientation); + } - mEnterCodeWordsButton = (Button) getView().findViewById(R.id.brave_sync_btn_enter_code_words); - if (mEnterCodeWordsButton != null) { - mEnterCodeWordsButton.setOnClickListener(this); - } + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + InvalidateCodephrase(); - mQRCodeImage = (ImageView) getView().findViewById(R.id.brave_sync_qr_code_image); + if (ensureCameraPermission()) { + createCameraSource(true, false); + } + mInflater = inflater; + // Read which category we should be showing. + return mInflater.inflate(R.layout.brave_sync_layout, container, false); + } + + private boolean ensureCameraPermission() { + if (ActivityCompat.checkSelfPermission( + getActivity().getApplicationContext(), Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(new String[] {Manifest.permission.CAMERA}, RC_HANDLE_CAMERA_PERM); + } - mDoneButton = (Button) getView().findViewById(R.id.brave_sync_btn_done); - if (mDoneButton != null) { - mDoneButton.setOnClickListener(this); - } + return false; + } - mDoneLaptopButton = (Button) getView().findViewById(R.id.brave_sync_btn_add_laptop_done); - if (mDoneLaptopButton != null) { - mDoneLaptopButton.setOnClickListener(this); - } + @Override + public void onRequestPermissionsResult( + int requestCode, String[] permissions, int[] grantResults) { + if (requestCode != RC_HANDLE_CAMERA_PERM) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); - mUseCameraButton = (Button) getView().findViewById(R.id.brave_sync_btn_use_camera); - if (mUseCameraButton != null) { - mUseCameraButton.setOnClickListener(this); - } - - mConfirmCodeWordsButton = (Button) getView().findViewById(R.id.brave_sync_confirm_code_words); - if (mConfirmCodeWordsButton != null) { - mConfirmCodeWordsButton.setOnClickListener(this); - } + return; + } - mMobileButton = (ImageButton) getView().findViewById(R.id.brave_sync_btn_mobile); - if (mMobileButton != null) { - mMobileButton.setOnClickListener(this); - } + if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // we have permission, so create the camerasource + createCameraSource(true, false); - mLaptopButton = (ImageButton) getView().findViewById(R.id.brave_sync_btn_laptop); - if (mLaptopButton != null) { - mLaptopButton.setOnClickListener(this); - } + return; + } - mPasteButton = (ImageButton) getView().findViewById(R.id.brave_sync_paste_button); - if (mPasteButton != null) { - mPasteButton.setOnClickListener(this); - } + Log.e(TAG, + "Permission not granted: results len = " + grantResults.length + " Result code = " + + (grantResults.length > 0 ? grantResults[0] : "(empty)")); + // We still allow to enter words + // getActivity().onBackPressed(); + } + + public void onSyncError(String message) { + try { + if (null == getActivity()) { + return; + } + if (null != message && !message.isEmpty()) { + message = " [" + message + "]"; + } + final String messageFinal = (null == message) ? "" : message; + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + showEndDialog( + getResources().getString(R.string.sync_device_failure) + messageFinal); + } + }); + } catch (Exception exc) { + Log.e(TAG, "onSyncError exception: " + exc); + } + } - mCopyButton = (Button) getView().findViewById(R.id.brave_sync_copy_button); - if (mCopyButton != null) { - mCopyButton.setOnClickListener(this); - } + public void onDevicesAvailable() { + try { + if (null == getActivity()) { + return; + } + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + if (View.VISIBLE != mScrollViewSyncDone.getVisibility()) { + Log.w(TAG, "No need to load devices for other pages"); + return; + } + ArrayList deviceInfos = + BraveSyncDevices.get().GetSyncDeviceList(); + Log.v(TAG, "Got " + deviceInfos.size() + " devices"); + ViewGroup insertPoint = + (ViewGroup) getView().findViewById(R.id.brave_sync_devices); + insertPoint.removeAllViews(); + int index = 0; + for (BraveSyncDevices.SyncDeviceInfo device : deviceInfos) { + View separator = (View) mInflater.inflate(R.layout.menu_separator, null); + View listItemView = + (View) mInflater.inflate(R.layout.brave_sync_device, null); + if (null != listItemView && null != separator && null != insertPoint) { + TextView textView = (TextView) listItemView.findViewById( + R.id.brave_sync_device_text); + if (null != textView) { + textView.setText(device.mName); + } - mBraveSyncTextViewInitial = (TextView) getView().findViewById(R.id.brave_sync_text_initial); - mBraveSyncTextViewSyncChainCode = (TextView) getView().findViewById(R.id.brave_sync_text_sync_chain_code); - mBraveSyncTextViewAddMobileDevice = (TextView) getView().findViewById(R.id.brave_sync_text_add_mobile_device); - mBraveSyncTextViewAddLaptop = (TextView) getView().findViewById(R.id.brave_sync_text_add_laptop); - mBraveSyncWarningTextViewAddMobileDevice = (TextView) getView().findViewById(R.id.brave_sync_warning_text_add_mobile_device); - mBraveSyncWarningTextViewAddLaptop = (TextView) getView().findViewById(R.id.brave_sync_warning_text_add_laptop); - mBraveSyncTextDevicesTitle = (TextView) getView().findViewById(R.id.brave_sync_devices_title); - mBraveSyncWordCountTitle = (TextView) getView().findViewById(R.id.brave_sync_text_word_count); - mBraveSyncWordCountTitle.setText(getString(R.string.brave_sync_word_count_text, 0)); - mBraveSyncAddDeviceCodeWords = (TextView) getView().findViewById(R.id.brave_sync_add_device_code_words); - setMainSyncText(); - mCameraSourcePreview = (CameraSourcePreview) getView().findViewById(R.id.preview); - - mAddDeviceButton = (Button) getView().findViewById(R.id.brave_sync_btn_add_device); - if (null != mAddDeviceButton) { - mAddDeviceButton.setOnClickListener(this); - } + if (device.mIsCurrentDevice) { + mDeviceName = device.mName; + // Current device is deleted by button on the bottom + if (null != textView) { + // Highlight curret device + textView.setTextColor(ApiCompatibilityUtils.getColor( + getActivity().getResources(), + R.color.brave_theme_color)); + String currentDevice = device.mName + " " + + getResources().getString( + R.string.brave_sync_this_device_text); + textView.setText(currentDevice); + } + // mRemoveDeviceButton is always visible, we can leave the chain + // in any time with sync v2 + if (null != mRemoveDeviceButton) { + mRemoveDeviceButton.setTag(device); + } + } + insertPoint.addView(separator, index++); + insertPoint.addView(listItemView, index++); + } + } - mCancelLoadingButton = (Button) getView().findViewById(R.id.brave_sync_btn_cancel_loading); - if (null != mCancelLoadingButton) { - mCancelLoadingButton.setOnClickListener(this); - } + if (index > 0) { + mBraveSyncTextDevicesTitle.setText( + getResources().getString(R.string.brave_sync_devices_title)); + View separator = (View) mInflater.inflate(R.layout.menu_separator, null); + if (null != insertPoint && null != separator) { + insertPoint.addView(separator, index++); + } + } + } + }); + } catch (Exception exc) { + Log.e(TAG, "onDevicesAvailable exception: " + exc); + } + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getActivity().setTitle(R.string.sign_in_sync); + + mScrollViewSyncInitial = (ScrollView) getView().findViewById(R.id.view_sync_initial); + mScrollViewSyncChainCode = (ScrollView) getView().findViewById(R.id.view_sync_chain_code); + mScrollViewSyncStartChain = (ScrollView) getView().findViewById(R.id.view_sync_start_chain); + mScrollViewAddMobileDevice = + (ScrollView) getView().findViewById(R.id.view_add_mobile_device); + mScrollViewAddLaptop = (ScrollView) getView().findViewById(R.id.view_add_laptop); + mScrollViewEnterCodeWords = (ScrollView) getView().findViewById(R.id.view_enter_code_words); + mScrollViewSyncDone = (ScrollView) getView().findViewById(R.id.view_sync_done); + + if (!DeviceFormFactor.isTablet()) { + clearBackground(mScrollViewSyncInitial); + clearBackground(mScrollViewSyncChainCode); + clearBackground(mScrollViewSyncStartChain); + clearBackground(mScrollViewAddMobileDevice); + clearBackground(mScrollViewAddLaptop); + clearBackground(mScrollViewEnterCodeWords); + clearBackground(mScrollViewSyncDone); + } - mRemoveDeviceButton = (Button) getView().findViewById(R.id.brave_sync_btn_remove_device); - if (null != mRemoveDeviceButton) { - mRemoveDeviceButton.setOnClickListener(this); - } + mLayoutSyncStartChain = + (LinearLayout) getView().findViewById(R.id.view_sync_start_chain_layout); - mQRCodeButton = (Button) getView().findViewById(R.id.brave_sync_qr_code_off_btn); - if (null != mQRCodeButton) { - mQRCodeButton.setOnClickListener(this); - } + mScanChainCodeButton = (Button) getView().findViewById(R.id.brave_sync_btn_scan_chain_code); + if (mScanChainCodeButton != null) { + mScanChainCodeButton.setOnClickListener(this); + } - mCodeWordsButton = (Button) getView().findViewById(R.id.brave_sync_code_words_off_btn); - if (null != mCodeWordsButton) { - mCodeWordsButton.setOnClickListener(this); - } + mStartNewChainButton = (Button) getView().findViewById(R.id.brave_sync_btn_start_new_chain); + if (mStartNewChainButton != null) { + mStartNewChainButton.setOnClickListener(this); + } - mCodeWords = (EditText) getView().findViewById(R.id.code_words); + mEnterCodeWordsButton = + (Button) getView().findViewById(R.id.brave_sync_btn_enter_code_words); + if (mEnterCodeWordsButton != null) { + mEnterCodeWordsButton.setOnClickListener(this); + } - mLayoutMobile = (FrameLayout) getView().findViewById(R.id.brave_sync_frame_mobile); - mLayoutLaptop = (FrameLayout) getView().findViewById(R.id.brave_sync_frame_laptop); + mQRCodeImage = (ImageView) getView().findViewById(R.id.brave_sync_qr_code_image); - mTimeoutTimer = new CountDownTimer(WAIT_TIMEOUT, WAIT_TIMEOUT) { - @Override - public void onTick(long millisUntilFinished) { - // No action is required here - } - @Override - public void onFinish() { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onDevicesAvailable(); - } - showEndDialog(getResources().getString(R.string.brave_sync_time_out_message)); - } - }; + mDoneButton = (Button) getView().findViewById(R.id.brave_sync_btn_done); + if (mDoneButton != null) { + mDoneButton.setOnClickListener(this); + } - setAppropriateView(); + mDoneLaptopButton = (Button) getView().findViewById(R.id.brave_sync_btn_add_laptop_done); + if (mDoneLaptopButton != null) { + mDoneLaptopButton.setOnClickListener(this); + } - super.onActivityCreated(savedInstanceState); - } + mUseCameraButton = (Button) getView().findViewById(R.id.brave_sync_btn_use_camera); + if (mUseCameraButton != null) { + mUseCameraButton.setOnClickListener(this); + } - private void setAppropriateView() { - getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); - getActivity().setTitle(R.string.sync_category_title); - // String seed = BravePrefServiceBridge.getInstance().getSyncSeed(); - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - String seed = sharedPref.getString(BraveSyncWorker.PREF_SEED, null); - //Log.i(TAG, "setAppropriateView: seed == " + seed); - if (null == seed || seed.isEmpty()) { - if (null != mCameraSourcePreview) { - mCameraSourcePreview.stop(); - } - if (null != mScrollViewSyncInitial) { - adjustWidth(mScrollViewSyncInitial, false); - mScrollViewSyncInitial.setVisibility(View.VISIBLE); - } - if (null != mScrollViewSyncChainCode) { - mScrollViewSyncChainCode.setVisibility(View.GONE); - } - if (null != mScrollViewEnterCodeWords) { - mScrollViewEnterCodeWords.setVisibility(View.GONE); - } - if (null != mScrollViewAddMobileDevice) { - mScrollViewAddMobileDevice.setVisibility(View.GONE); - } - if (null != mScrollViewAddLaptop) { - mScrollViewAddLaptop.setVisibility(View.GONE); - } - if (null != mScrollViewSyncStartChain) { - mScrollViewSyncStartChain.setVisibility(View.GONE); - } - if (null != mScrollViewSyncDone) { - mScrollViewSyncDone.setVisibility(View.GONE); - } - if (null != mCodeWords) { - mCodeWords.setText(""); - } - return; - } - setSyncDoneLayout(); - } + mConfirmCodeWordsButton = + (Button) getView().findViewById(R.id.brave_sync_confirm_code_words); + if (mConfirmCodeWordsButton != null) { + mConfirmCodeWordsButton.setOnClickListener(this); + } - private void setMainSyncText() { - setSyncText(getResources().getString(R.string.brave_sync_official), getResources().getString(R.string.brave_sync_description_page_1_part_1) + "\n\n" + - getResources().getString(R.string.brave_sync_description_page_1_part_2), mBraveSyncTextViewInitial); - } + mMobileButton = (ImageButton) getView().findViewById(R.id.brave_sync_btn_mobile); + if (mMobileButton != null) { + mMobileButton.setOnClickListener(this); + } - private void setQRCodeText() { - setSyncText("", getResources().getString(R.string.brave_sync_qrcode_message_v2), mBraveSyncTextViewSyncChainCode); - } + mLaptopButton = (ImageButton) getView().findViewById(R.id.brave_sync_btn_laptop); + if (mLaptopButton != null) { + mLaptopButton.setOnClickListener(this); + } - private void setSyncText(String title, String message, TextView textView) { - String text = ""; - if (title.length() > 0) { - text = title + "\n\n"; - } - text += message; - SpannableString formatedText = new SpannableString(text); - formatedText.setSpan(new RelativeSizeSpan(1.25f), 0, title.length(), 0); - textView.setText(formatedText); - } + mPasteButton = (ImageButton) getView().findViewById(R.id.brave_sync_paste_button); + if (mPasteButton != null) { + mPasteButton.setOnClickListener(this); + } - /** OnClickListener for the clear button. We show an alert dialog to confirm the action */ - @Override - public void onClick(View v) { - if ((getActivity() == null) || (v != mScanChainCodeButton && v != mStartNewChainButton - && v != mEnterCodeWordsButton && v != mDoneButton && v != mDoneLaptopButton - && v != mUseCameraButton && v != mConfirmCodeWordsButton && v != mMobileButton && v != mLaptopButton - && v != mPasteButton && v != mCopyButton && v != mRemoveDeviceButton && v != mAddDeviceButton - && v != mCancelLoadingButton && v != mQRCodeButton && v != mCodeWordsButton)) return; - - if (mScanChainCodeButton == v) { - showAddDeviceNameDialog(false); - } else if (mStartNewChainButton == v) { - showAddDeviceNameDialog(true); - } else if (mMobileButton == v) { - setAddMobileDeviceLayout(); - } else if (mLaptopButton == v) { - setAddLaptopLayout(); - } else if (mDoneButton == v) { - setSyncDoneLayout(); - } else if (mDoneLaptopButton == v) { - setSyncDoneLayout(); - } else if (mUseCameraButton == v) { - setJoinExistingChainLayout(); - } else if (mQRCodeButton == v) { - setAddMobileDeviceLayout(); - } else if (mCodeWordsButton == v) { - setAddLaptopLayout(); - } else if (mPasteButton == v) { - if (null != mCodeWords) { - ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clipData = clipboard.getPrimaryClip(); - if (null != clipData && clipData.getItemCount() > 0) { - mCodeWords.setText(clipData.getItemAt(0).coerceToText(getActivity().getApplicationContext())); - } - } - } else if (mCopyButton == v) { - if (null != mBraveSyncAddDeviceCodeWords) { - ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("", mBraveSyncAddDeviceCodeWords.getText()); - clipboard.setPrimaryClip(clip); - Toast.makeText(getActivity().getApplicationContext(), getResources().getString(R.string.brave_sync_copied_text), Toast.LENGTH_LONG).show(); - } - } else if (mConfirmCodeWordsButton == v) { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - String[] words = mCodeWords.getText().toString().trim().replace(" ", " ").replace("\n", " ").split(" "); - if (BraveSyncWorker.NICEWARE_WORD_COUNT != words.length && BraveSyncWorker.BIP39_WORD_COUNT != words.length) { - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onSyncError(getResources().getString(R.string.brave_sync_word_count_error)); - } - return; - } - if (null != mainActivity && null != mainActivity.mBraveSyncWorker && null != words) { - for (int i = 0; i < words.length; i++) { - words[i] = words[i].trim(); - } - mainActivity.mBraveSyncWorker.GetNumber(words); - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // String[] words = mCodeWords.getText().toString().trim().replace(" ", " ").replace("\n", " ").split(" "); - // if (BraveSyncService.NICEWARE_WORD_COUNT != words.length && BraveSyncService.BIP39_WORD_COUNT != words.length) { - // if (null != mSyncServiceObserver) { - // mSyncServiceObserver.onSyncSetupError(getResources().getString(R.string.brave_sync_word_count_error)); - // } - // return; - // } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService && null != words) { - // for (int i = 0; i < words.length; i++) { - // words[i] = words[i].trim(); - // } - // mSyncServiceObserver.onHaveSyncWords(words); - // } - } else if (mEnterCodeWordsButton == v) { - getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - if (null != mScrollViewSyncInitial) { - mScrollViewSyncInitial.setVisibility(View.GONE); - } - if (null != mScrollViewAddMobileDevice) { - mScrollViewAddMobileDevice.setVisibility(View.GONE); - } - if (null != mScrollViewAddLaptop) { - mScrollViewAddLaptop.setVisibility(View.GONE); - } - if (null != mScrollViewSyncStartChain) { - mScrollViewSyncStartChain.setVisibility(View.GONE); - } - if (null != mCameraSourcePreview) { - mCameraSourcePreview.stop(); - } - if (null != mScrollViewSyncChainCode) { - mScrollViewSyncChainCode.setVisibility(View.GONE); - } - if (null != mScrollViewEnterCodeWords) { - adjustWidth(mScrollViewEnterCodeWords, false); - mScrollViewEnterCodeWords.setVisibility(View.VISIBLE); - } - getActivity().setTitle(R.string.brave_sync_code_words_title); - if (null != mCodeWords && null != mBraveSyncWordCountTitle) { - mCodeWords.addTextChangedListener(new TextWatcher() { - @Override - public void afterTextChanged(Editable s) {} - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - int wordCount = mCodeWords.getText().toString().length(); - if (0 != wordCount) { - String[] words = mCodeWords.getText().toString().trim().replace(" ", " ").replace("\n", " ").split(" "); - wordCount = words.length; - } - mBraveSyncWordCountTitle.setText(getString(R.string.brave_sync_word_count_text, wordCount)); - mBraveSyncWordCountTitle.invalidate(); - } - }); - } - } else if (mRemoveDeviceButton == v) { - } else if (mAddDeviceButton == v) { - setNewChainLayout(); - } else if (mCancelLoadingButton == v) { - cancelLoadingResetAndBack(); - } - } + mCopyButton = (Button) getView().findViewById(R.id.brave_sync_copy_button); + if (mCopyButton != null) { + mCopyButton.setOnClickListener(this); + } - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if ((getActivity() == null) || (buttonView != mSyncSwitchBookmarks)) { - Log.w(TAG, "Unknown button"); - return; - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // if (buttonView == mSyncSwitchBookmarks) { - // mSyncService.onSetSyncBookmarks(isChecked); - // } - // } - } + mBraveSyncTextViewInitial = (TextView) getView().findViewById(R.id.brave_sync_text_initial); + mBraveSyncTextViewSyncChainCode = + (TextView) getView().findViewById(R.id.brave_sync_text_sync_chain_code); + mBraveSyncTextViewAddMobileDevice = + (TextView) getView().findViewById(R.id.brave_sync_text_add_mobile_device); + mBraveSyncTextViewAddLaptop = + (TextView) getView().findViewById(R.id.brave_sync_text_add_laptop); + mBraveSyncWarningTextViewAddMobileDevice = + (TextView) getView().findViewById(R.id.brave_sync_warning_text_add_mobile_device); + mBraveSyncWarningTextViewAddLaptop = + (TextView) getView().findViewById(R.id.brave_sync_warning_text_add_laptop); + mBraveSyncTextDevicesTitle = + (TextView) getView().findViewById(R.id.brave_sync_devices_title); + mBraveSyncWordCountTitle = + (TextView) getView().findViewById(R.id.brave_sync_text_word_count); + mBraveSyncWordCountTitle.setText(getString(R.string.brave_sync_word_count_text, 0)); + mBraveSyncAddDeviceCodeWords = + (TextView) getView().findViewById(R.id.brave_sync_add_device_code_words); + setMainSyncText(); + mCameraSourcePreview = (CameraSourcePreview) getView().findViewById(R.id.preview); + + mAddDeviceButton = (Button) getView().findViewById(R.id.brave_sync_btn_add_device); + if (null != mAddDeviceButton) { + mAddDeviceButton.setOnClickListener(this); + } - private void showMainSyncScrypt() { - if (null != mScrollViewSyncInitial) { - adjustWidth(mScrollViewSyncInitial, false); - mScrollViewSyncInitial.setVisibility(View.VISIBLE); - } - if (null != mScrollViewAddMobileDevice) { - mScrollViewAddMobileDevice.setVisibility(View.GONE); - } - if (null != mScrollViewAddLaptop) { - mScrollViewAddLaptop.setVisibility(View.GONE); - } - if (null != mScrollViewSyncStartChain) { - mScrollViewSyncStartChain.setVisibility(View.GONE); - } - if (null != mScrollViewSyncChainCode) { - mScrollViewSyncChainCode.setVisibility(View.GONE); - } - if (null != mScrollViewEnterCodeWords) { - mScrollViewEnterCodeWords.setVisibility(View.GONE); - } - setMainSyncText(); - } + mRemoveDeviceButton = (Button) getView().findViewById(R.id.brave_sync_btn_remove_device); + if (null != mRemoveDeviceButton) { + mRemoveDeviceButton.setOnClickListener(this); + } - // Handles the requesting of the camera permission. - private void requestCameraPermission() { - Log.w(TAG, "Camera permission is not granted. Requesting permission"); + mShowCategoriesButton = + (Button) getView().findViewById(R.id.brave_sync_btn_show_categories); + if (null != mShowCategoriesButton) { + mShowCategoriesButton.setOnClickListener(this); + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - final String[] permissions = new String[]{Manifest.permission.CAMERA}; + mQRCodeButton = (Button) getView().findViewById(R.id.brave_sync_qr_code_off_btn); + if (null != mQRCodeButton) { + mQRCodeButton.setOnClickListener(this); + } - requestPermissions(permissions, RC_HANDLE_CAMERA_PERM); - } - } + mCodeWordsButton = (Button) getView().findViewById(R.id.brave_sync_code_words_off_btn); + if (null != mCodeWordsButton) { + mCodeWordsButton.setOnClickListener(this); + } - @SuppressLint("InlinedApi") - private void createCameraSource(boolean autoFocus, boolean useFlash) { - Context context = getActivity().getApplicationContext(); - - // A barcode detector is created to track barcodes. An associated multi-processor instance - // is set to receive the barcode detection results, track the barcodes, and maintain - // graphics for each barcode on screen. The factory is used by the multi-processor to - // create a separate tracker instance for each barcode. - BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context) - .setBarcodeFormats(Barcode.ALL_FORMATS) - .build(); - BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(this); - barcodeDetector.setProcessor(new MultiProcessor.Builder<>(barcodeFactory).build()); - - if (!barcodeDetector.isOperational()) { - // Note: The first time that an app using the barcode or face API is installed on a - // device, GMS will download a native libraries to the device in order to do detection. - // Usually this completes before the app is run for the first time. But if that - // download has not yet completed, then the above call will not detect any barcodes. - // - // isOperational() can be used to check if the required native libraries are currently - // available. The detectors will automatically become operational once the library - // downloads complete on device. - Log.w(TAG, "Detector dependencies are not yet available."); - } + mCodeWords = (EditText) getView().findViewById(R.id.code_words); - // Creates and starts the camera. Note that this uses a higher resolution in comparison - // to other detection examples to enable the barcode detector to detect small barcodes - // at long distances. - DisplayMetrics metrics = new DisplayMetrics(); - getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); + mLayoutMobile = (FrameLayout) getView().findViewById(R.id.brave_sync_frame_mobile); + mLayoutLaptop = (FrameLayout) getView().findViewById(R.id.brave_sync_frame_laptop); - CameraSource.Builder builder = new CameraSource.Builder(getActivity().getApplicationContext(), barcodeDetector) - .setFacing(CameraSource.CAMERA_FACING_BACK) - .setRequestedPreviewSize(metrics.widthPixels, metrics.heightPixels) - .setRequestedFps(24.0f); + setAppropriateView(); - // make sure that auto focus is an available option - builder = builder.setFocusMode( - autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE : null); + super.onActivityCreated(savedInstanceState); + } - mCameraSource = builder - .setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null) - .build(); - } + private void setAppropriateView() { + getActivity().getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + getActivity().setTitle(R.string.sync_category_title); + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + assert (mainActivity != null); + boolean firstSetupComplete = mainActivity.mBraveSyncWorker.IsFirstSetupComplete(); + Log.v(TAG, "setAppropriateView first setup complete " + firstSetupComplete); + if (!firstSetupComplete) { + if (null != mCameraSourcePreview) { + mCameraSourcePreview.stop(); + } + if (null != mScrollViewSyncInitial) { + adjustWidth(mScrollViewSyncInitial, false); + mScrollViewSyncInitial.setVisibility(View.VISIBLE); + } + if (null != mScrollViewSyncChainCode) { + mScrollViewSyncChainCode.setVisibility(View.GONE); + } + if (null != mScrollViewEnterCodeWords) { + mScrollViewEnterCodeWords.setVisibility(View.GONE); + } + if (null != mScrollViewAddMobileDevice) { + mScrollViewAddMobileDevice.setVisibility(View.GONE); + } + if (null != mScrollViewAddLaptop) { + mScrollViewAddLaptop.setVisibility(View.GONE); + } + if (null != mScrollViewSyncStartChain) { + mScrollViewSyncStartChain.setVisibility(View.GONE); + } + if (null != mScrollViewSyncDone) { + mScrollViewSyncDone.setVisibility(View.GONE); + } + if (null != mCodeWords) { + mCodeWords.setText(""); + } + return; + } + setSyncDoneLayout(); + } + + private void setMainSyncText() { + setSyncText(getResources().getString(R.string.brave_sync_official), + getResources().getString(R.string.brave_sync_description_page_1_part_1) + "\n\n" + + getResources().getString(R.string.brave_sync_description_page_1_part_2), + mBraveSyncTextViewInitial); + } + + private void setQRCodeText() { + setSyncText("", getResources().getString(R.string.brave_sync_qrcode_message_v2), + mBraveSyncTextViewSyncChainCode); + } + + private void setSyncText(String title, String message, TextView textView) { + String text = ""; + if (title.length() > 0) { + text = title + "\n\n"; + } + text += message; + SpannableString formatedText = new SpannableString(text); + formatedText.setSpan(new RelativeSizeSpan(1.25f), 0, title.length(), 0); + textView.setText(formatedText); + } + + /** OnClickListener for the clear button. We show an alert dialog to confirm the action */ + @Override + public void onClick(View v) { + if ((getActivity() == null) + || (v != mScanChainCodeButton && v != mStartNewChainButton + && v != mEnterCodeWordsButton && v != mDoneButton && v != mDoneLaptopButton + && v != mUseCameraButton && v != mConfirmCodeWordsButton + && v != mMobileButton && v != mLaptopButton && v != mPasteButton + && v != mCopyButton && v != mRemoveDeviceButton + && v != mShowCategoriesButton && v != mAddDeviceButton && v != mQRCodeButton + && v != mCodeWordsButton)) + return; - private void startCameraSource() throws SecurityException { - if (mCameraSource != null && mCameraSourcePreview.mCameraExist) { - // check that the device has play services available. - try { - int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable( - getActivity().getApplicationContext()); - if (code != ConnectionResult.SUCCESS) { - Dialog dlg = - GoogleApiAvailability.getInstance().getErrorDialog(getActivity(), code, RC_HANDLE_GMS); - if (null != dlg) { - dlg.show(); - } - } - } catch (ActivityNotFoundException e) { - Log.e(TAG, "Unable to start camera source.", e); - mCameraSource.release(); - mCameraSource = null; + if (mScanChainCodeButton == v) { + setJoinExistingChainLayout(); + } else if (mStartNewChainButton == v) { + // Creating a new chain + GetCodephrase(); + setNewChainLayout(); + seedWordsReceived(mCodephrase); + } else if (mMobileButton == v) { + setAddMobileDeviceLayout(); + } else if (mLaptopButton == v) { + setAddLaptopLayout(); + } else if (mDoneButton == v) { + setSyncDoneLayout(); + } else if (mDoneLaptopButton == v) { + setSyncDoneLayout(); + } else if (mUseCameraButton == v) { + setJoinExistingChainLayout(); + } else if (mQRCodeButton == v) { + setAddMobileDeviceLayout(); + } else if (mCodeWordsButton == v) { + setAddLaptopLayout(); + } else if (mPasteButton == v) { + if (null != mCodeWords) { + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService( + Context.CLIPBOARD_SERVICE); + ClipData clipData = clipboard.getPrimaryClip(); + if (null != clipData && clipData.getItemCount() > 0) { + mCodeWords.setText(clipData.getItemAt(0).coerceToText( + getActivity().getApplicationContext())); + } + } + } else if (mCopyButton == v) { + if (null != mBraveSyncAddDeviceCodeWords) { + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService( + Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("", mBraveSyncAddDeviceCodeWords.getText()); + clipboard.setPrimaryClip(clip); + Toast.makeText(getActivity().getApplicationContext(), + getResources().getString(R.string.brave_sync_copied_text), + Toast.LENGTH_LONG) + .show(); + } + } else if (mConfirmCodeWordsButton == v) { + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + String[] words = mCodeWords.getText() + .toString() + .trim() + .replace(" ", " ") + .replace("\n", " ") + .split(" "); + if (BIP39_WORD_COUNT != words.length) { + Log.e(TAG, "Confirm code words - wrong words count " + words.length); + onSyncError(getResources().getString(R.string.brave_sync_word_count_error)); + return; + } - return; - } - try { - mCameraSourcePreview.start(mCameraSource); - } catch (IOException e) { - Log.e(TAG, "Unable to start camera source.", e); - mCameraSource.release(); - mCameraSource = null; - } - } - } + if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { + String hexString = mainActivity.mBraveSyncWorker.GetSeedHexFromWords( + TextUtils.join(" ", words)); + if (hexString == null || hexString.isEmpty()) { + Log.e(TAG, "Confirm code words - wrong codephrase"); + onSyncError(getResources().getString(R.string.brave_sync_wrong_code_error)); + return; + } + } - @Override - public void onResume() { - super.onResume(); - try { - if (null != mCameraSourcePreview && View.GONE != mScrollViewSyncChainCode.getVisibility()) { - startCameraSource(); - } - } catch (SecurityException se) { - Log.e(TAG,"Do not have permission to start the camera", se); - } catch (RuntimeException e) { - Log.e(TAG, "Could not start camera source.", e); - } - } + String codephraseCandidate = TextUtils.join(" ", words); + // Validate the code words with GetSeedHexFromWords + String seedHex = mainActivity.mBraveSyncWorker.GetSeedHexFromWords(codephraseCandidate); + if (null == seedHex || seedHex.isEmpty()) { + onSyncError(getResources().getString(R.string.brave_sync_wrong_code_error)); + return; + } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.close_menu_id) { - cancelTimeoutTimer(); - } + // Code phrase looks valid, we can pass it down to sync system + mCodephrase = codephraseCandidate; + seedWordsReceived(mCodephrase); + setAppropriateView(); + } else if (mEnterCodeWordsButton == v) { + getActivity().getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + if (null != mScrollViewSyncInitial) { + mScrollViewSyncInitial.setVisibility(View.GONE); + } + if (null != mScrollViewAddMobileDevice) { + mScrollViewAddMobileDevice.setVisibility(View.GONE); + } + if (null != mScrollViewAddLaptop) { + mScrollViewAddLaptop.setVisibility(View.GONE); + } + if (null != mScrollViewSyncStartChain) { + mScrollViewSyncStartChain.setVisibility(View.GONE); + } + if (null != mCameraSourcePreview) { + mCameraSourcePreview.stop(); + } + if (null != mScrollViewSyncChainCode) { + mScrollViewSyncChainCode.setVisibility(View.GONE); + } + if (null != mScrollViewEnterCodeWords) { + adjustWidth(mScrollViewEnterCodeWords, false); + mScrollViewEnterCodeWords.setVisibility(View.VISIBLE); + } + getActivity().setTitle(R.string.brave_sync_code_words_title); + if (null != mCodeWords && null != mBraveSyncWordCountTitle) { + mCodeWords.addTextChangedListener(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) {} + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } - return super.onOptionsItemSelected(item); - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + int wordCount = mCodeWords.getText().toString().length(); + if (0 != wordCount) { + String[] words = mCodeWords.getText() + .toString() + .trim() + .replace(" ", " ") + .replace("\n", " ") + .split(" "); + wordCount = words.length; + } + mBraveSyncWordCountTitle.setText( + getString(R.string.brave_sync_word_count_text, wordCount)); + mBraveSyncWordCountTitle.invalidate(); + } + }); + } + } else if (mRemoveDeviceButton == v) { + BraveSyncDevices.SyncDeviceInfo deviceToDelete = + (BraveSyncDevices.SyncDeviceInfo) v.getTag(); + assert deviceToDelete.mIsCurrentDevice; + assert mDeviceName.equals(deviceToDelete.mName); + deleteDeviceDialog(deviceToDelete, v); + } else if (mShowCategoriesButton == v) { + SettingsLauncher.getInstance().launchSettingsPage( + getContext(), BraveManageSyncSettings.class); + } else if (mAddDeviceButton == v) { + setNewChainLayout(); + } + } - @Override - public void onPause() { - super.onPause(); - if (mCameraSourcePreview != null) { - mCameraSourcePreview.stop(); - } - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); - } + // This function used when we have scanned the QR code to connect to the chain + private void seedHexReceived(String seedHex) { + assert seedHex != null && !seedHex.isEmpty(); + assert isBarCodeValid(seedHex); - @Override - public void onDestroy() { - super.onDestroy(); - if (mCameraSourcePreview != null) { - mCameraSourcePreview.release(); - } - } + if (null == getActivity()) { + return; + } + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { + String seedWords = mainActivity.mBraveSyncWorker.GetWordsFromSeedHex(seedHex); + seedWordsReceivedImpl(seedWords); + } + setAppropriateView(); + } + }); + } + + // This function used in two cases: + // 1) when we have entered the code words to connect to the chain + // 2) when we have created a new chain + private void seedWordsReceived(String seedWords) { + if (null == getActivity()) { + return; + } + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + seedWordsReceivedImpl(seedWords); + } + }); + } + + private void seedWordsReceivedImpl(String seedWords) { + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { + mainActivity.mBraveSyncWorker.RequestSync(); + mainActivity.mBraveSyncWorker.SaveCodephrase(seedWords); + mainActivity.mBraveSyncWorker.FinalizeSyncSetup(); + } + } - private boolean isBarCodeValid(String barcode, boolean hexValue) { - if (hexValue && barcode.length() != 64) { - return false; - } else if (!hexValue) { - String[] split = barcode.split(","); - if (split.length != 32) { - return false; - } - } + private void showMainSyncScrypt() { + if (null != mScrollViewSyncInitial) { + adjustWidth(mScrollViewSyncInitial, false); + mScrollViewSyncInitial.setVisibility(View.VISIBLE); + } + if (null != mScrollViewAddMobileDevice) { + mScrollViewAddMobileDevice.setVisibility(View.GONE); + } + if (null != mScrollViewAddLaptop) { + mScrollViewAddLaptop.setVisibility(View.GONE); + } + if (null != mScrollViewSyncStartChain) { + mScrollViewSyncStartChain.setVisibility(View.GONE); + } + if (null != mScrollViewSyncChainCode) { + mScrollViewSyncChainCode.setVisibility(View.GONE); + } + if (null != mScrollViewEnterCodeWords) { + mScrollViewEnterCodeWords.setVisibility(View.GONE); + } + setMainSyncText(); + } - return true; - } + // Handles the requesting of the camera permission. + private void requestCameraPermission() { + Log.w(TAG, "Camera permission is not granted. Requesting permission"); - @Override - public void onDetectedQrCode(Barcode barcode) { - if (barcode != null) { - //Log.i(TAG, "!!!code == " + barcode.displayValue); - final String barcodeValue = barcode.displayValue; - if (!isBarCodeValid(barcodeValue, true)) { - showEndDialog(getResources().getString(R.string.brave_sync_device_failure)); - showMainSyncScrypt(); - - return; - } - String[] barcodeString = barcodeValue.replaceAll("..(?!$)", "$0 ").split(" "); - String seed = ""; - for (int i = 0; i < barcodeString.length; i++) { - if (0 != seed.length()) { - seed += ","; - } - seed += String.valueOf(Integer.parseInt(barcodeString[i], 16)); - } - //Log.i(TAG, "!!!seed == " + seed); - // Save seed and deviceId in preferences - // BravePrefServiceBridge.getInstance().setSyncSeed(seed); - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(BraveSyncWorker.PREF_SEED, seed); - editor.apply(); - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.SetSyncEnabled(true); - mainActivity.mBraveSyncWorker.InitSync(true, false); - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // mSyncService.onSetSyncEnabled(true); - // mSyncService.onSetupSyncNewToSync(mDeviceName); - // } - setAppropriateView(); - } - }); - } - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final String[] permissions = new String[] {Manifest.permission.CAMERA}; - private void showEndDialog(String message) { - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog); - if (null == alert) { - return; - } - DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int button) { - } - }; - AlertDialog alertDialog = alert - .setTitle(getResources().getString(R.string.brave_sync_device)) - .setMessage(message) - .setPositiveButton(R.string.ok, onClickListener) - .create(); - alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); - alertDialog.show(); - } + requestPermissions(permissions, RC_HANDLE_CAMERA_PERM); + } + } + + @SuppressLint("InlinedApi") + private void createCameraSource(boolean autoFocus, boolean useFlash) { + Context context = getActivity().getApplicationContext(); + + // A barcode detector is created to track barcodes. An associated multi-processor instance + // is set to receive the barcode detection results, track the barcodes, and maintain + // graphics for each barcode on screen. The factory is used by the multi-processor to + // create a separate tracker instance for each barcode. + BarcodeDetector barcodeDetector = + new BarcodeDetector.Builder(context).setBarcodeFormats(Barcode.ALL_FORMATS).build(); + BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(this); + barcodeDetector.setProcessor(new MultiProcessor.Builder<>(barcodeFactory).build()); + + if (!barcodeDetector.isOperational()) { + // Note: The first time that an app using the barcode or face API is installed on a + // device, GMS will download a native libraries to the device in order to do detection. + // Usually this completes before the app is run for the first time. But if that + // download has not yet completed, then the above call will not detect any barcodes. + // + // isOperational() can be used to check if the required native libraries are currently + // available. The detectors will automatically become operational once the library + // downloads complete on device. + Log.w(TAG, "Detector dependencies are not yet available."); + } - private void startTimeoutTimerWithPopup(String message) { - Toast.makeText(getActivity().getApplicationContext(), message, Toast.LENGTH_LONG).show(); - mTimeoutTimer.start(); - } + // Creates and starts the camera. Note that this uses a higher resolution in comparison + // to other detection examples to enable the barcode detector to detect small barcodes + // at long distances. + DisplayMetrics metrics = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); + + CameraSource.Builder builder = + new CameraSource.Builder(getActivity().getApplicationContext(), barcodeDetector) + .setFacing(CameraSource.CAMERA_FACING_BACK) + .setRequestedPreviewSize(metrics.widthPixels, metrics.heightPixels) + .setRequestedFps(24.0f); + + // make sure that auto focus is an available option + builder = builder.setFocusMode( + autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE : null); + + mCameraSource = + builder.setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null).build(); + } + + private void startCameraSource() throws SecurityException { + if (mCameraSource != null && mCameraSourcePreview.mCameraExist) { + // check that the device has play services available. + try { + int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable( + getActivity().getApplicationContext()); + if (code != ConnectionResult.SUCCESS) { + Dialog dlg = GoogleApiAvailability.getInstance().getErrorDialog( + getActivity(), code, RC_HANDLE_GMS); + if (null != dlg) { + dlg.show(); + } + } + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Unable to start camera source.", e); + mCameraSource.release(); + mCameraSource = null; - private void cancelTimeoutTimer() { - mTimeoutTimer.cancel(); - } + return; + } + try { + mCameraSourcePreview.start(mCameraSource); + } catch (IOException e) { + Log.e(TAG, "Unable to start camera source.", e); + mCameraSource.release(); + mCameraSource = null; + } + } + } + + @Override + public void onResume() { + super.onResume(); + try { + if (null != mCameraSourcePreview + && View.GONE != mScrollViewSyncChainCode.getVisibility()) { + startCameraSource(); + } + } catch (SecurityException se) { + Log.e(TAG, "Do not have permission to start the camera", se); + } catch (RuntimeException e) { + Log.e(TAG, "Could not start camera source.", e); + } + } - private void showAddDeviceNameDialog(boolean createNewChain) { - LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.add_sync_device_name_dialog, null); - final EditText input = (EditText) view.findViewById(R.id.device_name); + @Override + public void onPause() { + super.onPause(); + if (mCameraSourcePreview != null) { + mCameraSourcePreview.stop(); + } + InputMethodManager imm = + (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mCameraSourcePreview != null) { + mCameraSourcePreview.release(); + } + if (deviceInfoObserverSet) { + BraveSyncDevices.get().removeDeviceInfoChangedListener(this); + deviceInfoObserverSet = false; + } + } + + // Barcode is valid when its raw representation has length of 64 + // and when it's possible to convert the barcode to bip39 code words + private boolean isBarCodeValid(String barcode) { + Log.v(TAG, "isBarCodeValid barcode length=" + barcode.length()); + if (barcode == null) { + Log.e(TAG, "Barcode is empty"); + return false; + } + if (barcode.length() != 64) { + Log.e(TAG, "Wrong barcode data length " + barcode.length() + " instead of 64"); + return false; + } + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + if (null == mainActivity || null == mainActivity.mBraveSyncWorker) { + Log.e(TAG, "Could not find Brave activity or sync worker"); + return false; + } + String seedWords = mainActivity.mBraveSyncWorker.GetWordsFromSeedHex(barcode); + if (seedWords == null || seedWords.isEmpty()) { + Log.e(TAG, "Wrong sync words converted from barcode"); + return false; + } + return true; + } + + @Override + public void onDetectedQrCode(Barcode barcode) { + if (barcode != null) { + final String barcodeValue = barcode.displayValue; + Log.e(TAG, "onDetectedQrCode barcodeValue=" + barcodeValue); + if (!isBarCodeValid(barcodeValue)) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + showEndDialog( + getResources().getString(R.string.brave_sync_wrong_qrcode_error)); + showMainSyncScrypt(); + } + }); + return; + } - DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int button) { - if (button == AlertDialog.BUTTON_POSITIVE) { - mDeviceName = input.getText().toString(); - if (mDeviceName.isEmpty()) { - mDeviceName = input.getHint().toString(); - } - // Log.i(TAG, "mDeviceName just set: " + mDeviceName); - // BravePrefServiceBridge.getInstance().setSyncDeviceName(mDeviceName); - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(BraveSyncWorker.PREF_SYNC_DEVICE_NAME, mDeviceName); - editor.apply(); - if (!createNewChain) { - setJoinExistingChainLayout(); - } else { - setNewChainLayout(); - } - } - } - }; + String seedHex = barcodeValue; + // seedHexReceived will call setAppropriateView + seedHexReceived(seedHex); + } + } - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog); - if (null == alert) { - return; - } - AlertDialog alertDialog = alert - .setTitle(R.string.brave_sync_settings_add_device_name_title) - .setMessage(getResources().getString(R.string.brave_sync_settings_add_device_name_label)) - .setView(view) - .setPositiveButton(R.string.ok, onClickListener) - .setNegativeButton(R.string.cancel, onClickListener) - .create(); - alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); - alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - KeyboardVisibilityDelegate.getInstance().showKeyboard(input); - } - }); - alertDialog.show(); - Button cancelButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); - cancelButton.setVisibility(View.GONE); - } + private void showEndDialog(String message) { + AlertDialog.Builder alert = + new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog); + if (null == alert) { + return; + } + DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int button) {} + }; + AlertDialog alertDialog = + alert.setTitle(getResources().getString(R.string.brave_sync_device)) + .setMessage(message) + .setPositiveButton(R.string.ok, onClickListener) + .create(); + alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); + alertDialog.show(); + } - private void deleteDeviceDialog(String deviceName, String deviceId, String deviceObjectId, View v) { + private void deleteDeviceDialog(BraveSyncDevices.SyncDeviceInfo deviceToDelete, View v) { + assert deviceToDelete != null; + assert !deviceToDelete.mName.isEmpty(); + assert deviceToDelete.mIsCurrentDevice; + Log.v(TAG, "deleteDeviceDialog deviceToDelete.mName=" + deviceToDelete.mName); AlertDialog.Builder alert = new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog); if (null == alert) { return; @@ -1226,41 +954,43 @@ private void deleteDeviceDialog(String deviceName, String deviceId, String devic @Override public void onClick(DialogInterface dialog, int button) { if (button == AlertDialog.BUTTON_POSITIVE) { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); + BraveActivity mainActivity = BraveActivity.getBraveActivity(); if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - new Thread() { - @Override - public void run() { - mainActivity.mBraveSyncWorker.SetUpdateDeleteDeviceName(BraveSyncWorker.DELETE_RECORD, deviceName, deviceId, deviceObjectId); - mainActivity.mBraveSyncWorker.InterruptSyncSleep(); - } - }.start(); - v.setEnabled(false); - startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_delete_sent)); + mainActivity.mBraveSyncWorker.ResetSync(); + InvalidateCodephrase(); + + try { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + setAppropriateView(); + } + }); + } catch (Exception exc) { + Log.e(TAG, "deleteDeviceDialog exception: " + exc); + } + + ViewGroup devicesUiGroup = + (ViewGroup) getView().findViewById(R.id.brave_sync_devices); + if (devicesUiGroup != null) { + devicesUiGroup.removeAllViews(); + } } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // new Thread() { - // @Override - // public void run() { - // mSyncService.onDeleteDevice(deviceId); - // } - // }.start(); - // v.setEnabled(false); - // startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_delete_sent)); - // } } } }; - AlertDialog alertDialog = alert - .setTitle(getResources().getString(R.string.brave_sync_remove_device_text)) - .setMessage(getString(R.string.brave_sync_delete_device, deviceName)) - .setPositiveButton(R.string.ok, onClickListener) - .setNegativeButton(R.string.cancel, onClickListener) - .create(); + String deviceNameToDisplay = deviceToDelete.mName + " " + + getResources().getString(R.string.brave_sync_this_device_text); + AlertDialog alertDialog = + alert.setTitle(getResources().getString(R.string.brave_sync_remove_device_text)) + .setMessage( + getString(R.string.brave_sync_delete_device, deviceNameToDisplay)) + .setPositiveButton(R.string.ok, onClickListener) + .setNegativeButton(R.string.cancel, onClickListener) + .create(); alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); alertDialog.show(); - } + } private void setJoinExistingChainLayout() { if (null != mScrollViewSyncInitial) { @@ -1318,23 +1048,29 @@ private void setNewChainLayout() { adjustImageButtons(getActivity().getApplicationContext().getResources().getConfiguration().orientation); } - private void cancelLoadingResetAndBack() { - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // mSyncService.onResetSync(); - // } - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - mainActivity.mBraveSyncWorker.ResetSync(); + private String mCodephrase; + public String GetCodephrase() { + if (mCodephrase == null || mCodephrase.isEmpty()) { + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + mCodephrase = mainActivity.mBraveSyncWorker.GetCodephrase(); } + return mCodephrase; + } + + public void InvalidateCodephrase() { + mCodephrase = null; } private void setAddMobileDeviceLayout() { getActivity().setTitle(R.string.brave_sync_btn_mobile); if (null != mBraveSyncTextViewAddMobileDevice) { setSyncText(getResources().getString(R.string.brave_sync_scan_sync_code), - getResources().getString(R.string.brave_sync_add_mobile_device_text_part_1) + "\n\n" + - getResources().getString(R.string.brave_sync_add_mobile_device_text_part_2) + "\n", mBraveSyncTextViewAddMobileDevice); + getResources().getString(R.string.brave_sync_add_mobile_device_text_part_1) + + "\n\n" + + getResources().getString( + R.string.brave_sync_add_mobile_device_text_part_2) + + "\n", + mBraveSyncTextViewAddMobileDevice); } if (null != mBraveSyncWarningTextViewAddMobileDevice) { String braveSyncCodeWarning = getResources().getString(R.string.brave_sync_code_warning); @@ -1363,32 +1099,65 @@ private void setAddMobileDeviceLayout() { getActivity().runOnUiThread(new Runnable() { @Override public void run() { - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // String seed = BravePrefServiceBridge.getInstance().getSyncSeed(); - // if (null == seed || seed.isEmpty()) { - // startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_loading_data_title)); - // // Init to receive new seed - // mSyncService.onSetupSyncNewToSync(mDeviceName); - // } - // } - - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); + BraveActivity mainActivity = BraveActivity.getBraveActivity(); if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - String seed = sharedPref.getString(BraveSyncWorker.PREF_SEED, null); - if (null == seed || seed.isEmpty()) { - startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_loading_data_title)); - // Init to receive new seed - mainActivity.mBraveSyncWorker.InitSync(true, true); + String seedHex = + mainActivity.mBraveSyncWorker.GetSeedHexFromWords(GetCodephrase()); + if (null == seedHex || seedHex.isEmpty()) { + // Give up, seed must be valid + Log.e(TAG, "setAddMobileDeviceLayout seedHex is empty"); + assert false; } else { - mSyncScreensObserver.onSeedReceived(seed, false, true); + fillQrCode(seedHex); } } } }); } + private void fillQrCode(String qrDataFinal) { + if (!isBarCodeValid(qrDataFinal)) { + Log.e(TAG, "fillQrCode - invalid QR code"); + // Normally must not reach here ever, because the code is validated right after scan + assert false; + showEndDialog(getResources().getString(R.string.sync_device_failure)); + return; + } + + new Thread(new Runnable() { + @Override + public void run() { + // Generate QR code + BitMatrix result; + try { + result = new MultiFormatWriter().encode( + qrDataFinal, BarcodeFormat.QR_CODE, WIDTH, WIDTH, null); + } catch (WriterException e) { + Log.e(TAG, "QR code unsupported format: " + e); + return; + } + int w = result.getWidth(); + int h = result.getHeight(); + int[] pixels = new int[w * h]; + for (int y = 0; y < h; y++) { + int offset = y * w; + for (int x = 0; x < w; x++) { + pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; + } + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, WIDTH, 0, 0, w, h); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mQRCodeImage.setImageBitmap(bitmap); + mQRCodeImage.invalidate(); + } + }); + } + }).start(); + } + private void setAddLaptopLayout() { getActivity().setTitle(R.string.brave_sync_btn_laptop); if (null != mBraveSyncTextViewAddLaptop) { @@ -1425,60 +1194,25 @@ private void setAddLaptopLayout() { getActivity().runOnUiThread(new Runnable() { @Override public void run() { - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - String seed = sharedPref.getString(BraveSyncWorker.PREF_SEED, null); - if (null == seed || seed.isEmpty()) { - startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_loading_data_title)); - // Init to receive new seed - mainActivity.mBraveSyncWorker.InitSync(true, true); - } else { - mSyncScreensObserver.onSeedReceived(seed, false, true); - } - } - // TODO(sergz): use service when we migrate to sync v2 - // if (null != mSyncService) { - // String seed = BravePrefServiceBridge.getInstance().getSyncSeed(); - // if (null == seed || seed.isEmpty()) { - // startTimeoutTimerWithPopup(getResources().getString(R.string.brave_sync_loading_data_title)); - // // Init to receive new seed - // mSyncService.onSetupSyncNewToSync(mDeviceName); - // } - // } + String codePhrase = GetCodephrase(); + assert codePhrase != null && !codePhrase.isEmpty(); + mBraveSyncAddDeviceCodeWords.setText(codePhrase); } }); } - private void scheduleCancelButton() { - // String deviceId = BravePrefServiceBridge.getInstance().getSyncDeviceId(); - SharedPreferences sharedPref = getActivity().getApplicationContext().getSharedPreferences(BraveSyncWorker.PREF_NAME, 0); - String deviceId = sharedPref.getString(BraveSyncWorker.PREF_DEVICE_ID, null); - boolean syncChainExists = (deviceId != null && !deviceId.isEmpty()); - if (!syncChainExists) { - mCancelLoadingButtonUpdater = new Timer(); - mCancelLoadingButtonUpdater.schedule(new TimerTask() { - @Override - public void run() { - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mCancelLoadingButton.setVisibility(View.VISIBLE); - } - }); - } - }, CANCEL_LOAD_BUTTON_TIMEOUT); - } - } + private void setSyncDoneLayout() { + BraveActivity mainActivity = BraveActivity.getBraveActivity(); + assert (null != mainActivity && null != mainActivity.mBraveSyncWorker); + boolean firstSetupComplete = mainActivity.mBraveSyncWorker.IsFirstSetupComplete(); + mainActivity.mBraveSyncWorker.SaveCodephrase(GetCodephrase()); + mainActivity.mBraveSyncWorker.FinalizeSyncSetup(); - private void dismissCancelLoadingButton() { - mCancelLoadingButton.setVisibility(View.GONE); - if (mCancelLoadingButtonUpdater != null) { - mCancelLoadingButtonUpdater.cancel(); + if (!deviceInfoObserverSet) { + BraveSyncDevices.get().addDeviceInfoChangedListener(this); + deviceInfoObserverSet = true; } - } - private void setSyncDoneLayout() { getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); getActivity().setTitle(R.string.sync_category_title); if (null != mCameraSourcePreview) { @@ -1506,32 +1240,14 @@ private void setSyncDoneLayout() { adjustWidth(mScrollViewSyncDone, false); mScrollViewSyncDone.setVisibility(View.VISIBLE); } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // if (null != mSyncSwitchBookmarks) { - // mSyncSwitchBookmarks.setChecked(false); - // } - // } - if (null != mRemoveDeviceButton) { - // It should become visible as soon as we get all devices info - mRemoveDeviceButton.setVisibility(View.GONE); - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // if (null != mSyncService) { - // mBraveSyncTextDevicesTitle.setText(getResources().getString(R.string.brave_sync_loading_devices_title)); - // } + // With sync v2 we may leave the sync chain even if we don't see other + // devices in chain, mRemoveDeviceButton is always visible - BraveActivity mainActivity = BraveRewardsHelper.getBraveActivity(); - if (null != mainActivity && null != mainActivity.mBraveSyncWorker) { + if (null != mainActivity) { mBraveSyncTextDevicesTitle.setText(getResources().getString(R.string.brave_sync_loading_devices_title)); - mainActivity.mBraveSyncWorker.InterruptSyncSleep(); } - scheduleCancelButton(); - - if (null != mSyncScreensObserver) { - mSyncScreensObserver.onDevicesAvailable(); - } + onDevicesAvailable(); } private void adjustWidth(View view, boolean special) { @@ -1600,99 +1316,9 @@ public boolean onBackPressed() { setJoinExistingChainLayout(); return true; } - cancelTimeoutTimer(); return false; } @Override - public void onCreatePreferences(Bundle bundle, String s) {} - - @Override - public void onGetSettingsAndDevices(ArrayList devices) { - try { - if (null == getActivity()) { - return; - } - getActivity() - .runOnUiThread( - new Runnable() { - @Override - public void run() { - if (View.VISIBLE != mScrollViewSyncDone.getVisibility()) { - Log.w(TAG, "No need to load devices for other pages"); - return; - } - // TODO(sergz): Uncomment sync service impl when we fully migrate on sync v2 - // String currentDeviceId = BravePrefServiceBridge.getInstance().getSyncDeviceId(); - // Load other devices in chain - // if (null != mSyncService) { - // new Thread(new Runnable() { - // @Override - // public void run() { - // if (null == getActivity()) { - // return; - // } - // getActivity().runOnUiThread(new Runnable() { - // @Override - // public void run() { - // ViewGroup insertPoint = (ViewGroup) getView().findViewById(R.id.brave_sync_devices); - // insertPoint.removeAllViews(); - // cancelTimeoutTimer(); - // int index = 0; - // for (BraveSyncService.ResolvedRecordToApply device : devices) { - // View separator = (View) mInflater.inflate(R.layout.menu_separator, null); - // View listItemView = (View) mInflater.inflate(R.layout.brave_sync_device, null); - // if (null != listItemView && null != separator && null != insertPoint) { - // TextView textView = (TextView) listItemView.findViewById(R.id.brave_sync_device_text); - // if (null != textView) { - // textView.setText(device.mDeviceName); - // } - // AppCompatImageView deleteButton = (AppCompatImageView) listItemView.findViewById(R.id.brave_sync_remove_device); - // if (null != deleteButton) { - // if (currentDeviceId.equals(device.mDeviceId)) { - // // Current device is deleted by button on the bottom - // deleteButton.setVisibility(View.GONE); - // if (null != textView) { - // // Highlight curret device - // textView.setTextColor(ApiCompatibilityUtils.getColor(getActivity().getResources(), R.color.brave_theme_color)); - // String currentDevice = device.mDeviceName + " " + getResources().getString(R.string.brave_sync_this_device_text); - // textView.setText(currentDevice); - // } - // if (null != mRemoveDeviceButton) { - // mRemoveDeviceButton.setTag(device); - // mRemoveDeviceButton.setVisibility(View.VISIBLE); - // mRemoveDeviceButton.setEnabled(true); - // } - // } else { - // deleteButton.setTag(device); - // deleteButton.setOnClickListener(v -> { - // BraveSyncService.ResolvedRecordToApply deviceToDelete = (BraveSyncService.ResolvedRecordToApply) v.getTag(); - // deleteDeviceDialog(deviceToDelete.mDeviceName, deviceToDelete.mDeviceId, deviceToDelete.mObjectId, v); - // }); - // } - // } - - // insertPoint.addView(separator, index++); - // insertPoint.addView(listItemView, index++); - // } - // } - // if (index > 0) { - // dismissCancelLoadingButton(); - // mBraveSyncTextDevicesTitle.setText(getResources().getString(R.string.brave_sync_devices_title)); - // View separator = (View) mInflater.inflate(R.layout.menu_separator, null); - // if (null != insertPoint && null != separator) { - // insertPoint.addView(separator, index++); - // } - // } - // } - // }); - // } - // }).start(); - // } - } - }); - } catch (Exception exc) { - Log.e(TAG, "onDevicesAvailable exception: " + exc); - } - } + public void onCreatePreferences(Bundle bundle, String s) {} /**/ } diff --git a/android/java/org/chromium/chrome/browser/sync/BraveSyncDevices.java b/android/java/org/chromium/chrome/browser/sync/BraveSyncDevices.java new file mode 100644 index 000000000000..25aefa34c6fe --- /dev/null +++ b/android/java/org/chromium/chrome/browser/sync/BraveSyncDevices.java @@ -0,0 +1,138 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.sync; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +@JNINamespace("chrome::android") +public class BraveSyncDevices { + public static final String TAG = "SYNC"; + private long mNativeBraveSyncDevicesAndroid = 0; + + private static BraveSyncDevices sBraveSyncDevices; + private static boolean sInitialized; + + public static BraveSyncDevices get() { + ThreadUtils.assertOnUiThread(); + if (!sInitialized) { + sBraveSyncDevices = new BraveSyncDevices(); + sInitialized = true; + } + return sBraveSyncDevices; + } + + public BraveSyncDevices() { + Init(); + } + + @CalledByNative + private void setNativePtr(long nativePtr) { + assert mNativeBraveSyncDevicesAndroid == 0; + mNativeBraveSyncDevicesAndroid = nativePtr; + } + + private void Init() { + if (mNativeBraveSyncDevicesAndroid == 0) { + nativeInit(); + } + } + + @Override + protected void finalize() { + Destroy(); + } + + private void Destroy() { + if (mNativeBraveSyncDevicesAndroid != 0) { + nativeDestroy(mNativeBraveSyncDevicesAndroid); + mNativeBraveSyncDevicesAndroid = 0; + } + } + + /** + * Listener for the devices syncchain changes. + */ + public interface DeviceInfoChangedListener { + // Invoked when the device info has changed. + public void deviceInfoChanged(); + } + + // Sync state changes more often than listeners are added/removed, so using CopyOnWrite. + private final List mDeviceInfoListeners = + new CopyOnWriteArrayList(); + + public void addDeviceInfoChangedListener(DeviceInfoChangedListener listener) { + ThreadUtils.assertOnUiThread(); + mDeviceInfoListeners.add(listener); + } + + public void removeDeviceInfoChangedListener(DeviceInfoChangedListener listener) { + ThreadUtils.assertOnUiThread(); + mDeviceInfoListeners.remove(listener); + } + + /** + * Called when the state of the native sync engine has changed, so various + * UI elements can update themselves. + */ + @CalledByNative + protected void deviceInfoChanged() { + for (DeviceInfoChangedListener listener : mDeviceInfoListeners) { + listener.deviceInfoChanged(); + } + } + + public class SyncDeviceInfo { + public String mName; + public boolean mIsCurrentDevice; + public String mType; + public Date mLastUpdatedTimestamp; + } + + public ArrayList GetSyncDeviceList() { + ArrayList deviceList = new ArrayList(); + String json = nativeGetSyncDeviceListJson(mNativeBraveSyncDevicesAndroid); + // Add root element to make it real JSON, otherwise getJSONArray cannot parse it + json = "{\"devices\":" + json + "}"; + try { + JSONObject result = new JSONObject(json); + JSONArray devices = result.getJSONArray("devices"); + Log.i(TAG, "GetSyncDeviceList devices length is " + devices.length()); + for (int i = 0; i < devices.length(); i++) { + SyncDeviceInfo deviceInfo = new SyncDeviceInfo(); + JSONObject device = devices.getJSONObject(i); + deviceInfo.mName = device.getString("name"); + deviceInfo.mIsCurrentDevice = device.getBoolean("isCurrentDevice"); + deviceInfo.mType = device.getString("type"); + long lastUpdatedTimestamp = device.getLong("lastUpdatedTimestamp"); + deviceInfo.mLastUpdatedTimestamp = new Date(lastUpdatedTimestamp); + deviceList.add(deviceInfo); + } + } catch (JSONException e) { + Log.e(TAG, "GetDeviceNameByObjectId JSONException error " + e); + } catch (IllegalStateException e) { + Log.e(TAG, "GetDeviceNameByObjectId IllegalStateException error " + e); + } + return deviceList; + } + + private native void nativeInit(); + private native void nativeDestroy(long nativeBraveSyncDevicesAndroid); + + private native String nativeGetSyncDeviceListJson(long nativeBraveSyncDevicesAndroid); +} diff --git a/android/java/org/chromium/chrome/browser/sync/BraveSyncService.java b/android/java/org/chromium/chrome/browser/sync/BraveSyncService.java deleted file mode 100644 index c3530b3136fb..000000000000 --- a/android/java/org/chromium/chrome/browser/sync/BraveSyncService.java +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.sync; - -import java.util.ArrayList; - -public class BraveSyncService { - public static final int NICEWARE_WORD_COUNT = 16; - public static final int BIP39_WORD_COUNT = 24; - - private static BraveSyncService sInstance; - private static final Object mLock = new Object(); - - public static BraveSyncService getInstance() { - synchronized (mLock) { - if (sInstance == null) { - sInstance = new BraveSyncService(); - } - } - return sInstance; - } - - private BraveSyncService() {} - - class BookmarkInternal { - public BookmarkInternal() {} - } - - public class ResolvedRecordToApply implements Comparable { - public ResolvedRecordToApply(String objectId, String action, - BookmarkInternal bookMarkInternal, String deviceName, String deviceId, - long syncTime) {} - - public String mObjectId; - public String mDeviceName; - public String mDeviceId; - - @Override - public int compareTo(ResolvedRecordToApply compare) { - return 0; - } - } - - public void onSetupSyncHaveCode(String syncWords, String deviceName) {} - public void onSetupSyncNewToSync(String deviceName) {} - public void onDeleteDevice(String deviceId) {} - public void onResetSync() {} - - public interface GetSettingsAndDevicesCallback { - public void onGetSettingsAndDevices(ArrayList devices); - } - - public void getSettingsAndDevices(GetSettingsAndDevicesCallback callback) {} - - public void getSyncWords() {} - public String getSeed() { - return ""; - } - - public void onSetSyncEnabled(boolean enabled) {} - public void onSetSyncBookmarks(boolean syncBookmarks) {} - public void onSetSyncBrowsingHistory(boolean syncBrowsingHistory) {} - public void onSetSyncSavedSiteSettings(boolean syncSavedSiteSettings) {} -} diff --git a/android/java/org/chromium/chrome/browser/sync/BraveSyncServiceObserver.java b/android/java/org/chromium/chrome/browser/sync/BraveSyncServiceObserver.java deleted file mode 100644 index 5a2428615af3..000000000000 --- a/android/java/org/chromium/chrome/browser/sync/BraveSyncServiceObserver.java +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.chromium.chrome.browser.sync; - -/** - * Allows observing sync service events. - */ -public interface BraveSyncServiceObserver { - /** - * Informs when sync setup has an error. - */ - public void onSyncSetupError(String message); - - /** - * Informs when the sync state has changed. - */ - public void onSyncStateChanged(); - - /** - * Informs when the sync words are received. - */ - public void onHaveSyncWords(String[] syncWords); -} diff --git a/android/java/org/chromium/chrome/browser/sync/settings/BraveManageSyncSettings.java b/android/java/org/chromium/chrome/browser/sync/settings/BraveManageSyncSettings.java new file mode 100644 index 000000000000..3600010736b7 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/sync/settings/BraveManageSyncSettings.java @@ -0,0 +1,36 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.sync.settings; + +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.preference.Preference; + +import org.chromium.chrome.browser.sync.settings.ManageSyncSettings; +import org.chromium.chrome.browser.ui.brave_tricks.checkbox_to_switch.CheckBoxPreference; + +// See org.brave.bytecode.BraveManageSyncSettingsClassAdapter +public class BraveManageSyncSettings extends ManageSyncSettings { + private Preference mGoogleActivityControls; + + private Preference mSyncEncryption; + + private Preference mManageSyncData; + + private CheckBoxPreference mSyncPaymentsIntegration; + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { + super.onCreatePreferences(savedInstanceState, rootKey); + + getPreferenceScreen().removePreference(mGoogleActivityControls); + getPreferenceScreen().removePreference(mSyncEncryption); + getPreferenceScreen().removePreference(mManageSyncData); + + mSyncPaymentsIntegration.setVisible(false); + } +} diff --git a/android/java/org/chromium/chrome/browser/ui/brave_tricks/checkbox_to_switch/CheckBoxPreference.java b/android/java/org/chromium/chrome/browser/ui/brave_tricks/checkbox_to_switch/CheckBoxPreference.java new file mode 100644 index 000000000000..6605cd46fed5 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/ui/brave_tricks/checkbox_to_switch/CheckBoxPreference.java @@ -0,0 +1,17 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.ui.brave_tricks.checkbox_to_switch; + +import android.content.Context; +import android.util.AttributeSet; + +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference; + +public class CheckBoxPreference extends ChromeSwitchPreference { + public CheckBoxPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } +} diff --git a/android/java/res/layout/add_sync_device_name_dialog.xml b/android/java/res/layout/add_sync_device_name_dialog.xml deleted file mode 100644 index 384ac256a2af..000000000000 --- a/android/java/res/layout/add_sync_device_name_dialog.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - diff --git a/android/java/res/layout/brave_sync_device.xml b/android/java/res/layout/brave_sync_device.xml index 425f68ed2305..2142c6401af4 100644 --- a/android/java/res/layout/brave_sync_device.xml +++ b/android/java/res/layout/brave_sync_device.xml @@ -27,19 +27,6 @@ android:textSize="16sp" android:layout_centerVertical="true" android:layout_toEndOf="@+id/brave_sync_device_image" - android:layout_toStartOf="@+id/brave_sync_remove_device" android:paddingStart="10dip" /> - - diff --git a/android/java/res/layout/brave_sync_done.xml b/android/java/res/layout/brave_sync_done.xml index d09e776d2177..5315ce8e87cb 100644 --- a/android/java/res/layout/brave_sync_done.xml +++ b/android/java/res/layout/brave_sync_done.xml @@ -28,138 +28,7 @@ android:paddingTop="30dip" android:visibility="gone" /> - - - - - - - - - - - - - - - - - + -