1 package io.keybase.ossifrage;
2 
3 import android.content.Context;
4 import android.os.RemoteException;
5 import android.os.SystemClock;
6 import android.util.Log;
7 
8 import java.util.concurrent.Executor;
9 import java.util.concurrent.Executors;
10 
11 import com.android.installreferrer.api.InstallReferrerClient;
12 import com.android.installreferrer.api.InstallReferrerStateListener;
13 import com.android.installreferrer.api.ReferrerDetails;
14 
15 import io.keybase.ossifrage.modules.NativeLogger;
16 import keybase.StringReceiver;
17 
18 public class KBInstallReferrerListener implements keybase.NativeInstallReferrerListener, InstallReferrerStateListener {
19 
20   private InstallReferrerClient mReferrerClient;
21   private keybase.StringReceiver callback;
22   private Context context;
23   private int retries;
24   private Executor executor;
25 
26   private static final int max_retries = 5;
27 
KBInstallReferrerListener(Context _context)28   KBInstallReferrerListener(Context _context) {
29     Log.d("KBIR", "KBInstallReferrerListener created");
30     context = _context;
31     executor = Executors.newSingleThreadExecutor();
32     retries = 0;
33   }
34 
35   // should only be called once per object
36   @Override
startInstallReferrerListener(StringReceiver cb)37   public void startInstallReferrerListener(StringReceiver cb) {
38     Log.e("KBIR", "KBInstallReferrerListener started");
39 
40     mReferrerClient = InstallReferrerClient.newBuilder(this.context).build();
41     mReferrerClient.startConnection(this);
42     callback = cb;
43   }
44 
45   @Override
onInstallReferrerSetupFinished(int responseCode)46   public void onInstallReferrerSetupFinished(int responseCode) {
47     Log.e("KBIR", "KBInstallReferrerListener#onInstallReferrerSetupFinished: got code " + responseCode);
48     executor.execute(new Runnable() {
49       @Override
50       public void run() {
51         switch (responseCode) {
52           case InstallReferrerClient.InstallReferrerResponse.OK:
53             // Connection established
54             handleReferrerResponseOK();
55             return;
56           case InstallReferrerClient.InstallReferrerResponse.SERVICE_DISCONNECTED:
57             reconnect();
58             return;
59           case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
60           case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
61           case InstallReferrerClient.InstallReferrerResponse.DEVELOPER_ERROR:
62           default:
63             // other issues, can't do much here....
64             callback.callbackWithString("");
65         }
66       }
67     });
68   }
69 
handleReferrerResponseOK()70   private void handleReferrerResponseOK() {
71     try {
72       ReferrerDetails response = mReferrerClient.getInstallReferrer();
73       String referrerData = response.getInstallReferrer();
74       callback.callbackWithString(referrerData);
75     } catch (RemoteException e) {
76       Log.e("KBIR", "KBInstallReferrerListener#handleReferrerResponseOK got exception: " + e.toString());
77       e.printStackTrace();
78       callback.callbackWithString("");
79     }
80     mReferrerClient.endConnection();
81   }
82 
83   // tries to reconnect up to max_retries times in case of errors
reconnect()84   private void reconnect() {
85     if (retries >= max_retries) {
86       Log.e("KBIR", "KBInstallReferrerListener max reconnection attempts exceeded");
87       callback.callbackWithString("");
88       mReferrerClient.endConnection();
89       return;
90     }
91 
92     retries++;
93     // sleep for a bit, hopefully when we wake up the play store
94     // connection will be available.
95     SystemClock.sleep(retries * 1000);
96     Log.e("KBIR", "KBInstallReferrerListener reconnecting...");
97     mReferrerClient.startConnection(this);
98   }
99 
100   @Override
onInstallReferrerServiceDisconnected()101   public void onInstallReferrerServiceDisconnected() {
102     Log.e("KBIR", "KBInstallReferrerListener#onInstallReferrerServiceDisconnected: attempting restart...");
103     executor.execute(new Runnable() {
104       @Override
105       public void run() {
106         reconnect();
107       }
108     });
109   }
110 }