/* * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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.amazonaws.mobileconnectors.util; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import com.amazonaws.AmazonClientException; import com.amazonaws.util.Base64; import com.amazonaws.util.StringUtils; import com.amazonaws.logging.Log; import com.amazonaws.logging.LogFactory; import org.json.JSONException; import org.json.JSONObject; import java.util.Locale; import java.util.Map; import java.util.UUID; /** * A class that consists of app info, device info, additional service info, and * user defined data. * *
* {@code
* ClientContext clientContext = new ClientContext(activity);
*
* Map map = new HashMap();
* map.put("first_name", "John");
* map.put("last_name", "Doe");
* clientContext.putCustomContext(map);
*
* clientContext.putServiceContext("mobile_analytics", serviceContext);
*
* String base64 = clientContext.toBase64String();
* }
*
*/
public class ClientContext {
private static final Log LOGGER = LogFactory.getLog(ClientContext.class);
/**
* Name of the shared preferences where client id is saved.
*/
static final String SHARED_PREFERENCES = "com.amazonaws.common";
private final JSONObject json;
private String base64String;
/**
* Constructs a new client context.
*
* @param context context of the app
*/
public ClientContext(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context can't be null");
}
json = new JSONObject();
try {
json.put("client", getClientInfo(context))
.put("env", getDeviceInfo(context));
} catch (final JSONException e) {
throw new AmazonClientException("Failed to build client context", e);
}
}
/**
* Gets the installation id from shared preferences. A new one will be
* assigned if not found. The installation id is unique per app
* installation. This value appears as installation_id in client context
* object in AWS Lambda.
*
* @param context context of the app
* @return the unique installation id per app installation
* @see The
* Context Object (Node.js)
*/
public static String getInstallationId(Context context) {
final SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES,
Context.MODE_PRIVATE);
String installationId = sp.getString("installation_id", null);
if (installationId == null) {
installationId = UUID.randomUUID().toString();
sp.edit().putString("installation_id", installationId).commit();
}
return installationId;
}
/**
* Gets the client info, including installation_id_id, app_title,
* app_version_name, app_version_code, and app_package_name.
*
* @param context context of the app
* @return an JSONObject that has the client info
* @throws JSONException
*/
static JSONObject getClientInfo(Context context) throws JSONException {
final JSONObject client = new JSONObject();
final PackageManager packageManager = context.getPackageManager();
try {
final PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
final ApplicationInfo applicationInfo = context.getApplicationInfo();
client.put("installation_id", getInstallationId(context))
.put("app_version_name", packageInfo.versionName)
.put("app_version_code", String.valueOf(packageInfo.versionCode))
.put("app_package_name", packageInfo.packageName);
// If null is returned for some reason, fall back to "Unknown"
final CharSequence title = packageManager.getApplicationLabel(applicationInfo);
client.put("app_title", title == null ? "Unknown" : title.toString());
} catch (final NameNotFoundException e) {
// When device starts, PackageManager will gather package
// information by scanning them. It will take a while to finish.
// This exception may be thrown when scan doesn't finish.
LOGGER.warn("Failed to load package info: " + context.getPackageName(), e);
}
return client;
}
/**
* Gets the device info, including platform, model, make, platform_version,
* and locale.
*
* @param context context of the app
* @return an JSONObject that has the device info
* @throws JSONException
*/
static JSONObject getDeviceInfo(Context context) throws JSONException {
final JSONObject env = new JSONObject()
.put("platform", "Android")
.put("model", Build.MODEL)
.put("make", Build.MANUFACTURER)
.put("platform_version", Build.VERSION.RELEASE)
.put("locale", Locale.getDefault().toString());
return env;
}
/**
* Adds additional user defined key-value pairs to the client context under
* "custom". This method is not thread safe.
*
*
* {@code
* Map map = new HashMap();
* map.put("first_name", "John");
* map.put("last_name", "Doe");
* clientContext.putCustomContext(map);
* }
*
*
* The above code will add a Json object under "custom" as following.
*
* * { * "custom": { * "first_name":"John", * "last_name":"Doe" * } * } ** * @param map the custom key-value context map */ public void putCustomContext(Map
* { * "services": { * "mobile_analytics": { * "app_id":"mobile_analytics_app_id" * } * } * } ** * @param service service name * @param map the service key-value context map */ public void putServiceContext(String service, Map