Going deeper with location

Steps
1. specify using Google Services
2. Access fine location

To have connection callbacks
– implements ConnectionCallbacks, OnConnectionFailedListener

@Override
public void onConnected(Bundle bundle){
	super.onStart();
	mGoogleApiClient.connect();
}
@Override
protected void onStop(){
	super.onStop();
	if(mGoogleApiClient.isConnected()) {
		mGoogleApiClient.disconnected();
	}
}
@Override
protected void onConnected(Bundle connectionHint){
	mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
	if(mLastLocation!=null){
	 mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
	 mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
	}
}

Setting up
-create App
-edit the Layout
-Add String.xml
-Update Build.gradle and AnxdroidManifest.xml

Different Priority Values

setInterval(period);
mil second

PRIORITY_BALANCED_POWER_ACCURACY
PRIORITY_HIGH_ACCURACY
PRIORUTY_LOW_POWER
PRIORITY_NO_POWER

steps to use Location Services
1. create a GoogleApiClient
that uses the Location Services API
2. Extend activity with the GoogleApiClientConnectionCallbacks
callbacks
3. Extend activity with the GoogleApiClient.OnConnectionFailedListener
Listener in case the connection fails
4. Extend activity with the LocationListener
listener for lacation updates
5. After connecting the GoogleApiClient
wait for the onConnected
callback
6. In this callback, set up onLocationChanged
callback, and in this can capture location information

Getting Started with Location

Location Provider
– Fused Location Provider: GPS, Satellites, Cellular Connection, WiFi Network
– Activity Recognition:

Google Api Client
Location Services: GoogleApiClientConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener

OnConnected
OnLocationChanged

asynchronous programming

Fine and Coarse Location
Fine Location: GPS Cell and WiFi
Coarse Location: Cell and WiFi

in order to use the Google API Client
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener

@Override
protected void onStart()
	super.onStart();
	// Connect the Client
	mGoogleApiClient.connect();

@Override
protected void onStop()
	// Disconnect the Client
	mGoogleApiClient.disconnect();
	super.onStop();

Starting App

build.gradle
compile ‘com.google.android.gms:play-service:7+’

AndroidManifest.xml

<meta-data android:name="com.google.android.gms.version"
	android:value="@integer/google_play_services_version" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Asynchronous Programming Model
OnCreate, OnStart
Location Services
OnConnectionFailed, OnConnectionSuspended, OnConnected, OnLocationChanged

Asynchronous programming steps
1. create a GoogleApiClient that uses desired API
2. Extend activity with the ConnectionCallbacks
3. Extend activity with the OnConnectionFailedListener in case the connection fails
4. After connecting the GoogleApiClient wait for the onConnected callback
5. Follow the requirements of specific API

GCD Threads

Grand Central Dispatch makes asynchronous programming easier and safer by hiding threads from developer.

Types of Queues
sync, async

Main Queue

dispatch_get_global_queue()
dispatch_async()

let q = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)

dispatch_async(q) { () -> Void in
	print("tic")
}
print("tac")

will it crash?

let downloadQueue = dispatch_queue_create("download", nil)

dispatch_async(downloadQueue)() -> Void in
	let imgData = NSData(contentsOfURL:url!)

	let image = UIImage(data:imgData!)

	self.photoView.image = image
@IBAction func synchronousDownload(_ sender: UIBarButtonItem){
	let url = URL(string: BigImages.seaLion.rawValue)
	let imgData = try? Data(contentsOf: url!)
	let image = UIImage(data: imgData!)

	photoView.image = image
}

parameters.putString

new GraphRequest(
	AccessToken.getCurrentAccessToken(),
	"/me",
	parameters,
	HttpMethod.GET,
	new GraphRequest.Callback(){
		@Override
		public void onCompleted(GraphResponse response){
			if (response.getError() != null){
				Toast.makeText(AccountActivity.this, response.getError().getErrorMessage(), Toast.LENGTH_LONG).show();
				return;
			}

			JSONObject jsonResponse = response.getJSONObject();
			try {
				String locationStr = jsonResponse.getString("location");
				location.setText(locationStr);
			} catch (JSONException e){
				e.printStackTrace();
			}
		}
	}
).executeAsync();
{
	"location": {
		"id": "107413405955233",
		"name": "Huntington Beach, California"
	},
	"id": "128607281023401"
}
Bundle parameters = new Bundle();
parameters.putString("message", "Access Denied");
new GraphRequest(
	AccessToken.getCurrentAccessToken(),
	"/me/feed",
	parameters,
	HttpMethod.POST,
	new GraphRequest.Callback(){
		@Override
		public void onCompleted(GraphResponse response){
			if (response.getError() != null){
				Toast.makeText(MainActivity.this, response.getError().getErrorMessage(), Toast.LENGTH_LONG).show();
				return;
			}
		}
	}
).executeAsync();

