package com.aptoide.amethyst.utils; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.os.Build; import android.util.Log; import android.view.Gravity; import android.view.WindowManager; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.aptoide.amethyst.AppViewActivity; import com.aptoide.amethyst.Aptoide; import com.aptoide.amethyst.data_provider.getAds.GetAdsRequestListener; import com.aptoide.amethyst.database.AptoideDatabase; import com.aptoide.amethyst.webservices.RegisterAdRefererRequest; import com.aptoide.amethyst.webservices.json.GetApkInfoJson; import com.aptoide.amethyst.webservices.v2.GetAdsRequest; import com.aptoide.models.ApkSuggestionJson; import com.crashlytics.android.Crashlytics; import com.google.android.gms.common.GooglePlayServicesNotAvailableException; import com.google.android.gms.common.GooglePlayServicesRepairableException; import com.octo.android.robospice.SpiceManager; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import java.io.IOException; import java.net.URI; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * Created by neuro on 08-10-2015. */ public class ReferrerUtils { public static final int RETRIES = 2; public static final int TIME_OUT = 5; public static final ReferrersMap excludedCampaings = new ReferrersMap(); private static final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); public static void extractReferrer(final ApkSuggestionJson.Ads ads, final SpiceManager spiceManager) { extractReferrer(ads, spiceManager, null); } public static void extractReferrer(final ApkSuggestionJson.Ads ads, final SpiceManager spiceManager, final SimpleFuture<String> simpleFuture) { extractReferrer(ads, spiceManager, simpleFuture, RETRIES); } public static void extractReferrer(ApkSuggestionJson.Ads ads, final SpiceManager spiceManager, final SimpleFuture<String> simpleFuture, final int retries) { // Just in case try { final String packageName = ads.getData().getPackageName(); final long appId = ads.getData().getId().longValue(); final long adId = ads.getInfo().getAd_id(); final long networkId = ads.getPartner().getPartnerInfo().getId().longValue(); final String click_url = ads.getPartner().getPartnerData().getClick_url(); extractReferrer(packageName, appId, adId, networkId, click_url, spiceManager, simpleFuture, retries); } catch (Exception e) { e.printStackTrace(); } } public static void extractReferrer(final String packageName, final long appId, final long adId, final long networkId, final String click_url, final SpiceManager spiceManager, final SimpleFuture<String> simpleFuture, final int retries) { if (!AptoideUtils.UI.isUiThread()) { throw new RuntimeException("ExtractReferrer must be run on UI thread!"); } final Context context = Aptoide.getContext(); try { Logger.d("ExtractReferrer", "Called for: " + click_url + " with packageName " + packageName); final String[] internalClickUrl = {click_url}; final SimpleFuture<String> clickUrlFuture = new SimpleFuture<>(); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams params; params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams .TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 0; params.width = 0; params.height = 0; LinearLayout view = new LinearLayout(context); view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); AptoideExecutors.getCachedThreadPool().execute(new Runnable() { @Override public void run() { try { internalClickUrl[0] = AptoideUtils.AdNetworks.parseString(context, click_url); clickUrlFuture.set(internalClickUrl[0]); Logger.d("ExtractReferrer", "Parsed click_url: " + internalClickUrl[0]); } catch (IOException | GooglePlayServicesNotAvailableException | GooglePlayServicesRepairableException e) { e.printStackTrace(); } } }); clickUrlFuture.get(); WebView wv = new WebView(context); wv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); view.addView(wv); wv.getSettings().setJavaScriptEnabled(true); wv.setWebViewClient(new WebViewClient() { Future<Void> future; @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); if (future == null) { future = postponeReferrerExtraction(TIME_OUT, retries); } } @Override public boolean shouldOverrideUrlLoading(WebView view, String clickUrl) { if (clickUrl.startsWith("market://") || clickUrl.startsWith("https://play.google.com") || clickUrl.startsWith("http://play.google.com")) { Logger.d("ExtractReferrer", "Clickurl landed on market"); final String referrer = getReferrer(clickUrl); if (simpleFuture != null) { simpleFuture.set(referrer); } Logger.d("ExtractReferrer", "Referrer successfully extracted"); new AptoideDatabase(Aptoide.getDb()).setReferrerToRollbackAction(packageName, referrer); future.cancel(false); postponeReferrerExtraction(0, true); return true; } return false; } private ScheduledFuture<Void> postponeReferrerExtraction(int delta, int retries) { return postponeReferrerExtraction(delta, false, retries); } private ScheduledFuture<Void> postponeReferrerExtraction(int delta, boolean success) { return postponeReferrerExtraction(delta, success, 0); } private ScheduledFuture<Void> postponeReferrerExtraction(int delta, final boolean success, final int retries) { Logger.d("ExtractReferrer", "Referrer postponed " + delta + " seconds."); Callable<Void> callable = new Callable<Void>() { @Override public Void call() throws Exception { Logger.d("ExtractReferrer", "Sending RegisterAdRefererRequest with value " + success); if (!spiceManager.isStarted()) { spiceManager.start(Aptoide.getContext()); } // Por ora fica desactivado pois pode induzir em falsos negativos. spiceManager.execute(new RegisterAdRefererRequest(adId, appId, internalClickUrl[0], success), RegisterAdRefererRequest.newDefaultResponse()); Log.d("ExtractReferrer", "Retries left: " + retries); if (!success) { excludedCampaings.add(packageName, networkId); try { if (retries > 0) { spiceManager.execute(GetAdsRequest.newDefaultRequest("secondtry", packageName), GetAdsRequestListener.withBroadcast(context, packageName, spiceManager, new SimpleFuture<String>(), retries - 1)); } else { // A lista de excluded networks deve ser limpa a cada "ronda" excludedCampaings.remove(packageName); } } catch (Exception e) { e.printStackTrace(); } } else { // A lista de excluded networks deve ser limpa a cada "ronda" excludedCampaings.remove(packageName); } return null; } }; return executorService.schedule(callable, delta, TimeUnit.SECONDS); } }); wv.loadUrl(internalClickUrl[0]); windowManager.addView(view, params); } catch (Exception e) { Crashlytics.logException(e); } } public static String getReferrer(String uri) { List<NameValuePair> params = URLEncodedUtils.parse(URI.create(uri), "UTF-8"); String referrer = null; for (NameValuePair param : params) { if (param.getName().equals("referrer")) { referrer = param.getValue(); } } return referrer; } public static void broadcastReferrer(Context context, String packageName, String referrer) { Intent i = new Intent("com.android.vending.INSTALL_REFERRER"); i.setPackage(packageName); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { i.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); } i.putExtra("referrer", referrer); context.sendBroadcast(i); Logger.d("InstalledBroadcastReceiver", "Sent broadcast to " + packageName + " with referrer " + referrer); } }