/* * Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.scvngr.levelup.core.net; import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import com.scvngr.levelup.core.R; import com.scvngr.levelup.core.annotation.LevelUpApi; import com.scvngr.levelup.core.annotation.LevelUpApi.Contract; import com.scvngr.levelup.core.util.BuildUtil; import com.scvngr.levelup.core.util.CoreLibConstants; import com.scvngr.levelup.core.util.CryptographicHashUtil; import com.scvngr.levelup.core.util.CryptographicHashUtil.Algorithms; import com.scvngr.levelup.core.util.DeviceIdentifier; import com.scvngr.levelup.core.util.NullUtils; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * Class with methods to help with creating requests. */ @LevelUpApi(contract = Contract.INTERNAL) public final class RequestUtils { /** * Header key for the accepts. */ @NonNull public static final String HEADER_ACCEPT = "Accept"; /** * Value for the accepts header for JSON. */ @NonNull public static final String HEADER_CONTENT_TYPE_JSON = "application/json"; /** * Header key for the user agent. */ @NonNull public static final String HEADER_USER_AGENT = "User-Agent"; /** * Header key that maps to the model of the current device. * * @see RequestUtils#HEADER_DEVICE_MODEL_VALUE */ @NonNull public static final String HEADER_DEVICE_MODEL_KEY = "X-Device-Model"; /** * Header value representing the model of the current device. * * @see RequestUtils#HEADER_DEVICE_MODEL_KEY */ @NonNull public static final String HEADER_DEVICE_MODEL_VALUE = NullUtils.format( "%s/%s", Build.BRAND, Build.PRODUCT); /** * Parameter for the app's LevelUp API key. */ @NonNull public static final String PARAM_API_KEY = "api_key"; /** * Parameter for the client identifier. This is a deprecated alias for {@link #PARAM_API_KEY} * and will be removed in the next major release of the SDK. */ @NonNull @Deprecated public static final String PARAM_CLIENT_ID = PARAM_API_KEY; /** * Parameter for the device identifier. */ @NonNull public static final String PARAM_DEVICE_IDENTIFIER = "device_identifier"; /** * Get the request headers for all API requests. * * @param context Application context. * @return the headers to add to the request. */ @NonNull public static Map<String, String> getDefaultRequestHeaders(@NonNull final Context context) { final Map<String, String> headers = new HashMap<String, String>(3); headers.put(HEADER_DEVICE_MODEL_KEY, HEADER_DEVICE_MODEL_VALUE); headers.put(HEADER_USER_AGENT, getUserAgent(context)); headers.put(HEADER_ACCEPT, HEADER_CONTENT_TYPE_JSON); return headers; } /** * Returns a {@link String} representation to use as the User-Agent string when communicating * with the server. A sample string looks like: * <p/> * "LevelUp/2.3.12 (Linux; U; Android; 1.0; generic_x86/sd_x86; en-US;) LevelUpSdk/0.0.1". * * @param context Application context. * @return the user agent value. */ @NonNull public static String getUserAgent(@NonNull final Context context) { return NullUtils.format( "%s (Linux; U; Android %s; %s/%s; %s) %s", getUserAgentAppVersionString(context), Build.VERSION.RELEASE, Build.BRAND, Build.PRODUCT, Locale.getDefault().toString(), getUserAgentSdkVersionString(context)); } /** * Get the API key for the context passed. * * @param context the Application context. * @return The API key from resources. */ @NonNull public static String getApiKey(@NonNull final Context context) { final String apiKey = NullUtils.nonNullContract(context.getString(R.string.levelup_api_key)); if (TextUtils.isEmpty(apiKey)) { throw new AssertionError(String.format(Locale.US, "Application must override %s", context.getResources().getResourceEntryName(R.string.levelup_api_key))); } return apiKey; } /** * Gets the deviceId to add to the login/register requests. * * @param context the Application context. * @return the deviceId or null if it couldn't be determined. */ @Nullable public static String getDeviceId(@NonNull final Context context) { final String deviceIdentifier = DeviceIdentifier.getDeviceId(context); final String hashedDeviceIdentifier; if (null != deviceIdentifier) { hashedDeviceIdentifier = CryptographicHashUtil.getHexHash(deviceIdentifier, Algorithms.SHA256); } else { hashedDeviceIdentifier = null; } return hashedDeviceIdentifier; } /** * Add the API key to the request query parameters. * * @param context Application context. * @param params the query parameter {@link Map} to add the API key to. */ public static void addApiKeyToRequestQueryParams(@NonNull final Context context, @NonNull final Map<String, String> params) { params.put(PARAM_API_KEY, getApiKey(context)); } /** * Add the API key to the request body. * * @param context Application context. * @param body the {@link JSONObject} to add the API key to. */ public static void addApiKeyToRequestBody(@NonNull final Context context, @NonNull final JSONObject body) { try { body.put(PARAM_API_KEY, getApiKey(context)); } catch (final JSONException e) { throw new AssertionError(e); } } /** * Add the Device ID to the request body if the Device ID can be determined. The request body is * not modified if the Device ID could not be determined. * * @param context Application context * @param body the {@link JSONObject} to add the Device ID to */ public static void addDeviceIdToRequestBody(@NonNull final Context context, @NonNull final JSONObject body) { try { body.putOpt(PARAM_DEVICE_IDENTIFIER, getDeviceId(context)); } catch (final JSONException e) { throw new AssertionError(e); } } /** * Gets the package name and version of the app for the user agent header. For example, * "com.scvngr.levelup.app/2.3.12". * * @param context the Application Context * @return version of the app. */ @NonNull private static String getUserAgentAppVersionString(@NonNull final Context context) { final PackageInfo info = BuildUtil.getMyPackageInfo(context); return info.applicationInfo.packageName + "/" + info.versionName; } /** * Gets the name and version of the SDK for the user agent header. For example, * "LevelUpSdk/0.1". * * @param context the Application Context * @return version of the SDK. */ @NonNull private static String getUserAgentSdkVersionString(@NonNull final Context context) { return NullUtils.format("LevelUpSdk/%s", CoreLibConstants.SDK_VERSION); } /** * Private constructor prevents instantiation. * * @throws UnsupportedOperationException because this class cannot be instantiated. */ private RequestUtils() { throw new UnsupportedOperationException("This class is non-instantiable"); } }