diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java index dde90fbcf5..f4637285f8 100644 --- a/android/src/com/mapswithme/maps/Framework.java +++ b/android/src/com/mapswithme/maps/Framework.java @@ -81,11 +81,13 @@ public class Framework public static final int ROUTE_REBUILD_AFTER_POINTS_LOADING = 0; @Retention(RetentionPolicy.SOURCE) - @IntDef({ SOCIAL_TOKEN_FACEBOOK, SOCIAL_TOKEN_GOOGLE }) - public @interface SocialTokenType {} + @IntDef({ SOCIAL_TOKEN_FACEBOOK, SOCIAL_TOKEN_GOOGLE, TOKEN_MAPSME }) + public @interface AuthTokenType + {} public static final int SOCIAL_TOKEN_FACEBOOK = 0; public static final int SOCIAL_TOKEN_GOOGLE = 1; + public static final int TOKEN_MAPSME = 2; @SuppressWarnings("unused") public interface MapObjectListener @@ -381,7 +383,7 @@ public class Framework public static native Banner[] nativeGetSearchBanners(); public static native void nativeAuthenticateUser(@NonNull String socialToken, - @SocialTokenType int socialTokenType, + @AuthTokenType int socialTokenType, @NonNull AuthorizationListener listener); public static native boolean nativeIsUserAuthenticated(); diff --git a/android/src/com/mapswithme/maps/auth/Authorizer.java b/android/src/com/mapswithme/maps/auth/Authorizer.java index ede53c49a3..c1d81a936a 100644 --- a/android/src/com/mapswithme/maps/auth/Authorizer.java +++ b/android/src/com/mapswithme/maps/auth/Authorizer.java @@ -70,16 +70,38 @@ public class Authorizer implements AuthorizationListener public final void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (requestCode != Constants.REQ_CODE_GET_SOCIAL_TOKEN - || resultCode != Activity.RESULT_OK || data == null) + + if (requestCode != Constants.REQ_CODE_GET_SOCIAL_TOKEN) + return; + + if (data == null) + return; + + if (resultCode == Activity.RESULT_CANCELED) { + if (mCallback == null) + return; + + @Framework.AuthTokenType + int type = data.getIntExtra(Constants.EXTRA_TOKEN_TYPE, -1); + boolean isCancel = data.getBooleanExtra(Constants.EXTRA_IS_CANCEL, false); + if (isCancel) + { + mCallback.onSocialAuthenticationCancel(type); + return; + } + + mCallback.onSocialAuthenticationError(type, data.getStringExtra(Constants.EXTRA_AUTH_ERROR)); return; } + if (resultCode != Activity.RESULT_OK) + return; + String socialToken = data.getStringExtra(Constants.EXTRA_SOCIAL_TOKEN); if (!TextUtils.isEmpty(socialToken)) { - @Framework.SocialTokenType + @Framework.AuthTokenType int type = data.getIntExtra(Constants.EXTRA_TOKEN_TYPE, -1); mIsAuthorizationInProgress = true; if (mCallback != null) @@ -110,5 +132,7 @@ public class Authorizer implements AuthorizationListener { void onAuthorizationFinish(boolean success); void onAuthorizationStart(); + void onSocialAuthenticationCancel(@Framework.AuthTokenType int type); + void onSocialAuthenticationError(@Framework.AuthTokenType int type, @Nullable String error); } } diff --git a/android/src/com/mapswithme/maps/auth/Constants.java b/android/src/com/mapswithme/maps/auth/Constants.java index a702b45291..6b48ae075c 100644 --- a/android/src/com/mapswithme/maps/auth/Constants.java +++ b/android/src/com/mapswithme/maps/auth/Constants.java @@ -8,6 +8,8 @@ class Constants static final int REQ_CODE_GET_SOCIAL_TOKEN = 101; static final String EXTRA_SOCIAL_TOKEN = "extra_social_token"; static final String EXTRA_TOKEN_TYPE = "extra_token_type"; + static final String EXTRA_AUTH_ERROR = "extra_auth_error"; + static final String EXTRA_IS_CANCEL = "extra_is_cancel"; static final List FACEBOOK_PERMISSIONS = Arrays.asList("email", "user_friends"); } diff --git a/android/src/com/mapswithme/maps/auth/SocialAuthDialogFragment.java b/android/src/com/mapswithme/maps/auth/SocialAuthDialogFragment.java index f4f42d0bb2..cb0329be12 100644 --- a/android/src/com/mapswithme/maps/auth/SocialAuthDialogFragment.java +++ b/android/src/com/mapswithme/maps/auth/SocialAuthDialogFragment.java @@ -51,7 +51,7 @@ public class SocialAuthDialogFragment extends BaseMwmDialogFragment public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_auth_passport_dialog, container, false); - LoginButton button = (LoginButton) view.findViewById(R.id.loging_button); + LoginButton button = view.findViewById(R.id.loging_button); button.setReadPermissions(Constants.FACEBOOK_PERMISSIONS); button.setFragment(this); button.registerCallback(mCallbackManager, new FBCallback(this)); @@ -78,19 +78,18 @@ public class SocialAuthDialogFragment extends BaseMwmDialogFragment } private void sendResult(int resultCode, @Nullable String socialToken, - @Framework.SocialTokenType int type) + @Framework.AuthTokenType int type, @Nullable String error, + boolean isCancel) { Fragment caller = getTargetFragment(); if (caller == null) return; - Intent data = null; - if (resultCode == Activity.RESULT_OK) - { - data = new Intent(); - data.putExtra(Constants.EXTRA_SOCIAL_TOKEN, socialToken); - data.putExtra(Constants.EXTRA_TOKEN_TYPE, type); - } + Intent data = new Intent(); + data.putExtra(Constants.EXTRA_SOCIAL_TOKEN, socialToken); + data.putExtra(Constants.EXTRA_TOKEN_TYPE, type); + data.putExtra(Constants.EXTRA_AUTH_ERROR, error); + data.putExtra(Constants.EXTRA_IS_CANCEL, isCancel); caller.onActivityResult(Constants.REQ_CODE_GET_SOCIAL_TOKEN, resultCode, data); } @@ -104,10 +103,11 @@ public class SocialAuthDialogFragment extends BaseMwmDialogFragment @Override public void onDismiss(DialogInterface dialog) { - Statistics.INSTANCE.trackEvent(Statistics.EventName.UGC_AUTH_DECLINED); AccessToken token = AccessToken.getCurrentAccessToken(); - sendResult(Activity.RESULT_OK, token != null ? token.getToken() : null, - Framework.SOCIAL_TOKEN_FACEBOOK); + int resultCode = token == null || TextUtils.isEmpty(token.getToken()) ? Activity.RESULT_CANCELED + : Activity.RESULT_OK; + sendResult(resultCode, token != null ? token.getToken() : null, + Framework.SOCIAL_TOKEN_FACEBOOK, null, true); super.onDismiss(dialog); } @@ -131,28 +131,28 @@ public class SocialAuthDialogFragment extends BaseMwmDialogFragment @Override public void onCancel() { - Statistics.INSTANCE.trackEvent(Statistics.EventName.UGC_AUTH_DECLINED); LOGGER.w(TAG, "onCancel"); - sendResult(Activity.RESULT_CANCELED, null, Framework.SOCIAL_TOKEN_FACEBOOK); + sendResult(Activity.RESULT_CANCELED, null, Framework.SOCIAL_TOKEN_FACEBOOK, + null, true); } @Override public void onError(FacebookException error) { - Statistics.INSTANCE.trackUGCAuthFailed(Statistics.ParamValue.FACEBOOK, - error != null ? error.getMessage() : null); LOGGER.e(TAG, "onError", error); - sendResult(Activity.RESULT_CANCELED, null, Framework.SOCIAL_TOKEN_FACEBOOK); + sendResult(Activity.RESULT_CANCELED, null, Framework.SOCIAL_TOKEN_FACEBOOK, + error != null ? error.getMessage() : null, false); } private void sendResult(int resultCode, @Nullable String socialToken, - @Framework.SocialTokenType int type) + @Framework.AuthTokenType int type, @Nullable String error, + boolean isCancel) { SocialAuthDialogFragment fragment = mFragmentRef.get(); if (fragment == null) return; - fragment.sendResult(resultCode, socialToken, type); + fragment.sendResult(resultCode, socialToken, type, error, isCancel); } } } diff --git a/android/src/com/mapswithme/maps/bookmarks/BookmarkCategoriesFragment.java b/android/src/com/mapswithme/maps/bookmarks/BookmarkCategoriesFragment.java index 5f3bb21fae..cafa9bcdc8 100644 --- a/android/src/com/mapswithme/maps/bookmarks/BookmarkCategoriesFragment.java +++ b/android/src/com/mapswithme/maps/bookmarks/BookmarkCategoriesFragment.java @@ -64,8 +64,8 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment super.onViewCreated(view, savedInstanceState); mLoadingPlaceholder = view.findViewById(R.id.placeholder_loading); - mBackupController = new BookmarkBackupController(view.findViewById(R.id.backup)); - mBackupController.setAuthorizer(new Authorizer(this)); + mBackupController = new BookmarkBackupController(view.findViewById(R.id.backup), + new Authorizer(this)); if (getAdapter() != null) { getAdapter().setOnClickListener(this); @@ -209,7 +209,7 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment protected void setupPlaceholder(@NonNull PlaceholderView placeholder) { placeholder.setContent(R.drawable.img_bookmarks, R.string.bookmarks_empty_title, - R.string.bookmarks_usage_hint); + R.string.bookmarks_usage_hint); } @Override diff --git a/android/src/com/mapswithme/maps/bookmarks/data/BookmarkBackupController.java b/android/src/com/mapswithme/maps/bookmarks/data/BookmarkBackupController.java index a356250235..7aa7cd12e3 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/BookmarkBackupController.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/BookmarkBackupController.java @@ -6,10 +6,12 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; +import com.mapswithme.maps.Framework; import com.mapswithme.maps.R; import com.mapswithme.maps.auth.Authorizer; import com.mapswithme.maps.widget.BookmarkBackupView; import com.mapswithme.util.DateUtils; +import com.mapswithme.util.statistics.Statistics; import java.util.Date; @@ -17,35 +19,40 @@ public class BookmarkBackupController implements Authorizer.Callback { @NonNull private final BookmarkBackupView mBackupView; - @Nullable - private Authorizer mAuthorizer; @NonNull - private final View.OnClickListener mSignInClickListener = v -> + private final Authorizer mAuthorizer; + @NonNull + private final View.OnClickListener mSignInClickListener = new View.OnClickListener() { - if (mAuthorizer != null) + @Override + public void onClick(View v) + { mAuthorizer.authorize(); + Statistics.INSTANCE.trackBkmSyncProposalApproved(false); + } }; @NonNull - private final View.OnClickListener mEnableClickListener = v -> + private final View.OnClickListener mEnableClickListener = new View.OnClickListener() { - BookmarkManager.INSTANCE.setCloudEnabled(true); - update(); + @Override + public void onClick(View v) + { + BookmarkManager.INSTANCE.setCloudEnabled(true); + update(); + Statistics.INSTANCE.trackBkmSyncProposalApproved(mAuthorizer.isAuthorized()); + } }; - public BookmarkBackupController(@NonNull BookmarkBackupView backupView) + public BookmarkBackupController(@NonNull BookmarkBackupView backupView, @NonNull Authorizer authorizer) { mBackupView = backupView; - } - - public void setAuthorizer(@Nullable Authorizer authorizer) - { mAuthorizer = authorizer; } public void update() { final Context context = mBackupView.getContext(); - if (mAuthorizer != null && !mAuthorizer.isAuthorized()) + if (!mAuthorizer.isAuthorized()) { mBackupView.setMessage(context.getString(R.string.bookmarks_message_unauthorized_user)); mBackupView.setButtonLabel(context.getString(R.string.authorization_button_sign_in)); @@ -59,6 +66,7 @@ public class BookmarkBackupController implements Authorizer.Callback mBackupView.hideProgressBar(); mBackupView.setClickListener(mSignInClickListener); mBackupView.showButton(); + Statistics.INSTANCE.trackBkmSyncProposalShown(mAuthorizer.isAuthorized()); } return; } @@ -89,25 +97,23 @@ public class BookmarkBackupController implements Authorizer.Callback mBackupView.setButtonLabel(context.getString(R.string.bookmarks_backup)); mBackupView.setClickListener(mEnableClickListener); mBackupView.showButton(); + Statistics.INSTANCE.trackBkmSyncProposalShown(mAuthorizer.isAuthorized()); } public void onStart() { - if (mAuthorizer != null) - mAuthorizer.attach(this); + mAuthorizer.attach(this); update(); } public void onStop() { - if (mAuthorizer != null) - mAuthorizer.detach(); + mAuthorizer.detach(); } public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (mAuthorizer != null) - mAuthorizer.onActivityResult(requestCode, resultCode, data); + mAuthorizer.onActivityResult(requestCode, resultCode, data); } @Override @@ -120,7 +126,26 @@ public class BookmarkBackupController implements Authorizer.Callback public void onAuthorizationFinish(boolean success /* it's ignored for a while.*/) { if (success) + { BookmarkManager.INSTANCE.setCloudEnabled(true); + Statistics.INSTANCE.trackEvent(Statistics.EventName.BMK_SYNC_PROPOSAL_ENABLED); + } + else + { + Statistics.INSTANCE.trackBkmSyncProposalError(Framework.TOKEN_MAPSME, "Unknown error"); + } update(); } + + @Override + public void onSocialAuthenticationError(@Framework.AuthTokenType int type, @Nullable String error) + { + Statistics.INSTANCE.trackBkmSyncProposalError(type, error); + } + + @Override + public void onSocialAuthenticationCancel(@Framework.AuthTokenType int type) + { + Statistics.INSTANCE.trackBkmSyncProposalError(type, "Cancel"); + } } diff --git a/android/src/com/mapswithme/maps/settings/SettingsPrefsFragment.java b/android/src/com/mapswithme/maps/settings/SettingsPrefsFragment.java index b7a7bf78fe..923976fa55 100644 --- a/android/src/com/mapswithme/maps/settings/SettingsPrefsFragment.java +++ b/android/src/com/mapswithme/maps/settings/SettingsPrefsFragment.java @@ -746,7 +746,9 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment pref.setOnPreferenceChangeListener( (preference, newValue) -> { - BookmarkManager.INSTANCE.setCloudEnabled((Boolean) newValue); + Boolean value = (Boolean) newValue; + BookmarkManager.INSTANCE.setCloudEnabled(value); + Statistics.INSTANCE.trackBkmSettingsToggle(value); return true; }); } diff --git a/android/src/com/mapswithme/maps/ugc/UGCEditorFragment.java b/android/src/com/mapswithme/maps/ugc/UGCEditorFragment.java index 4dd019b89f..4099b910f4 100644 --- a/android/src/com/mapswithme/maps/ugc/UGCEditorFragment.java +++ b/android/src/com/mapswithme/maps/ugc/UGCEditorFragment.java @@ -10,6 +10,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.EditText; +import com.mapswithme.maps.Framework; import com.mapswithme.maps.R; import com.mapswithme.maps.auth.BaseMwmAuthorizationFragment; import com.mapswithme.maps.bookmarks.data.FeatureId; @@ -42,9 +43,9 @@ public class UGCEditorFragment extends BaseMwmAuthorizationFragment @Nullable Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_ugc_editor, container, false); - mReviewEditText = (EditText) root.findViewById(R.id.review); + mReviewEditText = root.findViewById(R.id.review); - RecyclerView rvRatingView = (RecyclerView) root.findViewById(R.id.ratings); + RecyclerView rvRatingView = root.findViewById(R.id.ratings); rvRatingView.setLayoutManager(new LinearLayoutManager(getContext())); rvRatingView.getLayoutManager().setAutoMeasureEnabled(true); rvRatingView.setNestedScrollingEnabled(false); @@ -109,6 +110,18 @@ public class UGCEditorFragment extends BaseMwmAuthorizationFragment getActivity().finish(); } + @Override + public void onSocialAuthenticationCancel(@Framework.AuthTokenType int type) + { + Statistics.INSTANCE.trackEvent(Statistics.EventName.UGC_AUTH_DECLINED); + } + + @Override + public void onSocialAuthenticationError(int type, @Nullable String error) + { + Statistics.INSTANCE.trackUGCAuthFailed(type, error); + } + private void onSubmitButtonClick() { List modifiedRatings = mUGCRatingAdapter.getItems(); diff --git a/android/src/com/mapswithme/util/statistics/Statistics.java b/android/src/com/mapswithme/util/statistics/Statistics.java index 54cd5a7ae7..7eaaf908c1 100644 --- a/android/src/com/mapswithme/util/statistics/Statistics.java +++ b/android/src/com/mapswithme/util/statistics/Statistics.java @@ -50,6 +50,10 @@ import static com.mapswithme.util.BatteryState.CHARGING_STATUS_PLUGGED; import static com.mapswithme.util.BatteryState.CHARGING_STATUS_UNKNOWN; import static com.mapswithme.util.BatteryState.CHARGING_STATUS_UNPLUGGED; import static com.mapswithme.util.statistics.Statistics.EventName.APPLICATION_COLD_STARTUP_INFO; +import static com.mapswithme.util.statistics.Statistics.EventName.BMK_SYNC_PROPOSAL_APPROVED; +import static com.mapswithme.util.statistics.Statistics.EventName.BMK_SYNC_PROPOSAL_ERROR; +import static com.mapswithme.util.statistics.Statistics.EventName.BMK_SYNC_PROPOSAL_SHOWN; +import static com.mapswithme.util.statistics.Statistics.EventName.BMK_SYNC_PROPOSAL_TOGGLE; import static com.mapswithme.util.statistics.Statistics.EventName.DISCOVERY_OPEN; import static com.mapswithme.util.statistics.Statistics.EventName.DOWNLOADER_DIALOG_ERROR; import static com.mapswithme.util.statistics.Statistics.EventName.PP_BANNER_BLANK; @@ -63,7 +67,6 @@ import static com.mapswithme.util.statistics.Statistics.EventName.PP_SPONSORED_S import static com.mapswithme.util.statistics.Statistics.EventName.PP_SPONSOR_ITEM_SELECTED; import static com.mapswithme.util.statistics.Statistics.EventName.ROUTING_PLAN_TOOLTIP_CLICK; import static com.mapswithme.util.statistics.Statistics.EventName.SEARCH_FILTER_CLICK; -import static com.mapswithme.util.statistics.Statistics.EventName.SEARCH_FILTER_OPEN; import static com.mapswithme.util.statistics.Statistics.EventName.UGC_AUTH_ERROR; import static com.mapswithme.util.statistics.Statistics.EventName.UGC_AUTH_EXTERNAL_REQUEST_SUCCESS; import static com.mapswithme.util.statistics.Statistics.EventName.UGC_AUTH_SHOWN; @@ -77,6 +80,7 @@ import static com.mapswithme.util.statistics.Statistics.EventParam.ERROR; import static com.mapswithme.util.statistics.Statistics.EventParam.ERROR_CODE; import static com.mapswithme.util.statistics.Statistics.EventParam.ERROR_MESSAGE; import static com.mapswithme.util.statistics.Statistics.EventParam.FEATURE_ID; +import static com.mapswithme.util.statistics.Statistics.EventParam.HAS_AUTH; import static com.mapswithme.util.statistics.Statistics.EventParam.HOTEL; import static com.mapswithme.util.statistics.Statistics.EventParam.HOTEL_LAT; import static com.mapswithme.util.statistics.Statistics.EventParam.HOTEL_LON; @@ -98,7 +102,10 @@ import static com.mapswithme.util.statistics.Statistics.EventParam.STATE; import static com.mapswithme.util.statistics.Statistics.EventParam.TYPE; import static com.mapswithme.util.statistics.Statistics.EventParam.VALUE; import static com.mapswithme.util.statistics.Statistics.ParamValue.BOOKING_COM; +import static com.mapswithme.util.statistics.Statistics.ParamValue.FACEBOOK; +import static com.mapswithme.util.statistics.Statistics.ParamValue.GOOGLE; import static com.mapswithme.util.statistics.Statistics.ParamValue.HOLIDAY; +import static com.mapswithme.util.statistics.Statistics.ParamValue.MAPSME; import static com.mapswithme.util.statistics.Statistics.ParamValue.OPENTABLE; import static com.mapswithme.util.statistics.Statistics.ParamValue.SEARCH_BOOKING_COM; import static com.mapswithme.util.statistics.Statistics.ParamValue.VIATOR; @@ -140,6 +147,11 @@ public enum Statistics public static final String BMK_GROUP_CHANGED = "Bookmark. Group changed"; public static final String BMK_COLOR_CHANGED = "Bookmark. Color changed"; public static final String BMK_CREATED = "Bookmark. Bookmark created"; + public static final String BMK_SYNC_PROPOSAL_SHOWN = "Bookmarks_SyncProposal_shown"; + public static final String BMK_SYNC_PROPOSAL_APPROVED = "Bookmarks_SyncProposal_approved"; + public static final String BMK_SYNC_PROPOSAL_ERROR = "Bookmarks_SyncProposal_error"; + public static final String BMK_SYNC_PROPOSAL_ENABLED = "Bookmarks_SyncProposal_enabled"; + public static final String BMK_SYNC_PROPOSAL_TOGGLE = "Settings_BookmarksSync_toggle"; // search public static final String SEARCH_CAT_CLICKED = "Search. Category clicked"; @@ -355,6 +367,7 @@ public enum Statistics static final String PLACEMENT = "placement"; public static final String PRICE_CATEGORY = "price_category"; public static final String DATE = "date"; + static final String HAS_AUTH = "has_auth"; private EventParam() {} } @@ -379,6 +392,8 @@ public enum Statistics public static final String CHECKIN = "check_in"; public static final String CHECKOUT = "check_out"; public static final String ANY = "any"; + public static final String GOOGLE = "google"; + public static final String MAPSME = "mapsme"; } // Initialized once in constructor and does not change until the process restarts. @@ -950,14 +965,30 @@ public enum Statistics trackEvent(UGC_AUTH_EXTERNAL_REQUEST_SUCCESS, params().add(EventParam.PROVIDER, provider)); } - public void trackUGCAuthFailed(@NonNull String provider, @Nullable String error) + public void trackUGCAuthFailed(@Framework.AuthTokenType int type, @Nullable String error) { trackEvent(UGC_AUTH_ERROR, params() - .add(EventParam.PROVIDER, provider) + .add(EventParam.PROVIDER, getAuthProvider(type)) .add(EventParam.ERROR, error) .get()); } + @NonNull + private static String getAuthProvider(@Framework.AuthTokenType int type) + { + switch (type) + { + case Framework.SOCIAL_TOKEN_FACEBOOK: + return FACEBOOK; + case Framework.SOCIAL_TOKEN_GOOGLE: + return GOOGLE; + case Framework.TOKEN_MAPSME: + return MAPSME; + default: + throw new AssertionError("Unknown social token type: " + type); + } + } + public void trackDiscoveryOpen() { trackEvent(DISCOVERY_OPEN, params().add(NETWORK, getConnectionState())); @@ -978,6 +1009,34 @@ public enum Statistics .get()); } + public void trackBkmSyncProposalShown(boolean hasAuth) + { + trackEvent(BMK_SYNC_PROPOSAL_SHOWN, params().add(HAS_AUTH, hasAuth ? 1 : 0).get()); + } + + public void trackBkmSyncProposalApproved(boolean hasAuth) + { + trackEvent(BMK_SYNC_PROPOSAL_APPROVED, params() + .add(HAS_AUTH, hasAuth ? 1 : 0) + .add(NETWORK, getConnectionState()) + .get()); + } + + public void trackBkmSyncProposalError(@Framework.AuthTokenType int type, @Nullable String message) + { + trackEvent(BMK_SYNC_PROPOSAL_ERROR, params() + .add(PROVIDER, getAuthProvider(type)) + .add(ERROR, message) + .get()); + } + + public void trackBkmSettingsToggle(boolean checked) + { + trackEvent(BMK_SYNC_PROPOSAL_TOGGLE, params() + .add(STATE, checked ? 1 : 0) + .get()); + } + public static ParameterBuilder params() { return new ParameterBuilder();