{"_id":"5a6b684793313c005b692e1c","category":{"_id":"5a6b684793313c005b692e0a","version":"5a6b684793313c005b692e07","project":"57c87ef85754fa1700b1228d","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2014-11-05T21:53:37.386Z","from_sync":false,"order":2,"slug":"reference","title":"Reference"},"project":"57c87ef85754fa1700b1228d","user":"55e5ba046015ce1900eadb8e","parentDoc":null,"version":{"_id":"5a6b684793313c005b692e07","project":"57c87ef85754fa1700b1228d","__v":1,"createdAt":"2018-01-26T17:41:27.297Z","releaseDate":"2018-01-26T17:41:27.297Z","categories":["5a6b684793313c005b692e08","5a6b684793313c005b692e09","5a6b684793313c005b692e0a","5a6b684793313c005b692e0b"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"3.5.3","version":"3.5.3"},"githubsync":"","__v":0,"updates":["57e46b92f3d7fc0e009c502e"],"next":{"pages":[],"description":""},"createdAt":"2016-03-23T15:29:38.991Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":11,"body":"Validating your users' input is a core part of the onboarding process. The Primer Android SDK will allow you to be notified of this data, be it signup, login, password recovery, or anything else, and let you handle them.\n\n####User Validation Callbacks\n\nIn order to receive any of this information, you should override the method that corresponds to the validation you are trying to complete. (example: signup should override 'signUpWithFields()' )\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\n/**\\n * Handles Primer input data and user login state\\n */\\nclass LaunchActivity extends AbstractClientLaunchActivity {\\n    :::at:::Override\\n    public void validateFields(Map<String, Object> allFieldsMap, ValidationCallback validationResultCallback) {\\n        // check input fields on each screen\\n        validationResultCallback.submit(new ValidationResult());\\n    }\\n\\n    @Override\\n    public void signUpWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\\n        // sign up the user using the signup flow inputs\\n        callback.submit(new ValidationResult(), \\\"UNIQUE_IDENTIFIER_FOR_USER\\\");\\n    }\\n\\n    @Override\\n    public void logInWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\\n        // log in the user using the login flow inputs\\n        callback.submit(new ValidationResult(), \\\"UNIQUE_IDENTIFIER_FOR_USER\\\");\\n    }\\n\\n    @Override\\n    public void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\\n        // recover the user's password using the recover password flow inputs\\n        callback.submit(new ValidationResult());\\n    }\\n\\n    @Override\\n    public void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\\n        // authenticate the user with Facebook flow inputs\\n        callback.submit(new ValidationResult(), \\\"UNIQUE_IDENTIFIER_FOR_USER\\\", isSignup);\\n    }\\n\\n    @Override\\n    public void willCloseWithFields(Map<String, Object> allProperties) {\\n        // optionally use input fields from an abandoned flow\\n    }\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n####Authentication Methods\n\nIn most of these overrides, you will be provided a `Map` of the relevant input fields that consist of the String key and the attached value as an `Object`. Most methods also have a callback that you must always call, even if in an asynchronous manner. Until you do so, the SDK displays a loading overlay to the user.\n\nWhen Primer tries to advance to the next screen, we will first validate input fields. When we try to advance from a screen that has inputs on it, we will call the `validateFields` method. The `Map` contains all input fields of the screen. We will not advance to the next screen until we get a valid (or null) response from the callback.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void validateFields(Map<String, Object> allFieldsMap, ValidationCallback callback) {\\n    // Called when Primer is about to advance to the next screen.\\n    // It is a chance for you to check the input fields and block progression.\\n    // You MUST call the callback when finished.\\n    callback.submit(new ValidationResult());\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nWhen a login flow is submitted, the `logInWithFields()` method gets called. The `Map` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void logInWithFields(final Map<String, Object> allFieldsMap, UserValidationCallback callback) {\\n    //This is called when the 'login user' action is performed.\\n    //NOTE, you MUST tell the callback param that you are finished.\\n    //the Second parameter is required. \\n  \\t//If log in was successful, then you must pass in a unique String identifier\\n\\n    String emailAddress, password;\\n    if (allFieldsMap.containsKey(\\\"email\\\")) {\\n        emailAddress = (String) allFieldsMap.get(\\\"email\\\");\\n    }\\n    if (allFieldsMap.containsKey(\\\"password\\\")) {\\n        password = (String) allFieldsMap.get(\\\"password\\\");\\n    }\\n    //a blank ValidationResult is considered valid\\n    final ValidationResult result = new ValidationResult();\\n\\n    asyncMethodToLogUserIn(email, password, new FakeCallback() {\\n\\n        void onSuccess(String uniqueIdForThisUser) {\\n            //result is successful. Pass in the User ID\\n            callback.submit(result, uniqueIdForThisUser);\\n        }\\n\\n        void onFailure(String errorMessage) {\\n            //invalidate the result with an error message. \\n          \\t//Primer will not advance.\\n            result.invalidateWithErrorMessage(errorMessage);\\n            callback.submit(result, null);\\n          \\t//it was a failure, so there is no User Identifier. pass null\\n        }\\n    });\\n}\",\n      \"language\": \"java\",\n      \"name\": null\n    }\n  ]\n}\n[/block]\nWhen a signup flow is submitted, the `signUpWithFields` method is called. The `Map` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void signUpWithFields(Map<String, Object> allFieldsMap, final UserValidationCallback callback) {\\n    //This is called when the 'signup user' action is performed.\\n    //NOTE, you MUST tell the callback param that you are finished.\\n    //the Second parameter is required. \\n  \\t//If sign up was successful, you must pass in a unique String identifier\\n\\n    String emailAddress, password;\\n    if (allFieldsMap.containsKey(\\\"email\\\")) {\\n        emailAddress = (String) allFieldsMap.get(\\\"email\\\");\\n    }\\n    if (allFieldsMap.containsKey(\\\"password\\\")) {\\n        password = (String) allFieldsMap.get(\\\"password\\\");\\n    }\\n\\n    //a blank ValidationResult is considered valid\\n    final ValidationResult result = new ValidationResult();\\n\\n    asyncMethodToSignUserUp(email, password, new FakeCallback() {\\n\\n        void onSuccess(String uniqueIdForThisUser) {\\n            //result is successful. Pass in the User ID\\n            callback.submit(result, uniqueIdForThisUser);\\n        }\\n\\n        void onFailure(String errorMessage) {\\n            //invalidate the result with an error message. \\n          \\t//Primer will not advance.\\n            result.invalidateWithErrorMessage(errorMessage);\\n            callback.submit(result, null);\\n          \\t//it was a failure, so there is no User Identifier. pass null\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nWhen a recover password flow is submitted, the `recoverPasswordsWithFields` method is called. The `Map` contains all fields of the flow.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\\n    //This is called when the 'reset password' action is performed.\\n    //NOTE, you MUST tell the callback that you are finished.\\n\\n    String emailAddress;\\n    if (allFieldsMap.containsKey(\\\"email\\\")) {\\n        emailAddress = (String) allFieldsMap.get(\\\"email\\\");\\n    }\\n\\n    //a blank ValidationResult is considered valid\\n    final ValidationResult result = new ValidationResult();\\n\\n    asyncMethodToResetPassword(email, password, new FakeCallback() {\\n\\n        void onSuccess() {\\n            //reset password was successful.\\n            callback.submit(result);\\n        }\\n\\n        void onFailure(String errorMessage) {\\n            //invalidate the result with an error message.\\n          \\t//Primer will not advance.\\n            result.invalidateWithErrorMessage(errorMessage);\\n            callback.submit(result);\\n          \\t//it was a failure\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nTo get notified when an experience closes, implement the `willCloseWithFields` method. It gets called when the primer experience is finishing (except for successful logins and signups). The `Map` contains all fields entered up until this point.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void willCloseWithFields(@NonNull Map<String, Object> allProperties) { }\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n####Validation Result\n\nAll of these overridden methods for validation include a special callback object that the SDK expects you to interact with. Both have an optional `ValidationResult` parameter, and the user validation callback has an additional string parameter for the user's identifier in cases when a user will be logged in after a successful validation.\n\nIf the validation succeeds (i.e. there are no invalid fields or errors), call the completion callback with either a new validation result instance or `null` as the first parameter. Also, when the callback is a `UserValidationCallback`, pass in the unique user identifier as the second parameter.\n\nIf the validation fails (because there is at least one invalid field or an error occurred), call the completion callback with a validation result that you invalidated. There are multiple ways to do that:\n* invalidate the result with an error message (useful when an error occurs but there's no invalid field)\n* invalidate a field (its default error message will be displayed)\n* invalidate a field with a custom error message** \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"ValidationResult validationResult = new ValidationResult();\\nvalidationResult.invalidateWithErrorMessage(\\\"Error message.\\\");\\n\\n// or\\n\\nvalidationResult.invalidateField(\\\"key\\\");\\n\\n// or\\n\\nvalidationResult.invalidateField(\\\"key\\\", \\\"Error message.\\\");\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n####Facebook Login\n\nIf you'd like to set Facebook Login up as part of the Primer onboarding experience, it's easy to do so. Just integrate the v4+ version of the Facebook Android SDK by following their <a href=\"https://developers.facebook.com/docs/android/getting-started\" target=\"_blank\">Getting Started</a> guide. \n\nWhen a Facebook authentication finishes, the `authenticateFacebookWithFields` method gets called by the validation callback. The `Map` contains all requested Graph API fields that Facebook returned to the SDK. Note that these fields get added as user properties after a successful validation. This callback behaves much like the signup callback, except it has one more boolean parameter for tracking whether this user was signed up as a new user, or logged in as an existing user. Pass in true if your system created and signed up a new user. Pass in false if the user was logged in. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\\n    String identifier = (String) allFieldsMap.get(\\\"FB_IDENTIFIER\\\");\\n    callback.submit(new ValidationResult(), identifier, isSignup);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"In addition to the Graph API fields the SDK also adds `profile_pic` to the dictionary, setting it to the 800px x 800px user avatar URL gathered from Facebook. If you wish, you can overwrite this at any time by [appending a user property](doc:user-management#section-user-properties) with the same key.\"\n}\n[/block]","excerpt":"","slug":"authentication","type":"basic","title":"Login/Signup"}
Validating your users' input is a core part of the onboarding process. The Primer Android SDK will allow you to be notified of this data, be it signup, login, password recovery, or anything else, and let you handle them. ####User Validation Callbacks In order to receive any of this information, you should override the method that corresponds to the validation you are trying to complete. (example: signup should override 'signUpWithFields()' ) [block:code] { "codes": [ { "code": "\n/**\n * Handles Primer input data and user login state\n */\nclass LaunchActivity extends AbstractClientLaunchActivity {\n @Override\n public void validateFields(Map<String, Object> allFieldsMap, ValidationCallback validationResultCallback) {\n // check input fields on each screen\n validationResultCallback.submit(new ValidationResult());\n }\n\n @Override\n public void signUpWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\n // sign up the user using the signup flow inputs\n callback.submit(new ValidationResult(), \"UNIQUE_IDENTIFIER_FOR_USER\");\n }\n\n @Override\n public void logInWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\n // log in the user using the login flow inputs\n callback.submit(new ValidationResult(), \"UNIQUE_IDENTIFIER_FOR_USER\");\n }\n\n @Override\n public void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\n // recover the user's password using the recover password flow inputs\n callback.submit(new ValidationResult());\n }\n\n @Override\n public void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\n // authenticate the user with Facebook flow inputs\n callback.submit(new ValidationResult(), \"UNIQUE_IDENTIFIER_FOR_USER\", isSignup);\n }\n\n @Override\n public void willCloseWithFields(Map<String, Object> allProperties) {\n // optionally use input fields from an abandoned flow\n }\n}", "language": "java" } ] } [/block] ####Authentication Methods In most of these overrides, you will be provided a `Map` of the relevant input fields that consist of the String key and the attached value as an `Object`. Most methods also have a callback that you must always call, even if in an asynchronous manner. Until you do so, the SDK displays a loading overlay to the user. When Primer tries to advance to the next screen, we will first validate input fields. When we try to advance from a screen that has inputs on it, we will call the `validateFields` method. The `Map` contains all input fields of the screen. We will not advance to the next screen until we get a valid (or null) response from the callback. [block:code] { "codes": [ { "code": "@Override\npublic void validateFields(Map<String, Object> allFieldsMap, ValidationCallback callback) {\n // Called when Primer is about to advance to the next screen.\n // It is a chance for you to check the input fields and block progression.\n // You MUST call the callback when finished.\n callback.submit(new ValidationResult());\n}", "language": "java" } ] } [/block] When a login flow is submitted, the `logInWithFields()` method gets called. The `Map` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. [block:code] { "codes": [ { "code": "@Override\npublic void logInWithFields(final Map<String, Object> allFieldsMap, UserValidationCallback callback) {\n //This is called when the 'login user' action is performed.\n //NOTE, you MUST tell the callback param that you are finished.\n //the Second parameter is required. \n \t//If log in was successful, then you must pass in a unique String identifier\n\n String emailAddress, password;\n if (allFieldsMap.containsKey(\"email\")) {\n emailAddress = (String) allFieldsMap.get(\"email\");\n }\n if (allFieldsMap.containsKey(\"password\")) {\n password = (String) allFieldsMap.get(\"password\");\n }\n //a blank ValidationResult is considered valid\n final ValidationResult result = new ValidationResult();\n\n asyncMethodToLogUserIn(email, password, new FakeCallback() {\n\n void onSuccess(String uniqueIdForThisUser) {\n //result is successful. Pass in the User ID\n callback.submit(result, uniqueIdForThisUser);\n }\n\n void onFailure(String errorMessage) {\n //invalidate the result with an error message. \n \t//Primer will not advance.\n result.invalidateWithErrorMessage(errorMessage);\n callback.submit(result, null);\n \t//it was a failure, so there is no User Identifier. pass null\n }\n });\n}", "language": "java", "name": null } ] } [/block] When a signup flow is submitted, the `signUpWithFields` method is called. The `Map` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. [block:code] { "codes": [ { "code": "@Override\npublic void signUpWithFields(Map<String, Object> allFieldsMap, final UserValidationCallback callback) {\n //This is called when the 'signup user' action is performed.\n //NOTE, you MUST tell the callback param that you are finished.\n //the Second parameter is required. \n \t//If sign up was successful, you must pass in a unique String identifier\n\n String emailAddress, password;\n if (allFieldsMap.containsKey(\"email\")) {\n emailAddress = (String) allFieldsMap.get(\"email\");\n }\n if (allFieldsMap.containsKey(\"password\")) {\n password = (String) allFieldsMap.get(\"password\");\n }\n\n //a blank ValidationResult is considered valid\n final ValidationResult result = new ValidationResult();\n\n asyncMethodToSignUserUp(email, password, new FakeCallback() {\n\n void onSuccess(String uniqueIdForThisUser) {\n //result is successful. Pass in the User ID\n callback.submit(result, uniqueIdForThisUser);\n }\n\n void onFailure(String errorMessage) {\n //invalidate the result with an error message. \n \t//Primer will not advance.\n result.invalidateWithErrorMessage(errorMessage);\n callback.submit(result, null);\n \t//it was a failure, so there is no User Identifier. pass null\n }\n });\n}", "language": "java" } ] } [/block] When a recover password flow is submitted, the `recoverPasswordsWithFields` method is called. The `Map` contains all fields of the flow. [block:code] { "codes": [ { "code": "@Override\npublic void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\n //This is called when the 'reset password' action is performed.\n //NOTE, you MUST tell the callback that you are finished.\n\n String emailAddress;\n if (allFieldsMap.containsKey(\"email\")) {\n emailAddress = (String) allFieldsMap.get(\"email\");\n }\n\n //a blank ValidationResult is considered valid\n final ValidationResult result = new ValidationResult();\n\n asyncMethodToResetPassword(email, password, new FakeCallback() {\n\n void onSuccess() {\n //reset password was successful.\n callback.submit(result);\n }\n\n void onFailure(String errorMessage) {\n //invalidate the result with an error message.\n \t//Primer will not advance.\n result.invalidateWithErrorMessage(errorMessage);\n callback.submit(result);\n \t//it was a failure\n }\n });\n}", "language": "java" } ] } [/block] To get notified when an experience closes, implement the `willCloseWithFields` method. It gets called when the primer experience is finishing (except for successful logins and signups). The `Map` contains all fields entered up until this point. [block:code] { "codes": [ { "code": "@Override\npublic void willCloseWithFields(@NonNull Map<String, Object> allProperties) { }", "language": "java" } ] } [/block] ####Validation Result All of these overridden methods for validation include a special callback object that the SDK expects you to interact with. Both have an optional `ValidationResult` parameter, and the user validation callback has an additional string parameter for the user's identifier in cases when a user will be logged in after a successful validation. If the validation succeeds (i.e. there are no invalid fields or errors), call the completion callback with either a new validation result instance or `null` as the first parameter. Also, when the callback is a `UserValidationCallback`, pass in the unique user identifier as the second parameter. If the validation fails (because there is at least one invalid field or an error occurred), call the completion callback with a validation result that you invalidated. There are multiple ways to do that: * invalidate the result with an error message (useful when an error occurs but there's no invalid field) * invalidate a field (its default error message will be displayed) * invalidate a field with a custom error message** [block:code] { "codes": [ { "code": "ValidationResult validationResult = new ValidationResult();\nvalidationResult.invalidateWithErrorMessage(\"Error message.\");\n\n// or\n\nvalidationResult.invalidateField(\"key\");\n\n// or\n\nvalidationResult.invalidateField(\"key\", \"Error message.\");", "language": "java" } ] } [/block] ####Facebook Login If you'd like to set Facebook Login up as part of the Primer onboarding experience, it's easy to do so. Just integrate the v4+ version of the Facebook Android SDK by following their <a href="https://developers.facebook.com/docs/android/getting-started" target="_blank">Getting Started</a> guide. When a Facebook authentication finishes, the `authenticateFacebookWithFields` method gets called by the validation callback. The `Map` contains all requested Graph API fields that Facebook returned to the SDK. Note that these fields get added as user properties after a successful validation. This callback behaves much like the signup callback, except it has one more boolean parameter for tracking whether this user was signed up as a new user, or logged in as an existing user. Pass in true if your system created and signed up a new user. Pass in false if the user was logged in. [block:code] { "codes": [ { "code": "@Override\npublic void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\n String identifier = (String) allFieldsMap.get(\"FB_IDENTIFIER\");\n callback.submit(new ValidationResult(), identifier, isSignup);\n}", "language": "java" } ] } [/block] [block:callout] { "type": "info", "body": "In addition to the Graph API fields the SDK also adds `profile_pic` to the dictionary, setting it to the 800px x 800px user avatar URL gathered from Facebook. If you wish, you can overwrite this at any time by [appending a user property](doc:user-management#section-user-properties) with the same key." } [/block]