Testing account kit

Making a test plan for account kit
common flows:
1. User logs in with phone number
2. User logs in with email

How can the Graph API make app better?
-increased personalization
-more opportunities for social interaction

Better personalization and more opportunities for social interaction can lead to improvements in:
-Engagement
-Retention

Facebook Graph API
https://developers.facebook.com/docs/graph-api?locale=ja_JP

if (accessToken != null &&
accessToken.getPermissions().contains("user_friends")){
	// make the API call to fetch friends list
	Bundle parameters = new Bundle();
	parameters.putString("fields", "picture");
	new GraphRequest(
	AccessToken.getCurrentAccessToken(), "/me/friends",HttpMethod.GET,...);
}.executeAsync();

Logout

Implementing the logout button manually

public void onLogout(View view){
	AccountKit.logOut();
	LoginManager.getInstance().logOut();
	launchLoginActivity();
}

How to Test: Making a Test Plan
unexpected conditions:
1.A new user declines to authenticate permissions once, then tries to log in again
2.A returning user who has changed their password
3.A returning user with an expired token
4.A returning user who logs in after disabling the Facebook platform

Account kit
Common Flows:
1. A user logs in with a phone number
2. A user logs in with an email address

Unexpected conditions:
1. A user tries to log in, but does not receive the SMS
2. A user types in the wrong code

Custom Tab Activity

<activity
	android:name="com.facebook.CustomTabActivity"
	android:exported="true">
	<intent-filter>
		<action android:name="android.intent.action.VIEW" />
		<category android:name="android.intent.category.DEFAULT" />
		<category android:name="android.intent.category.BROWSABLE" />
		<data android:scheme="@string/fb_login_protocol_scheme" />
	</intent-filter>
</activity>
@Override
protected void onActivityResult(final int requestCode,
final int resultCode, final Intent data){
	super.onActivityResult(requestCode, resultCode, data);

	callbackManager.onActivityResult(requestCode, resultCode, data);
	...
}
if (AccessToken.getCurrentAccessToken() != null){
	...
}
else{
	AccountKit.getCurrentAccount(new AccountKitCallback<Account>(){
		...
	})
}

if (AccessToken.getCurrentAccessToken() != null){
	Profile profile = Profile.getCurrentProfile();
}

if (AccessToken.getCurrentAccessToken() != null){
	Profile currentProfile = Profile.getCurrentProfile();
	if (currentProfile != null){
		displayProfileInfo(currentProfile);
	} else {
		Profile.fetchProfileForCurrentAccessToken();
	}
}

AuthCode

AccountKitConfiguration.AccountKitConfigurationBuilder configurationBuilder = new AccountKitConfiguration.AccountKitConfigurationBuilder(
	loginType,
	AccountKitActivity.ResponseType.CODE
);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
	super.onActivityResult(requestCode, resultCode, data);
		AccountKitLoginResult loginResult = data.getParcelableExtra(
			AccountKitLoginResult.RESULT_KEY);
		String toastMessage;
		if(loginResult.getError() != null){
			toastMessage = loginResult.getError().getErrorType().getMessage();
			showErrorActivity(loginResult.getError());
		else if (loginResult.wasCancelled());
			toastMessage = "Login Canceled";
		} else {
			String authCode = loginResult.getAuthorizationCode();
			startActivity(new Intent(this, AuthorizedActivity.class));
		}

}
{
	"id" : <account_kit_user_id>,
		"access_token" : <account_access_token>,
		"token_refresh_interval_sec" : <refresh_interval>
}

GET https://graph.accountkint.com/v1.v1/me/?access_token=

{
	"id":"12345"
	"phone":{
		"number":"+15551234567"
		"country_prefix":"1",
			"national_number":"5551234567"
	}
}
public void getAccountInfo(AccountInfo accountInfo){
	String accountKitId = accountInfo.getId();
	String phoneNumber = accountInfo.getPhone().getNumber();

	String email = accountInfo.getEmail();
}
AppEventsLogger logger = AppEventsLogger.newLogger(this)

public void onLoginSMS(final View view){
	logger.logEvent("onSMSLogin");
	onLogin(LoginType.PHONE);
}

public void onLoginEmail(final View view){
	logger.logEvent("onEmailLogin");
	onLogin(LoginType.EMAIL);
}