3. facebook.addActionListener(e -> {
final Login fb = FacebookConnect.getInstance();
if(UberClone.isDriverMode()) {
fb.setClientId("value for driver app");
fb.setClientSecret("value for driver app");
} else {
fb.setClientId("value for user app");
fb.setClientSecret("value for user app");
}
fb.setRedirectURI("https://www.codenameone.com/");
fb.setCallback(new LoginCallback() {
@Override
public void loginFailed(String errorMessage) {
ToastBar.showErrorMessage("Login failed: " + errorMessage);
}
@Override
public void loginSuccessful() {
String token = fb.getAccessToken().getToken();
new EnterPasswordForm(null, token, null).show();
}
});
fb.doLogin();
});
FacebookOrGoogleLoginForm
To get login working on the simulator we'll need a bit more. We'll also need to write code that supports the login process within the FacebookOrGoogleLoginForm class.
FacebookConnect is a subclass of the Login class that lets us login into facebook and request publish permissions if necessary
4. facebook.addActionListener(e -> {
final Login fb = FacebookConnect.getInstance();
if(UberClone.isDriverMode()) {
fb.setClientId("value for driver app");
fb.setClientSecret("value for driver app");
} else {
fb.setClientId("value for user app");
fb.setClientSecret("value for user app");
}
fb.setRedirectURI("https://www.codenameone.com/");
fb.setCallback(new LoginCallback() {
@Override
public void loginFailed(String errorMessage) {
ToastBar.showErrorMessage("Login failed: " + errorMessage);
}
@Override
public void loginSuccessful() {
String token = fb.getAccessToken().getToken();
new EnterPasswordForm(null, token, null).show();
}
});
fb.doLogin();
});
FacebookOrGoogleLoginForm
The client id and secret aren't used on devices. These are here strictly for the benefit of the simulator!
If you don't need to debug on the simulator the lines until setCallback are redundant...
Notice that we have two versions of these values for the User app and the driver app.
5. facebook.addActionListener(e -> {
final Login fb = FacebookConnect.getInstance();
if(UberClone.isDriverMode()) {
fb.setClientId("value for driver app");
fb.setClientSecret("value for driver app");
} else {
fb.setClientId("value for user app");
fb.setClientSecret("value for user app");
}
fb.setRedirectURI("https://www.codenameone.com/");
fb.setCallback(new LoginCallback() {
@Override
public void loginFailed(String errorMessage) {
ToastBar.showErrorMessage("Login failed: " + errorMessage);
}
@Override
public void loginSuccessful() {
String token = fb.getAccessToken().getToken();
new EnterPasswordForm(null, token, null).show();
}
});
fb.doLogin();
});
FacebookOrGoogleLoginForm
The callback is invoked upon login success/failure, if a login is successful we get the token from facebook which is an "authorization token". This token allows us to
access information within the Facebook graph API to query facts about the user. Notice we have a new constructor for EnterPasswordForm which I will discuss soon
6. facebook.addActionListener(e -> {
final Login fb = FacebookConnect.getInstance();
if(UberClone.isDriverMode()) {
fb.setClientId("value for driver app");
fb.setClientSecret("value for driver app");
} else {
fb.setClientId("value for user app");
fb.setClientSecret("value for user app");
}
fb.setRedirectURI("https://www.codenameone.com/");
fb.setCallback(new LoginCallback() {
@Override
public void loginFailed(String errorMessage) {
ToastBar.showErrorMessage("Login failed: " + errorMessage);
}
@Override
public void loginSuccessful() {
String token = fb.getAccessToken().getToken();
new EnterPasswordForm(null, token, null).show();
}
});
fb.doLogin();
});
FacebookOrGoogleLoginForm
This triggers the actual login but the method is asynchronous and login will only actually succeed or fail when the callback is reached
7. public EnterPasswordForm(String phoneNumber, String facebookId, String googleId) {
super(new BorderLayout());
Form previous = getCurrentForm();
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
boolean exists = UserService.userExists(phoneNumber, facebookId, googleId);
// same code as before snipped...
fab.addActionListener(e -> {
Dialog ipDlg = new InfiniteProgress().showInifiniteBlocking();
if(exists) {
UserService.login(phoneNumber, facebookId, googleId, password.getText(), (value) -> {
MapForm.get().show();
}, (sender, err, errorCode, errorMessage) -> {
ipDlg.dispose();
error.setText("Login error");
error.setVisible(true);
revalidate();
});
} else {
if(UserService.addNewUser(new User().
phone.set(phoneNumber).
facebookId.set(facebookId).
googleId.set(googleId).
password.set(password.getText()).
driver.set(UberClone.isDriverMode()))) {
MapForm.get().show();
} else {
EnterPasswordForm
Before we go to the Google login support lets look at the additional changes we need to get both Facebook and Google working. I already discussed the changes to
EnterPasswordForm so lets start there…
The constructor accepts one of the 3 options the other two should be null in this case
8. public EnterPasswordForm(String phoneNumber, String facebookId, String googleId) {
super(new BorderLayout());
Form previous = getCurrentForm();
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
boolean exists = UserService.userExists(phoneNumber, facebookId, googleId);
// same code as before snipped...
fab.addActionListener(e -> {
Dialog ipDlg = new InfiniteProgress().showInifiniteBlocking();
if(exists) {
UserService.login(phoneNumber, facebookId, googleId, password.getText(), (value) -> {
MapForm.get().show();
}, (sender, err, errorCode, errorMessage) -> {
ipDlg.dispose();
error.setText("Login error");
error.setVisible(true);
revalidate();
});
} else {
if(UserService.addNewUser(new User().
phone.set(phoneNumber).
facebookId.set(facebookId).
googleId.set(googleId).
password.set(password.getText()).
driver.set(UberClone.isDriverMode()))) {
MapForm.get().show();
} else {
EnterPasswordForm
I also updated the UserService method accordingly, I'll get into that shortly. Notice I snipped some code below here to keep the entire block in one page but it’s still
there…
9. public EnterPasswordForm(String phoneNumber, String facebookId, String googleId) {
super(new BorderLayout());
Form previous = getCurrentForm();
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
boolean exists = UserService.userExists(phoneNumber, facebookId, googleId);
// same code as before snipped...
fab.addActionListener(e -> {
Dialog ipDlg = new InfiniteProgress().showInifiniteBlocking();
if(exists) {
UserService.login(phoneNumber, facebookId, googleId, password.getText(), (value) -> {
MapForm.get().show();
}, (sender, err, errorCode, errorMessage) -> {
ipDlg.dispose();
error.setText("Login error");
error.setVisible(true);
revalidate();
});
} else {
if(UserService.addNewUser(new User().
phone.set(phoneNumber).
facebookId.set(facebookId).
googleId.set(googleId).
password.set(password.getText()).
driver.set(UberClone.isDriverMode()))) {
MapForm.get().show();
} else {
EnterPasswordForm
The login method now accepts the Google/Facebook credentials as an optional argument
10. public EnterPasswordForm(String phoneNumber, String facebookId, String googleId) {
super(new BorderLayout());
Form previous = getCurrentForm();
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
boolean exists = UserService.userExists(phoneNumber, facebookId, googleId);
// same code as before snipped...
fab.addActionListener(e -> {
Dialog ipDlg = new InfiniteProgress().showInifiniteBlocking();
if(exists) {
UserService.login(phoneNumber, facebookId, googleId, password.getText(), (value) -> {
MapForm.get().show();
}, (sender, err, errorCode, errorMessage) -> {
ipDlg.dispose();
error.setText("Login error");
error.setVisible(true);
revalidate();
});
} else {
if(UserService.addNewUser(new User().
phone.set(phoneNumber).
facebookId.set(facebookId).
googleId.set(googleId).
password.set(password.getText()).
driver.set(UberClone.isDriverMode()))) {
MapForm.get().show();
} else {
EnterPasswordForm
Two of the three values for identification will be null so we can set all of them and only one will have a value
11. public static boolean userExists(String phoneNumber, String facebookId, String googleId) {
if(phoneNumber != null) {
return userExistsPhone(phoneNumber);
}
if(facebookId != null) {
return userExistsFacebook(facebookId);
}
return userExistsGoogle(googleId);
}
public static boolean userExistsPhone(String phoneNumber) {
return userExistsImpl("user/exists", phoneNumber);
}
public static boolean userExistsFacebook(String phoneNumber) {
return userExistsImpl("user/existsFacebook", phoneNumber);
}
public static boolean userExistsGoogle(String phoneNumber) {
return userExistsImpl("user/existsGoogle", phoneNumber);
}
private static boolean userExistsImpl(String url, String val) {
Response<byte[]> b = Rest.get(SERVER_URL + url).
acceptJson().
queryParam("v", val).getAsBytes();
if(b.getResponseCode() == 200) {
// the t from true
return b.getResponseData()[0] == (byte)'t';
}
return false;
UserService
Next lets see the changes to the UserService class.
This is the main method we use which we broke up for the other types
12. public static boolean userExists(String phoneNumber, String facebookId, String googleId) {
if(phoneNumber != null) {
return userExistsPhone(phoneNumber);
}
if(facebookId != null) {
return userExistsFacebook(facebookId);
}
return userExistsGoogle(googleId);
}
public static boolean userExistsPhone(String phoneNumber) {
return userExistsImpl("user/exists", phoneNumber);
}
public static boolean userExistsFacebook(String phoneNumber) {
return userExistsImpl("user/existsFacebook", phoneNumber);
}
public static boolean userExistsGoogle(String phoneNumber) {
return userExistsImpl("user/existsGoogle", phoneNumber);
}
private static boolean userExistsImpl(String url, String val) {
Response<byte[]> b = Rest.get(SERVER_URL + url).
acceptJson().
queryParam("v", val).getAsBytes();
if(b.getResponseCode() == 200) {
// the t from true
return b.getResponseData()[0] == (byte)'t';
}
return false;
UserService
This generic implementation demonstrates why I chose to change the argument name from phone to v so it can now suite all the permutations of this method
13. return userExistsImpl("user/existsFacebook", phoneNumber);
}
public static boolean userExistsGoogle(String phoneNumber) {
return userExistsImpl("user/existsGoogle", phoneNumber);
}
private static boolean userExistsImpl(String url, String val) {
Response<byte[]> b = Rest.get(SERVER_URL + url).
acceptJson().
queryParam("v", val).getAsBytes();
if(b.getResponseCode() == 200) {
// the t from true
return b.getResponseData()[0] == (byte)'t';
}
return false;
}
public static void login(String phoneNumber, String facebookId, String googleId, String password,
final SuccessCallback<User> onSuccess, final FailureCallback<Object> onError) {
Rest.get(SERVER_URL + "user/login").
acceptJson().
queryParam("password", password).
queryParam("phone", phoneNumber).
queryParam("facebookId", facebookId).
queryParam("googleId", googleId).
getAsJsonMapAsync(new Callback<Response<Map>>() {
// this code was unchanged
});
}
UserService
Login is almost identical to the original code. I added the new values to the mix. If they are null the arguments won't be sent and everything will work as expected.
Once this is done Facebook login should work on the device and simulator.