/*
* Copyright (c) 2016 Uber Technologies, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.uber.sdk.android.rides;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.uber.sdk.android.core.Deeplink;
import com.uber.sdk.android.core.UberSdk;
import com.uber.sdk.android.core.install.SignupDeeplink;
import com.uber.sdk.android.core.utils.AppProtocol;
import com.uber.sdk.android.core.utils.PackageManagers;
import com.uber.sdk.rides.client.SessionConfiguration;
import static com.uber.sdk.android.core.utils.Preconditions.checkNotNull;
/**
* A deeplink for requesting rides in the Uber application.
*
* @see <a href="https://developer.uber.com/v1/deep-linking/">Uber deeplink documentation</a>
*/
public class RequestDeeplink implements Deeplink {
private static final String USER_AGENT_DEEPLINK = "rides-android-v0.6.1-deeplink";
@NonNull
private final Uri uri;
@NonNull
private final Context context;
private RequestDeeplink(@NonNull Context context, @NonNull Uri uri) {
this.uri = uri;
this.context = context;
}
/**
* Executes the deeplink to launch the Uber app. If the app is not installed redirects to the play store.
*/
public void execute() {
if (isSupported()) {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
context.startActivity(intent);
} else {
Log.i(UberSdk.UBER_SDK_LOG_TAG, "Uber app not installed, redirecting to mobile sign up.");
final String clientId = uri.getQueryParameter(Builder.CLIENT_ID);
final String userAgent = uri.getQueryParameter(Builder.USER_AGENT);
new SignupDeeplink(context, clientId, userAgent)
.execute();
}
}
@Override
public boolean isSupported() {
for (String packageName : AppProtocol.UBER_PACKAGE_NAMES) {
if(PackageManagers.isPackageAvailable(context, packageName)) {
return true;
}
}
return false;
}
/**
* @return The {@link Uri} for the deeplink.
*/
@NonNull
public Uri getUri() {
return uri;
}
/**
* Builder for {@link RequestDeeplink} objects.
*/
public static class Builder {
public static final String ACTION = "action";
public static final String SET_PICKUP = "setPickup";
public static final String CLIENT_ID = "client_id";
public static final String PRODUCT_ID = "product_id";
public static final String MY_LOCATION = "my_location";
public static final String LATITUDE = "[latitude]";
public static final String LONGITUDE = "[longitude]";
public static final String NICKNAME = "[nickname]";
public static final String FORMATTED_ADDRESS = "[formatted_address]";
public static final String USER_AGENT = "user-agent";
private RideParameters rideParameters;
private SessionConfiguration sessionConfiguration;
private final Context context;
/**
* @param context to execute the deeplink.
*/
public Builder(Context context) {
this.context = context;
}
/**
* Sets the {@link RideParameters} for the deeplink.
*
* @return this instance of {@link Builder}
*/
public RequestDeeplink.Builder setRideParameters(@NonNull RideParameters rideParameters) {
this.rideParameters = rideParameters;
return this;
}
/**
* Sets the client Id
*
* @return this instance of {@link Builder}
*/
public RequestDeeplink.Builder setSessionConfiguration(@NonNull SessionConfiguration loginConfiguration) {
sessionConfiguration = loginConfiguration;
return this;
}
/**
* Builds an {@link RequestDeeplink} object.
*
* @return {@link RequestDeeplink} generated from parameters
*/
@NonNull
public RequestDeeplink build() {
checkNotNull(rideParameters, "Must supply ride parameters.");
checkNotNull(sessionConfiguration, "Must supply a Login Configuration");
checkNotNull(sessionConfiguration.getClientId(), "Must supply client Id on Login Configuration");
Uri.Builder builder = new Uri.Builder();
builder.scheme(AppProtocol.DEEPLINK_SCHEME);
builder.appendQueryParameter(ACTION, SET_PICKUP);
builder.appendQueryParameter(CLIENT_ID, sessionConfiguration.getClientId());
if (rideParameters.getProductId() != null) {
builder.appendQueryParameter(PRODUCT_ID, rideParameters.getProductId());
}
if (rideParameters.getPickupLatitude() != null && rideParameters.getPickupLongitude() != null) {
addLocation(LocationType.PICKUP, Double.toString(rideParameters.getPickupLatitude()),
Double.toString(rideParameters.getPickupLongitude()), rideParameters.getPickupNickname(),
rideParameters.getPickupAddress(), builder);
}
if (rideParameters.isPickupMyLocation()) {
builder.appendQueryParameter(LocationType.PICKUP.getUriQueryKey(), MY_LOCATION);
}
if (rideParameters.getDropoffLatitude() != null && rideParameters.getDropoffLongitude() != null) {
addLocation(LocationType.DROPOFF, Double.toString(rideParameters.getDropoffLatitude()),
Double.toString(rideParameters.getDropoffLongitude()), rideParameters.getDropoffNickname(),
rideParameters.getDropoffAddress(), builder);
}
String userAgent = rideParameters.getUserAgent();
if (userAgent == null) {
userAgent = USER_AGENT_DEEPLINK;
}
builder.appendQueryParameter(USER_AGENT, userAgent);
return new RequestDeeplink(context, builder.build());
}
private void addLocation(
@NonNull LocationType locationType, @NonNull String latitude,
@NonNull String longitude, @Nullable String nickname, @Nullable String address, Uri.Builder builder) {
String typeQueryKey = locationType.getUriQueryKey();
builder.appendQueryParameter(typeQueryKey + LATITUDE, latitude);
builder.appendQueryParameter(typeQueryKey + LONGITUDE, longitude);
if (nickname != null) {
builder.appendQueryParameter(typeQueryKey + NICKNAME, nickname);
}
if (address != null) {
builder.appendQueryParameter(typeQueryKey + FORMATTED_ADDRESS, address);
}
}
}
private enum LocationType {
PICKUP,
DROPOFF;
private String getUriQueryKey() {
return name().toLowerCase();
}
}
}