1143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandepackage com.android.server.wifi; 2143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 3143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.content.BroadcastReceiver; 4143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.content.Context; 5143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.content.Intent; 6143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.content.IntentFilter; 7143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.net.wifi.RttManager; 8143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.net.wifi.WifiManager; 902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpandeimport android.os.Bundle; 10143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.Handler; 11143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.HandlerThread; 12143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.Looper; 13143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.Message; 14143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.Messenger; 1502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpandeimport android.os.Parcel; 16143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.os.RemoteException; 17143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.util.Log; 18143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.net.wifi.IRttManager; 19143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport android.util.Slog; 20143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 21143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport com.android.internal.util.AsyncChannel; 22143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport com.android.internal.util.Protocol; 23143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport com.android.internal.util.StateMachine; 24143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport com.android.internal.util.State; 25143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport com.android.server.SystemService; 26143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 27143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport java.util.HashMap; 2802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpandeimport java.util.Iterator; 29143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport java.util.LinkedList; 30143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeimport java.util.Queue; 31143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 32143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpandeclass RttService extends SystemService { 33143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 3402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande public static final boolean DBG = true; 35143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 36143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande class RttServiceImpl extends IRttManager.Stub { 37143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 38143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 39143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public Messenger getMessenger() { 40143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return new Messenger(mClientHandler); 41143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 42143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 43143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private class ClientHandler extends Handler { 44143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 45143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientHandler(android.os.Looper looper) { 46143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande super(looper); 47143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 48143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 49143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 50143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void handleMessage(Message msg) { 51143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 52143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (DBG) Log.d(TAG, "ClientHandler got" + msg); 53143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 54143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande switch (msg.what) { 55143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 56143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 57143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 58143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande AsyncChannel c = (AsyncChannel) msg.obj; 59143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (DBG) Slog.d(TAG, "New client listening to asynchronous messages: " + 60143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande msg.replyTo); 61143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientInfo cInfo = new ClientInfo(c, msg.replyTo); 62143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mClients.put(msg.replyTo, cInfo); 63143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else { 64143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 65143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 66143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return; 67143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 68143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 69143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Slog.e(TAG, "Send failed, client connection lost"); 70143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else { 71143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 72143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 73143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (DBG) Slog.d(TAG, "closing client " + msg.replyTo); 74143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientInfo ci = mClients.remove(msg.replyTo); 75f392c0185c2bea228f89fd42fa4551fa19797e7aVinit Deshpande if (ci != null) ci.cleanup(); 76143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return; 77143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 78143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande AsyncChannel ac = new AsyncChannel(); 79143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ac.connect(mContext, this, msg.replyTo); 80143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return; 81143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 82143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 83143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientInfo ci = mClients.get(msg.replyTo); 84143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (ci == null) { 85143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Slog.e(TAG, "Could not find client info for message " + msg.replyTo); 86143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande replyFailed(msg, RttManager.REASON_INVALID_LISTENER, "Could not find listener"); 87143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return; 88143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 89143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 90143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande int validCommands[] = { 91143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttManager.CMD_OP_START_RANGING, 92143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttManager.CMD_OP_STOP_RANGING 93143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande }; 94143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 95143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande for(int cmd : validCommands) { 96143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (cmd == msg.what) { 97143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine.sendMessage(Message.obtain(msg)); 98143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return; 99143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 100143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 101143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 102143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande replyFailed(msg, RttManager.REASON_INVALID_REQUEST, "Invalid request"); 103143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 104143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 105143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 106143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private Context mContext; 107143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private RttStateMachine mStateMachine; 108143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private ClientHandler mClientHandler; 109143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 110143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttServiceImpl() { } 111143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 112143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttServiceImpl(Context context) { 113143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mContext = context; 114143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 115143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 116143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void startService(Context context) { 117143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mContext = context; 118143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 119143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande HandlerThread thread = new HandlerThread("WifiRttService"); 120143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande thread.start(); 121143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 122143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mClientHandler = new ClientHandler(thread.getLooper()); 123143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine = new RttStateMachine(thread.getLooper()); 124143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 125143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mContext.registerReceiver( 126143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande new BroadcastReceiver() { 127143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 128143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void onReceive(Context context, Intent intent) { 129143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande int state = intent.getIntExtra( 130143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); 131143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (DBG) Log.d(TAG, "SCAN_AVAILABLE : " + state); 132143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (state == WifiManager.WIFI_STATE_ENABLED) { 133143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine.sendMessage(CMD_DRIVER_LOADED); 134143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else if (state == WifiManager.WIFI_STATE_DISABLED) { 135143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 136143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 137143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 138143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE)); 139143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 140143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine.start(); 141143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 142143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 143143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private class RttRequest { 144143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Integer key; 145143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientInfo ci; 14602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.RttParams[] params; 147143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 148143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 149143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private class ClientInfo { 150143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private final AsyncChannel mChannel; 151143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private final Messenger mMessenger; 15202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande HashMap<Integer, RttRequest> mRequests = new HashMap<Integer, 15302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttRequest>(); 154143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 155143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande ClientInfo(AsyncChannel c, Messenger m) { 156143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mChannel = c; 157143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mMessenger = m; 158143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 159143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 16002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande boolean addRttRequest(int key, RttManager.ParcelableRttParams parcelableParams) { 16102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (parcelableParams == null) { 16202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande return false; 16302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 16402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 16502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.RttParams params[] = parcelableParams.mParams; 16602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 167143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttRequest request = new RttRequest(); 168143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande request.key = key; 169143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande request.ci = this; 170143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande request.params = params; 17102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mRequests.put(key, request); 172143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mRequestQueue.add(request); 17302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande return true; 174143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 175143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 176143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void removeRttRequest(int key) { 177143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mRequests.remove(key); 178143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 179143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 180143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void reportResult(RttRequest request, RttManager.RttResult[] results) { 18102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.ParcelableRttResults parcelableResults = 18202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande new RttManager.ParcelableRttResults(results); 18302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 18402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mChannel.sendMessage(RttManager.CMD_OP_SUCCEEDED, 18502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 0, request.key, parcelableResults); 186143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mRequests.remove(request.key); 187143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 188143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 189143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void reportFailed(RttRequest request, int reason, String description) { 19002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande reportFailed(request.key, reason, description); 19102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 19202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 19302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande void reportFailed(int key, int reason, String description) { 19402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande Bundle bundle = new Bundle(); 19502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande bundle.putString(RttManager.DESCRIPTION_KEY, description); 19602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mChannel.sendMessage(RttManager.CMD_OP_FAILED, key, reason, bundle); 19702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mRequests.remove(key); 19802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 19902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 20002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande void reportAborted(int key) { 20102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mChannel.sendMessage(RttManager.CMD_OP_ABORTED, key); 20202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mRequests.remove(key); 203143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 204143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 205143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void cleanup() { 206143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mRequests.clear(); 207143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 208143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 209143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 210143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private Queue<RttRequest> mRequestQueue = new LinkedList<RttRequest>(); 211143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>(4); 212143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 21302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande private static final int BASE = Protocol.BASE_WIFI_RTT_SERVICE; 214143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 215143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private static final int CMD_DRIVER_LOADED = BASE + 0; 216143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private static final int CMD_DRIVER_UNLOADED = BASE + 1; 217143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private static final int CMD_ISSUE_NEXT_REQUEST = BASE + 2; 218143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private static final int CMD_RTT_RESPONSE = BASE + 3; 219143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 220143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande class RttStateMachine extends StateMachine { 221143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 222143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande DefaultState mDefaultState = new DefaultState(); 223143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande EnabledState mEnabledState = new EnabledState(); 224143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RequestPendingState mRequestPendingState = new RequestPendingState(); 225143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 226143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttStateMachine(Looper looper) { 227143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande super("RttStateMachine", looper); 22802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 22902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande addState(mDefaultState); 23002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande addState(mEnabledState); 23102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande addState(mRequestPendingState, mEnabledState); 23202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 23302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande setInitialState(mDefaultState); 234143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 235143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 236143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande class DefaultState extends State { 237143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 238143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public boolean processMessage(Message msg) { 23902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "DefaultState got" + msg); 240143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande switch (msg.what) { 241143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_DRIVER_LOADED: 242143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande transitionTo(mEnabledState); 243143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 244143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_ISSUE_NEXT_REQUEST: 245143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande deferMessage(msg); 246143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 24702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande case RttManager.CMD_OP_START_RANGING: 24802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande replyFailed(msg, RttManager.REASON_NOT_AVAILABLE, "Try later"); 24902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande break; 25002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande case RttManager.CMD_OP_STOP_RANGING: 25102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande return HANDLED; 252143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande default: 253143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return NOT_HANDLED; 254143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 255143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return HANDLED; 256143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 257143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 258143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 259143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande class EnabledState extends State { 260143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 261143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public boolean processMessage(Message msg) { 26202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "EnabledState got" + msg); 26302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande ClientInfo ci = mClients.get(msg.replyTo); 26402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 265143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande switch (msg.what) { 266143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_DRIVER_UNLOADED: 267143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande transitionTo(mDefaultState); 268143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 269143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_ISSUE_NEXT_REQUEST: 270143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande deferMessage(msg); 271143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande transitionTo(mRequestPendingState); 272143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 27302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande case RttManager.CMD_OP_START_RANGING: { 27402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.ParcelableRttParams params = 27502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande (RttManager.ParcelableRttParams)msg.obj; 27602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (params == null) { 27702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande replyFailed(msg, 27802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.REASON_INVALID_REQUEST, "No params"); 27902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } else if (ci.addRttRequest(msg.arg2, params) == false) { 28002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande replyFailed(msg, 28102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttManager.REASON_INVALID_REQUEST, "Unspecified"); 28202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } else { 28302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande sendMessage(CMD_ISSUE_NEXT_REQUEST); 28402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 28502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 28602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande break; 28702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande case RttManager.CMD_OP_STOP_RANGING: 28802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande for (Iterator<RttRequest> it = mRequestQueue.iterator(); 28902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande it.hasNext(); ) { 29002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande RttRequest request = it.next(); 29102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (request.key == msg.arg2) { 29202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "Cancelling not-yet-scheduled RTT"); 29302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mRequestQueue.remove(request); 29402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande request.ci.reportAborted(request.key); 29502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande break; 29602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 29702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 29802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande break; 299143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande default: 300143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return NOT_HANDLED; 301143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 302143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return HANDLED; 303143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 304143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 305143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 306143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande class RequestPendingState extends State { 307143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttRequest mOutstandingRequest; 308143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 309143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public boolean processMessage(Message msg) { 31002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "RequestPendingState got" + msg); 311143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande switch (msg.what) { 312143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_DRIVER_UNLOADED: 313143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (mOutstandingRequest != null) { 31402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande WifiNative.cancelRtt(mOutstandingRequest.params); 31502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 31602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mOutstandingRequest = null; 317143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 318143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande transitionTo(mDefaultState); 319143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 320143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_ISSUE_NEXT_REQUEST: 321143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (mOutstandingRequest == null) { 322143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mOutstandingRequest = issueNextRequest(); 323143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (mOutstandingRequest == null) { 324143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande transitionTo(mEnabledState); 325143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 326143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else { 327143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande /* just wait; we'll issue next request after 328143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande * current one is finished */ 32902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST"); 330143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 331143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 332143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande case CMD_RTT_RESPONSE: 33302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "Received an RTT response"); 334143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mOutstandingRequest.ci.reportResult( 335143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mOutstandingRequest, (RttManager.RttResult[])msg.obj); 33602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mOutstandingRequest = null; 337143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande sendMessage(CMD_ISSUE_NEXT_REQUEST); 338143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande break; 33902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande case RttManager.CMD_OP_STOP_RANGING: 34002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (mOutstandingRequest != null 34102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande && msg.arg2 == mOutstandingRequest.key) { 34202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "Cancelling ongoing RTT"); 34302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande WifiNative.cancelRtt(mOutstandingRequest.params); 34402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 34502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande mOutstandingRequest = null; 34602a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande sendMessage(CMD_ISSUE_NEXT_REQUEST); 34702a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } else { 34802a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande /* Let EnabledState handle this */ 34902a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande return NOT_HANDLED; 35002a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 35102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande break; 352143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande default: 353143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return NOT_HANDLED; 354143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 355143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return HANDLED; 356143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 357143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 358143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 359143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 360143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void replySucceeded(Message msg, Object obj) { 361143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (msg.replyTo != null) { 362143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Message reply = Message.obtain(); 363143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.what = RttManager.CMD_OP_SUCCEEDED; 364143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.arg2 = msg.arg2; 365143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.obj = obj; 366143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande try { 367143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande msg.replyTo.send(reply); 368143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } catch (RemoteException e) { 369143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande // There's not much we can do if reply can't be sent! 370143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 371143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else { 372143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande // locally generated message; doesn't need a reply! 373143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 374143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 375143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 376143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande void replyFailed(Message msg, int reason, String description) { 377143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Message reply = Message.obtain(); 378143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.what = RttManager.CMD_OP_FAILED; 379143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.arg1 = reason; 380143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande reply.arg2 = msg.arg2; 38102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 38202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande Bundle bundle = new Bundle(); 38302a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande bundle.putString(RttManager.DESCRIPTION_KEY, description); 38402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande reply.obj = bundle; 38502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande 386143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande try { 387143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande msg.replyTo.send(reply); 388143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } catch (RemoteException e) { 389143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande // There's not much we can do if reply can't be sent! 390143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 391143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 392143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 393143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private WifiNative.RttEventHandler mEventHandler = new WifiNative.RttEventHandler() { 394143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 395143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void onRttResults(RttManager.RttResult[] result) { 396143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mStateMachine.sendMessage(CMD_RTT_RESPONSE, result); 397143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 398143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande }; 399143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 400143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttRequest issueNextRequest() { 401143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttRequest request = null; 40202a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande while (mRequestQueue.isEmpty() == false) { 403143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande request = mRequestQueue.remove(); 40402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (WifiNative.requestRtt(request.params, mEventHandler)) { 40502a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "Issued next RTT request"); 406143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return request; 407143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } else { 408143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande request.ci.reportFailed(request, 409143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttManager.REASON_UNSPECIFIED, "Failed to start"); 410143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 41102a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande } 412143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 413143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande /* all requests exhausted */ 41402a1f98f2cecb8ae2d466d6f9fab06b473f970ddVinit Deshpande if (DBG) Log.d(TAG, "No more requests left"); 415143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande return null; 416143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 417143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 418143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 419143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande private static final String TAG = "RttService"; 420143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande RttServiceImpl mImpl; 421143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 422143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public RttService(Context context) { 423143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande super(context); 424143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Log.i(TAG, "Creating " + Context.WIFI_RTT_SERVICE); 425143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 426143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 427143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 428143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void onStart() { 429143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mImpl = new RttServiceImpl(getContext()); 430143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 431143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Log.i(TAG, "Starting " + Context.WIFI_RTT_SERVICE); 432143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande publishBinderService(Context.WIFI_RTT_SERVICE, mImpl); 433143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 434143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande 435143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande @Override 436143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande public void onBootPhase(int phase) { 437143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 438143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande Log.i(TAG, "Registering " + Context.WIFI_RTT_SERVICE); 439143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande if (mImpl == null) { 440143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mImpl = new RttServiceImpl(getContext()); 441143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 442143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande mImpl.startService(getContext()); 443143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 444143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande } 445143657392bf0702a155fe688171a5abbf4c86570Vinit Deshpande} 446