package com.hokolinks.model; import android.content.Context; import android.content.Intent; import android.os.Bundle; import com.hokolinks.utils.log.HokoLog; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; /** * Route gather information from annotated activity classes, mapping the route format, * the route and query parameters to a given class. Also provides methods to create an intent for * that particular class with the given parameters and a URL instance. Also provides validation * to routes, in order to guarantee all necessary parameters can be mapped. */ public class IntentRouteImpl extends Route { // Keys for the Intent.putExtras(...) public static final String BUNDLE_KEY = "HokoRoute"; public static final String ROUTE_PARAMETERS_BUNDLE_KEY = "HokoRouteParameters"; public static final String QUERY_PARAMETERS_BUNDLE_KEY = "HokoQueryParameters"; public static final String METADATA_KEY = "HokoMetadata"; private Context mContext; private String mActivityClassName; private HashMap<String, Field> mRouteParameters; private HashMap<String, Field> mQueryParameters; /** * The constructor for Route objects. * * @param route A route in route format. * @param activityClassName The activity's class name. * @param routeParameters A HashMap where the keys are route components and the values are * Fields. * @param queryParameters A HashMap where the keys are query components and the values are * Fields. * @param context A context to be able to generate the JSON, and the intent. */ public IntentRouteImpl(String route, String activityClassName, HashMap<String, Field> routeParameters, HashMap<String, Field> queryParameters, Context context) { super(route); mActivityClassName = activityClassName; mRouteParameters = routeParameters; mQueryParameters = queryParameters; mContext = context; } public String getActivityClassName() { return mActivityClassName; } public HashMap<String, Field> getRouteParameters() { return mRouteParameters; } public HashMap<String, Field> getQueryParameters() { return mQueryParameters; } /** * Retrieves the actual class out of the activity's class name. * * @return A class object or null. */ private Class getActivityClass() { try { return Class.forName(mActivityClassName); } catch (ClassNotFoundException e) { HokoLog.e(e); } return null; } /** * Generates an Intent out of mapping URL information with the Route object. * The intent has 2 bundles, a route parameters bundle which contains a * HashMap<String, String> of key value pairs and a query parameters bundle which also * contains a HashMap<String, String> of key value pairs. The function also sets a few * flags for better deeplinking experience. * * @param deeplink A Deeplink instance. * @return The generated intent. */ private Intent getIntent(Deeplink deeplink) { Class<?> klass = getActivityClass(); if (klass == null) return null; Intent intent = new Intent(mContext, klass); Bundle mainBundle = new Bundle(); mainBundle.putString(BUNDLE_KEY, this.getRoute()); // Route Params Bundle routeParametersBundle = new Bundle(); HashMap<String, String> routeParameters = deeplink.getRouteParameters(); if (routeParameters != null) { for (String key : routeParameters.keySet()) { String value = routeParameters.get(key); routeParametersBundle.putString(key, value); } } mainBundle.putBundle(ROUTE_PARAMETERS_BUNDLE_KEY, routeParametersBundle); // Query Params Bundle queryParametersBundle = new Bundle(); HashMap<String, String> queryParameters = deeplink.getQueryParameters(); for (String key : queryParameters.keySet()) { String value = queryParameters.get(key); queryParametersBundle.putString(key, value); } mainBundle.putBundle(QUERY_PARAMETERS_BUNDLE_KEY, queryParametersBundle); if (deeplink.getMetadata() != null) { mainBundle.putString(METADATA_KEY, deeplink.getMetadata().toString()); } intent.putExtras(mainBundle); // Flags for Deeplinking intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); return intent; } @Override public void execute(Deeplink deeplink) { openIntent(getIntent(deeplink)); } /** * Utility function to start an activity with a given intent. * * @param intent The intent to start the activity. */ private void openIntent(Intent intent) { if (intent != null) mContext.startActivity(intent); } /** * Checks if an instance of Route is actually valid when it comes to mapping route * components to the route parameters available. * * @return true if it's valid, false otherwise. */ public boolean isValid() { List<String> routeComponents = getComponents(); for (String routeComponent : routeComponents) { if (routeComponent.startsWith(":")) { routeComponent = routeComponent.substring(1); if (!getRouteParameters().containsKey(routeComponent)) return false; } } return true; } }