Advertisement
mateorod

external_gps_port.frameworks_base.diff

May 15th, 2013
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 54.89 KB | None | 0 0
  1. mateor@mateor-HP-Pavilion-dv6700:~/android/system/CM10b/frameworks/base$ git diff 126a201b051a18bef5e1e700be8c70967001da5c
  2. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provid
  3. index 8870944..d82d207 100644
  4. --- a/core/java/android/provider/Settings.java
  5. +++ b/core/java/android/provider/Settings.java
  6. @@ -4708,6 +4708,13 @@ public final class Settings {
  7.           */
  8.          public static final String WIMAX_ON = "wimax_on";
  9.  
  10. +         /*
  11. +         * Ported from CM10 (by Cuong)
  12. +         * External GPS source/device
  13. +         * @hide
  14. +         */
  15. +        public static final String EXTERNAL_GPS_BT_DEVICE = "0";
  16. +
  17.          /**
  18.           * This are the settings to be backed up.
  19.           *
  20. diff --git a/location/java/android/location/ILocationManager.aidl b/location/jav
  21. index f663e0a..3ee131a 100644
  22. --- a/location/java/android/location/ILocationManager.aidl
  23. +++ b/location/java/android/location/ILocationManager.aidl
  24. @@ -60,6 +60,9 @@ interface ILocationManager
  25.  
  26.      boolean sendNiResponse(int notifId, int userResponse);
  27.  
  28. +    // add set gps source--from CM10
  29. +    void setGPSSource(String device);
  30. +
  31.      // --- deprecated ---
  32.      List<String> getAllProviders();
  33.      List<String> getProviders(in Criteria criteria, boolean enabledOnly);
  34. diff --git a/location/java/android/location/LocationManager.java b/location/java
  35. index 5a2f71b..71e22d8 100644
  36. --- a/location/java/android/location/LocationManager.java
  37. +++ b/location/java/android/location/LocationManager.java
  38. @@ -291,6 +291,16 @@ public class LocationManager {
  39.          return new LocationProvider(name, properties);
  40.      }
  41.  
  42. +    // From CM10-- external GPS
  43. +    public void setGPSSource(String device) {
  44. +        try {
  45. +            mService.setGPSSource(device);
  46. +        } catch (RemoteException e) {
  47. +            Log.e(TAG, e.getMessage());
  48. +        }
  49. +    }
  50. +
  51. +
  52.      /**
  53.       * Returns a list of the names of all known location providers.
  54.       * <p>All providers are returned, including ones that are not permitted to
  55. diff --git a/services/java/com/android/server/LocationManagerService.java b/serv
  56. index 0f08c56..1a076ea 100644
  57. --- a/services/java/com/android/server/LocationManagerService.java
  58. +++ b/services/java/com/android/server/LocationManagerService.java
  59. @@ -56,12 +56,15 @@ import android.os.SystemClock;
  60.  import android.os.UserHandle;
  61.  import android.os.WorkSource;
  62.  import android.provider.Settings;
  63. +import android.text.TextUtils;
  64.  import android.util.Log;
  65.  import android.util.Slog;
  66.  
  67.  import com.android.internal.content.PackageMonitor;
  68.  import com.android.internal.location.ProviderProperties;
  69.  import com.android.internal.location.ProviderRequest;
  70. +
  71. +import com.android.server.location.BTGpsLocationProvider;
  72.  import com.android.server.location.GeocoderProxy;
  73.  import com.android.server.location.GeofenceManager;
  74.  import com.android.server.location.GpsLocationProvider;
  75. @@ -320,6 +323,36 @@ public class LocationManagerService extends ILocationManage
  76.                  + "partition. The fallback must also be marked coreApp=\"true\"
  77.      }
  78.  
  79. +    public void setGPSSource(String device) {
  80. +        synchronized (mLock) {
  81. +            if (mGpsLocationProvider != null &&
  82. +                    mProvidersByName.containsKey(mGpsLocationProvider.getName()
  83. +                Slog.i(TAG, "Disable and removing provider " + mGpsLocationProv
  84. +                mGpsLocationProvider.disable();
  85. +                Settings.Secure.setLocationProviderEnabled(mContext.getContentR
  86. +                        LocationManager.GPS_PROVIDER, false);
  87. +                removeProvider(mGpsLocationProvider);
  88. +                mGpsLocationProvider = null;
  89. +            }
  90. +            Slog.i(TAG, "Setting GPS Source to: " + device);
  91. +            if ("0".equals(device)) {
  92. +                if (mGpsLocationProvider != null && !GpsLocationProvider.isSupp
  93. +                    return;
  94. +                GpsLocationProvider gpsProvider = new GpsLocationProvider(mCont
  95. +                mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
  96. +                mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
  97. +                addProvider(gpsProvider);
  98. +                mGpsLocationProvider = gpsProvider;
  99. +            } else {
  100. +                BTGpsLocationProvider gpsProvider = new BTGpsLocationProvider(m
  101. +                mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
  102. +                mNetInitiatedListener = null;
  103. +                addProvider(gpsProvider);
  104. +                mGpsLocationProvider = gpsProvider;
  105. +            }
  106. +        }
  107. +    }
  108. +
  109.      private void loadProvidersLocked() {
  110.          // create a passive location provider, which is always enabled
  111.          PassiveProvider passiveProvider = new PassiveProvider(this);
  112. @@ -327,14 +360,16 @@ public class LocationManagerService extends ILocationManag
  113.          mEnabledProviders.add(passiveProvider.getName());
  114.          mPassiveProvider = passiveProvider;
  115.  
  116. -        if (GpsLocationProvider.isSupported()) {
  117. -            // Create a gps location provider
  118. -            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext,
  119. -            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
  120. -            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
  121. -            addProviderLocked(gpsProvider);
  122. -            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
  123. +        // Create a gps location provider based on the setting EXTERNAL_GPS_BT_
  124. +        String btDevice = Settings.System.getString(mContext.getContentResolver
  125. +                Settings.Secure.EXTERNAL_GPS_BT_DEVICE);
  126. +        if (TextUtils.isEmpty(btDevice)) {
  127. +            // default option
  128. +            btDevice = "0";
  129. +            Settings.System.putString(mContext.getContentResolver(),
  130. +                    Settings.Secure.EXTERNAL_GPS_BT_DEVICE, btDevice);
  131.          }
  132. +        setGPSSource(btDevice);
  133.  
  134.          /*
  135.          Load package name(s) containing location provider support.
  136. diff --git a/services/java/com/android/server/location/BTGPSService.java b/servi
  137. new file mode 100644
  138. index 0000000..49aa20d
  139. --- /dev/null
  140. +++ b/services/java/com/android/server/location/BTGPSService.java
  141. @@ -0,0 +1,465 @@
  142. +/*
  143. + * Copyright (C) 2011 Cuong Bui
  144. + *
  145. + * Licensed under the Apache License, Version 2.0 (the "License");
  146. + * you may not use this file except in compliance with the License.
  147. + * You may obtain a copy of the License at
  148. + *
  149. + *      http://www.apache.org/licenses/LICENSE-2.0
  150. + *
  151. + * Unless required by applicable law or agreed to in writing, software
  152. + * distributed under the License is distributed on an "AS IS" BASIS,
  153. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  154. + * See the License for the specific language governing permissions and
  155. + * limitations under the License.
  156. + */
  157. +package com.android.server.location;
  158. +
  159. +import java.io.BufferedReader;
  160. +import java.io.IOException;
  161. +import java.io.InputStream;
  162. +import java.io.InputStreamReader;
  163. +import java.io.OutputStream;
  164. +import java.util.UUID;
  165. +
  166. +import android.bluetooth.BluetoothAdapter;
  167. +import android.bluetooth.BluetoothDevice;
  168. +import android.bluetooth.BluetoothSocket;
  169. +import android.os.Handler;
  170. +import android.os.Message;
  171. +import android.util.Log;
  172. +
  173. +public class BTGPSService {
  174. +    private static final boolean D = true;
  175. +    private static final String TAG = "BTGPSService";
  176. +    private static final UUID BT_UUID = UUID.fromString("00001101-0000-1000-800
  177. +    private final BluetoothAdapter mAdapter;
  178. +    private final Handler mHandler;
  179. +    private WatchdogThread mWatchdogThread = null;
  180. +    private ConnectThread mConnectThread = null;
  181. +    private ConnectedThread mConnectedThread = null;
  182. +    private final int mMaxNMEABuffer=4096;
  183. +    private final char[] buffer = new char[mMaxNMEABuffer];
  184. +    int bytes;
  185. +    private long refreshRate = 1000;
  186. +    private long lastActivity = 0;
  187. +    // MAX_ACTIVITY_TIMEOUT * refresh time window should have at least one acti
  188. +    private int MAX_ACTIVITY_TIMEOUT = 5;
  189. +    // Maximum connect retry attempt
  190. +    private int MAX_RECONNECT_RETRIES = 5;
  191. +    // time window for one single connection (ms). socket connect timeout is ar
  192. +    private int MAX_CONNECT_TIMEOUT = 13000;
  193. +    // last connected device. is used to auto reconnect.
  194. +    private BluetoothDevice lastConnectedDevice=null;
  195. +
  196. +    private int mState = 0;
  197. +    // Constants that indicate the current connection state
  198. +    public static final int STATE_NONE = 0;       // we're doing nothing
  199. +    public static final int STATE_LISTEN = 1;     // now listening for incoming
  200. +    public static final int STATE_CONNECTING = 2; // now initiating an outgoing
  201. +    public static final int STATE_CONNECTED = 3;  // now connected to a remote
  202. +
  203. +    public synchronized void setRefreshRate(long r) {
  204. +        refreshRate = r;
  205. +    }
  206. +
  207. +    public synchronized long getRefreshRate() {
  208. +        return refreshRate;
  209. +    }
  210. +
  211. +    public BTGPSService(Handler h) {
  212. +        mAdapter = BluetoothAdapter.getDefaultAdapter();
  213. +        mHandler = h;
  214. +    }
  215. +
  216. +    private void sendMessage(int message, int arg, Object obj) {
  217. +        Message m = Message.obtain(mHandler, message);
  218. +        m.arg1 = arg;
  219. +        m.obj = obj;
  220. +        mHandler.sendMessage(m);
  221. +    }
  222. +
  223. +    private void handleFailedConnection() {
  224. +        if (getServiceState() != STATE_NONE) {
  225. +            if (D) Log.d(TAG, "Connection failed with status != 0. try to recon
  226. +            connect(lastConnectedDevice);
  227. +        } else {
  228. +            if (D) Log.d(TAG, "Connection stopped with status = 0.");
  229. +        }
  230. +    }
  231. +
  232. +    /**
  233. +     * Set the current state of the chat connection
  234. +     * @param state  An integer defining the current connection state
  235. +     */
  236. +    private synchronized void setState(int state) {
  237. +        if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
  238. +        mState = state;
  239. +        if (mState == STATE_NONE) {
  240. +            sendMessage(BTGpsLocationProvider.GPS_STATUS_UPDATE, 0, null);
  241. +        } else if (mState == STATE_CONNECTED) {
  242. +            sendMessage(BTGpsLocationProvider.GPS_STATUS_UPDATE, 1, null);
  243. +        }
  244. +    }
  245. +
  246. +    /**
  247. +     * Return the current connection state. */
  248. +    public synchronized int getServiceState() {
  249. +        return mState;
  250. +    }
  251. +
  252. +    /**
  253. +     * Start the chat service. Specifically start AcceptThread to begin a
  254. +     * session in listening (server) mode. Called by the Activity onResume() */
  255. +    public synchronized void start() {
  256. +
  257. +        if (D) Log.d(TAG, "start");
  258. +        if (!mAdapter.isEnabled()) {
  259. +            setState(STATE_NONE);
  260. +            return;
  261. +        }
  262. +        // Cancel any thread attempting to make a connection
  263. +        if (mConnectThread != null) {
  264. +            mConnectThread.cancel();
  265. +            mConnectThread = null;
  266. +        }
  267. +        // Cancel any thread currently running a connection
  268. +        if (mConnectedThread != null) {
  269. +            mConnectedThread.cancel();
  270. +            mConnectedThread = null;
  271. +        }
  272. +        setState(STATE_LISTEN);
  273. +    }
  274. +
  275. +    /**
  276. +     * Start the ConnectThread to initiate a connection to a remote device.
  277. +     * @param device  The BluetoothDevice to connect
  278. +     */
  279. +    public synchronized boolean connect(BluetoothDevice device) {
  280. +        lastConnectedDevice = device;
  281. +        if (D) Log.d(TAG, "connect to: " + device);
  282. +        // Cancel any thread attempting to make a connection
  283. +        if (mConnectThread != null) {
  284. +            mConnectThread.cancel();
  285. +            mConnectThread = null;
  286. +        }
  287. +        if (mWatchdogThread != null) {
  288. +            mWatchdogThread.cancel();
  289. +            mWatchdogThread = null;
  290. +        }
  291. +        // Cancel any thread currently running a connection
  292. +        if (mConnectedThread != null) {
  293. +            mConnectedThread.cancel();
  294. +            mConnectedThread = null;
  295. +        }
  296. +        // Helper thread that monitors and retries to connect after time out
  297. +        mWatchdogThread = new WatchdogThread(device);
  298. +        mWatchdogThread.start();
  299. +        return true;
  300. +    }
  301. +
  302. +    /**
  303. +     * Start the ConnectedThread to begin managing a Bluetooth connection
  304. +     * @param socket  The BluetoothSocket on which the connection was made
  305. +     * @param device  The BluetoothDevice that has been connected
  306. +     */
  307. +    public synchronized void connected(BluetoothSocket socket) {
  308. +        // reset connect thread
  309. +        if (mConnectThread != null) mConnectThread = null;
  310. +
  311. +        // kill watchdog, since we are connected
  312. +        if (mWatchdogThread != null) {
  313. +            mWatchdogThread.cancel();
  314. +            mWatchdogThread = null;
  315. +        }
  316. +        // Cancel any thread currently running a connection
  317. +        if (mConnectedThread != null) {
  318. +            mConnectedThread.cancel();
  319. +            mConnectedThread = null;
  320. +        }
  321. +
  322. +        // Start the thread to manage the connection and perform transmissions
  323. +        mConnectedThread = new ConnectedThread(socket);
  324. +        mConnectedThread.start();
  325. +        setState(STATE_CONNECTED);
  326. +    }
  327. +
  328. +    /**
  329. +     * Stop all threads
  330. +     */
  331. +    public synchronized void stop() {
  332. +        if (D) Log.d(TAG, "Stopping btsvc, Set state to None");
  333. +        setState(STATE_NONE);
  334. +
  335. +        if (mWatchdogThread != null) {
  336. +            if (D) Log.d(TAG, "Cancelling watchdog thread");
  337. +            mWatchdogThread.cancel();
  338. +            mWatchdogThread = null;
  339. +        }
  340. +
  341. +        if (mConnectThread != null) {
  342. +            if (D) Log.d(TAG, "Cancelling connect thread");
  343. +            mConnectThread.cancel();
  344. +            mConnectThread = null;
  345. +        }
  346. +        if (mConnectedThread != null) {
  347. +            if (D) Log.d(TAG, "Cancelling connected thread");
  348. +            mConnectedThread.cancel();
  349. +            mConnectedThread = null;
  350. +        }
  351. +    }
  352. +
  353. +    /**
  354. +     * Write to the ConnectedThread in an unsynchronized manner
  355. +     * @param out The bytes to write
  356. +     * @see ConnectedThread#write(byte[])
  357. +     */
  358. +    public void write(byte[] out) {
  359. +        // Create temporary object
  360. +        ConnectedThread r;
  361. +        // Synchronize a copy of the ConnectedThread
  362. +        synchronized (this) {
  363. +            if (mState != STATE_CONNECTED) return;
  364. +            r = mConnectedThread;
  365. +        }
  366. +        r.write(out);
  367. +    }
  368. +
  369. +    /**
  370. +     * This thread runs while attempting to make an outgoing connection
  371. +     * with a device. It runs straight through; the connection either
  372. +     * succeeds or fails.
  373. +     */
  374. +    private class ConnectThread extends Thread {
  375. +        private BluetoothSocket mmSocket;
  376. +        private final BluetoothDevice mmDevice;
  377. +        private String mSocketType;
  378. +
  379. +        public ConnectThread(BluetoothDevice device) {
  380. +            mmDevice = device;
  381. +        }
  382. +
  383. +        private void closeSocket() {
  384. +            if (D) Log.d(TAG, getId()+":close socket");
  385. +            if (mmSocket == null) {
  386. +                Log.e(TAG, getId()+":Socket not ready. Aborting Close");
  387. +                return;
  388. +            }
  389. +
  390. +            try {
  391. +                mmSocket.close();
  392. +                mmSocket = null;
  393. +            } catch (IOException e) {
  394. +                Log.e(TAG, getId()+":close() of connect " + mSocketType + " soc
  395. +            }
  396. +        }
  397. +
  398. +        public void run() {
  399. +            Log.i(TAG, getId() + ":begin mConnectThread");
  400. +            BluetoothSocket tmp = null;
  401. +            // Always cancel discovery because it will slow down a connection
  402. +
  403. +            try {
  404. +                tmp = mmDevice.createRfcommSocketToServiceRecord(BT_UUID);
  405. +            } catch (IOException e) {
  406. +                Log.e(TAG, "Socket create() failed", e);
  407. +                return;
  408. +            }
  409. +            mmSocket = tmp;
  410. +            // Make a connection to the BluetoothSocket
  411. +            if (mAdapter.isEnabled()) mAdapter.cancelDiscovery();
  412. +            try {
  413. +                // This is a blocking call and will only return on a
  414. +                // successful connection or an exception
  415. +                if (D)  Log.d(TAG, getId() + ":Connecting to socket...");
  416. +                mmSocket.connect();
  417. +                if (D) Log.d(TAG, "connected with remote device: "
  418. +                        + mmDevice.getName() + " at address " + mmDevice.getAdd
  419. +                connected(mmSocket);
  420. +            } catch (IOException e) {
  421. +                Log.w(TAG, getId() + ":connect failed.", e);
  422. +                return;
  423. +            }
  424. +        }
  425. +
  426. +        public synchronized void cancel() {
  427. +            closeSocket();
  428. +        }
  429. +    }
  430. +
  431. +    /**
  432. +     * This thread runs during a connection with a remote device.
  433. +     * It handles all incoming and outgoing transmissions.
  434. +     */
  435. +    private class ConnectedThread extends Thread {
  436. +        private BluetoothSocket mmSocket;
  437. +        private InputStream mmInStream;
  438. +        private OutputStream mmOutStream;
  439. +        private boolean cancelled = false;
  440. +
  441. +        private void closeSocket() {
  442. +            if (D) Log.d(TAG, getId()+":close socket");
  443. +            if (mmSocket == null) {
  444. +                Log.e(TAG, getId()+":Socket not ready. Aborting Close");
  445. +                return;
  446. +            }
  447. +            try {
  448. +                mmSocket.close();
  449. +                mmSocket = null;
  450. +            } catch (IOException e) {
  451. +                Log.e(TAG, getId()+": close() of connect socket failed", e);
  452. +            }
  453. +        }
  454. +
  455. +        public ConnectedThread(BluetoothSocket socket) {
  456. +            Log.d(TAG, getId() + ":begin ConnectedThread");
  457. +            mmSocket = socket;
  458. +            InputStream tmpIn = null;
  459. +            OutputStream tmpOut = null;
  460. +
  461. +            // Get the BluetoothSocket input and output streams
  462. +            try {
  463. +                tmpIn = socket.getInputStream();
  464. +                tmpOut = socket.getOutputStream();
  465. +            } catch (IOException e) {
  466. +                Log.e(TAG, "temp sockets not created", e);
  467. +            }
  468. +            mmInStream = tmpIn;
  469. +            mmOutStream = tmpOut;
  470. +        }
  471. +
  472. +        public void run() {
  473. +            if (mmSocket == null || mmInStream == null) {
  474. +                Log.e(TAG, "Input stream or socket is null. Aborting thread");
  475. +                return;
  476. +            }
  477. +            if (D) Log.d(TAG, getId() + ":BEGIN mConnectedThread");
  478. +            java.util.Arrays.fill(buffer, (char) ' ');
  479. +            // reset refresh rate to 1000
  480. +            refreshRate = 1000;
  481. +            lastActivity = 0;
  482. +            BufferedReader reader = new BufferedReader(new InputStreamReader(mm
  483. +            // Keep listening to the InputStream while connected
  484. +            while (true) {
  485. +                try {
  486. +                    if (reader.ready()) {
  487. +                        bytes = reader.read(buffer, 0, mMaxNMEABuffer);
  488. +                        Message msg = mHandler.obtainMessage(
  489. +                                BTGpsLocationProvider.GPS_DATA_AVAILABLE,buffer
  490. +                        lastActivity = System.currentTimeMillis();
  491. +                        msg.arg1 = bytes;
  492. +                        mHandler.sendMessage(msg);
  493. +                    }
  494. +                    if (lastActivity != 0 && (System.currentTimeMillis() - last
  495. +                            MAX_ACTIVITY_TIMEOUT*refreshRate) {
  496. +                        Log.w(TAG, getId() + ":BT activity timeout.");
  497. +                        closeSocket();
  498. +                        handleFailedConnection();
  499. +                        return;
  500. +                    }
  501. +                    try {
  502. +                        // get default sleep time
  503. +                        Thread.sleep(getRefreshRate());
  504. +                    } catch (InterruptedException e) {
  505. +                        if (cancelled) {
  506. +                            closeSocket();
  507. +                            return;
  508. +                        }
  509. +                    }
  510. +                } catch (IOException e) {
  511. +                    Log.w(TAG, getId() + ":disconnected.", e);
  512. +                    closeSocket();
  513. +                    handleFailedConnection();
  514. +                    return;
  515. +                }
  516. +            }
  517. +        }
  518. +
  519. +        /**
  520. +         * Write to the connected OutStream.
  521. +         * @param buffer  The bytes to write
  522. +         */
  523. +        public void write(byte[] buffer) {
  524. +            try {
  525. +                mmOutStream.write(buffer);
  526. +                mmOutStream.flush();
  527. +            } catch (IOException e) {
  528. +                Log.e(TAG, "Exception during write", e);
  529. +            }
  530. +        }
  531. +
  532. +        public void cancel() {
  533. +            try {
  534. +                if (mmSocket == null) {
  535. +                    Log.e(TAG, "Input stream null. Aborting Cacnel");
  536. +                    return;
  537. +                }
  538. +                mmSocket.close();
  539. +            } catch (IOException e) {
  540. +                Log.e(TAG, "close() of connect socket failed", e);
  541. +            } finally {
  542. +                cancelled = true;
  543. +                interrupt();
  544. +            }
  545. +        }
  546. +    }
  547. +    /*
  548. +     * Thread that starts the connection thread an monitors it.
  549. +     * Thread will be cancelled if timeot occurs
  550. +     */
  551. +    private class WatchdogThread extends Thread {
  552. +        private final BluetoothDevice btdevice;
  553. +        private int retries = 0;
  554. +        private boolean sleep = false;
  555. +        private boolean cancelled = false;
  556. +
  557. +        public WatchdogThread(BluetoothDevice dev) {
  558. +            btdevice = dev;
  559. +        }
  560. +
  561. +        public void run() {
  562. +            while(retries < MAX_RECONNECT_RETRIES) {
  563. +                if (mConnectThread != null) {
  564. +                    mConnectThread.cancel();
  565. +                    mConnectThread = null;
  566. +                }
  567. +                if (mConnectedThread != null) {
  568. +                    mConnectedThread.cancel();
  569. +                    mConnectedThread = null;
  570. +                }
  571. +
  572. +                mConnectThread = new ConnectThread(btdevice);
  573. +                mConnectThread.start();
  574. +                setState(STATE_CONNECTING);
  575. +                // monitor connection and cancel if timeout
  576. +                if (D) Log.d(TAG, getId() + ":Waiting " + MAX_CONNECT_TIMEOUT
  577. +                        + " (ms) for service to connect...");
  578. +                try {
  579. +                    sleep = true;
  580. +                    Thread.sleep(MAX_CONNECT_TIMEOUT);
  581. +                    sleep = false;
  582. +                    if (D) Log.d(TAG, getId() + ":Connecting timeout.");
  583. +                } catch (InterruptedException e) {
  584. +                    if (D) Log.d(TAG, getId() + ":Watchdog interrupted. probabl
  585. +                }
  586. +                if (getServiceState() == STATE_CONNECTED) {
  587. +                    if (D) Log.d(TAG, getId() + ":Connected. aborting watchdog"
  588. +                    return;
  589. +                }
  590. +                if (cancelled) {
  591. +                    if (D) Log.d(TAG, getId() + ":Cancelled. aborting watchdog"
  592. +                    return;
  593. +                }
  594. +                retries++;
  595. +            }
  596. +            // max timeout, so stopping service
  597. +            if (D) Log.d(TAG, getId() + ":Max connection retries exceeded. stop
  598. +            BTGPSService.this.stop();
  599. +        }
  600. +
  601. +        public void cancel() {
  602. +            cancelled = true;
  603. +            if (sleep) interrupt();
  604. +        }
  605. +    }
  606. +}
  607. diff --git a/services/java/com/android/server/location/BTGpsLocationProvider.jav
  608. new file mode 100644
  609. index 0000000..8f2bbab
  610. --- /dev/null
  611. +++ b/services/java/com/android/server/location/BTGpsLocationProvider.java
  612. @@ -0,0 +1,858 @@
  613. +/*
  614. + * Copyright (C) 2011 Cuong Bui
  615. + *
  616. + * Licensed under the Apache License, Version 2.0 (the "License");
  617. + * you may not use this file except in compliance with the License.
  618. + * You may obtain a copy of the License at
  619. + *
  620. + *      http://www.apache.org/licenses/LICENSE-2.0
  621. + *
  622. + * Unless required by applicable law or agreed to in writing, software
  623. + * distributed under the License is distributed on an "AS IS" BASIS,
  624. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  625. + * See the License for the specific language governing permissions and
  626. + * limitations under the License.
  627. + */
  628. +package com.android.server.location;
  629. +
  630. +
  631. +import java.util.ArrayList;
  632. +import java.util.concurrent.CountDownLatch;
  633. +
  634. +import android.bluetooth.BluetoothAdapter;
  635. +import android.bluetooth.BluetoothDevice;
  636. +import android.content.BroadcastReceiver;
  637. +import android.content.Context;
  638. +import android.content.Intent;
  639. +import android.content.IntentFilter;
  640. +import android.location.Criteria;
  641. +import android.location.IGpsStatusListener;
  642. +import android.location.IGpsStatusProvider;
  643. +import android.location.ILocationManager;
  644. +import android.location.Location;
  645. +import android.location.LocationManager;
  646. +import android.location.LocationProvider;
  647. +import android.net.NetworkInfo;
  648. +import android.os.Bundle;
  649. +import android.os.Handler;
  650. +import android.os.IBinder;
  651. +import android.os.Looper;
  652. +import android.os.Message;
  653. +import android.os.PowerManager;
  654. +import android.os.RemoteException;
  655. +import android.os.ServiceManager;
  656. +import android.os.SystemClock;
  657. +import android.os.WorkSource;
  658. +import android.provider.Settings;
  659. +import android.text.TextUtils;
  660. +import android.util.Log;
  661. +import android.util.SparseIntArray;
  662. +
  663. +import com.android.internal.app.IBatteryStats;
  664. +
  665. +
  666. +public class BTGpsLocationProvider  implements LocationProviderInterface {
  667. +    private static final boolean D = true;
  668. +    private final String PROVIDER = "External Bleutooth Location Provider";
  669. +    private final String TAG = "BTGpsLocationProvider";
  670. +    private final NMEAParser nmeaparser = new NMEAParser(PROVIDER);
  671. +
  672. +    private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapte
  673. +
  674. +    // GPS update codes
  675. +    public static final int GPS_DATA_AVAILABLE = 1000;
  676. +    public static final int GPS_STATUS_UPDATE = 1001;
  677. +    public static final int GPS_CUSTOM_COMMAND = 1002;
  678. +
  679. +
  680. +    // Wakelocks
  681. +    private final static String WAKELOCK_KEY = "GpsLocationProvider";
  682. +    private final PowerManager.WakeLock mWakeLock;
  683. +    // bitfield of pending messages to our Handler
  684. +    // used only for messages that cannot have multiple instances queued
  685. +    private int mPendingMessageBits;
  686. +    // separate counter for ADD_LISTENER and REMOVE_LISTENER messages,
  687. +    // which might have multiple instances queued
  688. +    private int mPendingListenerMessages;
  689. +
  690. +    private final IBatteryStats mBatteryStats;
  691. +    private final SparseIntArray mClientUids = new SparseIntArray();
  692. +    // Handler messages
  693. +    private static final int CHECK_LOCATION = 1;
  694. +    private static final int ENABLE = 2;
  695. +    private static final int ENABLE_TRACKING = 3;
  696. +    private static final int UPDATE_NETWORK_STATE = 4;
  697. +    private static final int INJECT_NTP_TIME = 5;
  698. +    private static final int DOWNLOAD_XTRA_DATA = 6;
  699. +    private static final int UPDATE_LOCATION = 7;
  700. +    private static final int ADD_LISTENER = 8;
  701. +    private static final int REMOVE_LISTENER = 9;
  702. +    private static final int REQUEST_SINGLE_SHOT = 10;
  703. +
  704. +    // for calculating time to first fix
  705. +    private long mFixRequestTime = 0;
  706. +    // time to first fix for most recent session
  707. +    private int mTTFF = 0;
  708. +    // time we received our last fix
  709. +    private long mLastFixTime;
  710. +
  711. +    // time for last status update
  712. +    private long mStatusUpdateTime = SystemClock.elapsedRealtime();
  713. +
  714. +    // true if we are enabled
  715. +    private volatile boolean mEnabled;
  716. +
  717. +    // true if GPS is navigating
  718. +    private boolean mNavigating;
  719. +
  720. +    private int mSvCount;
  721. +    // current status
  722. +    private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
  723. +
  724. +    private Bundle mLocationExtras = new Bundle();
  725. +    private Location mLocation = new Location(PROVIDER);
  726. +
  727. +    private final Context mContext;
  728. +    private final ILocationManager mLocationManager;
  729. +
  730. +    private final IntentFilter mIntentBTFilter;
  731. +
  732. +    private final Thread mMessageLoopThread = new BTGPSMessageThread();
  733. +    private final CountDownLatch mInitializedLatch = new CountDownLatch(1);
  734. +
  735. +    /**
  736. +     *Listen for BT changes. If BT is turned off, disable GPS services
  737. +     */
  738. +    private final BroadcastReceiver mReceiver;
  739. +
  740. +    /**
  741. +     *  Message handler
  742. +     *  Receives nmea sentences
  743. +     *  receives connection lost signals
  744. +     *  enabling/disabling gps signals
  745. +     *  adding/removing listeners
  746. +     */
  747. +    private Handler mHandler;
  748. +
  749. +    // BT gps service. This class handles the actual BT connection and data xfe
  750. +    private final BTGPSService btsvc;
  751. +
  752. +    // BT Location provider , uses the same method signature as the org GPS loc
  753. +    public BTGpsLocationProvider(Context context, ILocationManager locationMana
  754. +
  755. +        mContext = context;
  756. +        mLocationManager = locationManager;
  757. +        // innit message handler
  758. +        mMessageLoopThread.start();
  759. +        // wait for message handler to be ready
  760. +        while (true) {
  761. +            try {
  762. +                mInitializedLatch.await();
  763. +                break;
  764. +            } catch (InterruptedException e) {
  765. +                Thread.currentThread().interrupt();
  766. +            }
  767. +        }
  768. +        // instantiate BTGPSService
  769. +        btsvc = new BTGPSService(mHandler);
  770. +
  771. +        // Create a wake lock.
  772. +        PowerManager powerManager = (PowerManager) mContext.getSystemService(Co
  773. +        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WA
  774. +        mWakeLock.setReferenceCounted(false);
  775. +
  776. +        // Battery statistics service to be notified when GPS turns on or off
  777. +        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getServic
  778. +
  779. +        // receive BT state changes
  780. +        mReceiver = new BroadcastReceiver() {
  781. +            @Override
  782. +            public void onReceive(Context context, Intent intent) {
  783. +                String action = intent.getAction();
  784. +                if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
  785. +                    int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE
  786. +                            BluetoothAdapter.ERROR);
  787. +                    switch (state) {
  788. +                    case BluetoothAdapter.STATE_ON:
  789. +                        if (D) Log.i(TAG, "BT turned on -> notify services?");
  790. +                        break;
  791. +                    case BluetoothAdapter.STATE_TURNING_OFF:
  792. +                        if (btsvc.getServiceState() != BTGPSService.STATE_NONE)
  793. +                            if (D) Log.i(TAG, "BT turned off -> stopping servic
  794. +                            btsvc.stop();
  795. +                        }
  796. +                        break;
  797. +                    }
  798. +                }
  799. +            }
  800. +        };
  801. +        mIntentBTFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGE
  802. +        mContext.registerReceiver(mReceiver, mIntentBTFilter);
  803. +    }
  804. +
  805. +    private final class BTGPSMessageThread extends Thread {
  806. +
  807. +        public void run() {
  808. +            try {
  809. +                Looper.prepare();
  810. +            } catch (RuntimeException e) {
  811. +                // ignored: Looper already prepared
  812. +            }
  813. +            mHandler = new Handler() {
  814. +                @Override
  815. +                public void handleMessage(Message msg) {
  816. +                    int message = msg.what;
  817. +                    switch (message) {
  818. +                    case GPS_DATA_AVAILABLE:
  819. +                        char[] writeBuf = (char[]) msg.obj;
  820. +                        int bytes = msg.arg1;
  821. +                        if ((writeBuf != null) && (mEnabled && bytes > 0)) {
  822. +                            String writeMessage = new String(writeBuf, 0, bytes
  823. +                            handleNMEAMessages(writeMessage);
  824. +                            java.util.Arrays.fill(writeBuf, (char) ' ');
  825. +                        }
  826. +                        break;
  827. +                    case GPS_STATUS_UPDATE:
  828. +                        notifyEnableDisableGPS(msg.arg1 == 1);
  829. +                        break;
  830. +                    case GPS_CUSTOM_COMMAND:
  831. +                        if (mEnabled && btsvc.getServiceState() == BTGPSService
  832. +                            // sends custom commands
  833. +                            byte[] cmds = (byte[]) msg.obj;
  834. +                            btsvc.write(cmds);
  835. +                        }
  836. +                        break;
  837. +                    case ENABLE:
  838. +                        if (msg.arg1 == 1) {
  839. +                            handleEnable();
  840. +                        } else {
  841. +                            handleDisable();
  842. +                        }
  843. +                        break;
  844. +                    case REQUEST_SINGLE_SHOT:
  845. +                    case ENABLE_TRACKING:
  846. +                    case UPDATE_NETWORK_STATE:
  847. +                    case INJECT_NTP_TIME:
  848. +                    case DOWNLOAD_XTRA_DATA:
  849. +                        break;
  850. +                    case UPDATE_LOCATION:
  851. +                        handleUpdateLocation((Location)msg.obj);
  852. +                        break;
  853. +                    case ADD_LISTENER:
  854. +                        handleAddListener(msg.arg1);
  855. +                        break;
  856. +                    case REMOVE_LISTENER:
  857. +                        handleRemoveListener(msg.arg1);
  858. +                        break;
  859. +                    }
  860. +                    // release wake lock if no messages are pending
  861. +                    synchronized (mWakeLock) {
  862. +                        mPendingMessageBits &= ~(1 << message);
  863. +                        if (message == ADD_LISTENER || message == REMOVE_LISTEN
  864. +                            mPendingListenerMessages--;
  865. +                        }
  866. +                        if (mPendingMessageBits == 0 && mPendingListenerMessage
  867. +                            mWakeLock.release();
  868. +                        }
  869. +                    }
  870. +                }
  871. +            };
  872. +            mInitializedLatch.countDown();
  873. +            Looper.loop();
  874. +        }
  875. +    }
  876. +
  877. +    @Override
  878. +    public void enable() {
  879. +        synchronized (mHandler) {
  880. +            sendMessage(ENABLE, 1, null);
  881. +        }
  882. +    }
  883. +
  884. +    /**
  885. +     * Enables BT GPS provider
  886. +     */
  887. +    private synchronized void handleEnable() {
  888. +        if (D) Log.d(TAG, "handleEnable");
  889. +        if (mEnabled) return;
  890. +        // check if BT is enabled
  891. +        if (!mAdapter.isEnabled()) {
  892. +            int state = mAdapter.getState();
  893. +            if (state == BluetoothAdapter.STATE_OFF) {
  894. +                if (D) Log.d(TAG, "BT not available. Enable and wait for it..."
  895. +                mAdapter.enable();
  896. +            }
  897. +            // wait for adapter to be ready
  898. +            while (true) {
  899. +                try {
  900. +                    state = mAdapter.getState();
  901. +                    if (state == BluetoothAdapter.STATE_ON) {
  902. +                        break;
  903. +                    } else if (state == BluetoothAdapter.STATE_TURNING_ON) {
  904. +                        if (D) Log.d(TAG, "BT not available yet. waiting for an
  905. +                        Thread.sleep(400);
  906. +                    } else {
  907. +                        if (D) Log.d(TAG, "BT got disabled or interrupted by ot
  908. +                        return;
  909. +                    }
  910. +
  911. +                } catch (InterruptedException e) {
  912. +                    Log.w(TAG, e.getMessage());
  913. +                }
  914. +            }
  915. +        }
  916. +        if (D) Log.d(TAG, "mEnabled -> true");
  917. +        mEnabled = true;
  918. +        if (D) Log.d(TAG, "mStatus -> temp unavailable");
  919. +        mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
  920. +        if (D) Log.d(TAG, "btservice start");
  921. +        btsvc.start();
  922. +        mFixRequestTime = System.currentTimeMillis();
  923. +        mTTFF = 0;
  924. +        String btDevice = Settings.System.getString(mContext.getContentResolver
  925. +                Settings.Secure.EXTERNAL_GPS_BT_DEVICE);
  926. +        if (D) Log.d(TAG, "Connecting to saved pref: " + btDevice);
  927. +        if ((btDevice != null) && !"0".equals(btDevice)) {
  928. +            if ((mAdapter != null) && (mAdapter.isEnabled())) {
  929. +                for (BluetoothDevice d: mAdapter.getBondedDevices()) {
  930. +                    if (btDevice.equals(d.getAddress())) {
  931. +                        if (D) Log.d(TAG, "Connecting...");
  932. +                        btsvc.connect(d);
  933. +                        return;
  934. +                    }
  935. +                }
  936. +            }
  937. +        }
  938. +    }
  939. +
  940. +    /**
  941. +     * Disables this provider.
  942. +     */
  943. +    @Override
  944. +    public void disable() {
  945. +        synchronized (mHandler) {
  946. +            sendMessage(ENABLE, 0, null);
  947. +        }
  948. +    }
  949. +
  950. +    private synchronized void handleDisable() {
  951. +        if (D) Log.d(TAG, "handleDisable");
  952. +        if (!mEnabled) return;
  953. +        if (D) Log.d(TAG, "mEnabled -> false");
  954. +        mEnabled = false;
  955. +        if (D) Log.d(TAG, "reportstatus notify listeners and system");
  956. +        notifyEnableDisableGPS(false);
  957. +        if (D) Log.d(TAG, "update to out of service");
  958. +        updateStatus(LocationProvider.OUT_OF_SERVICE, mSvCount);
  959. +        if (D) Log.d(TAG, "btservice Stop");
  960. +        btsvc.stop();
  961. +    }
  962. +
  963. +    /* We do not need to implement scheduled tracking. With internal gps provid
  964. +     * to hibernate and resume periodically. With BT GPS providers it doesn't m
  965. +     * @see com.android.server.location.LocationProviderInterface#enableLocatio
  966. +     */
  967. +    @Override
  968. +    public void enableLocationTracking(boolean enable) {
  969. +    }
  970. +
  971. +    @Override
  972. +    public int getAccuracy() {
  973. +        return Criteria.ACCURACY_FINE;
  974. +    }
  975. +
  976. +    /* Debug native state used by normal GPS provider only
  977. +     * @see com.android.server.location.LocationProviderInterface#getInternalSt
  978. +     */
  979. +    @Override
  980. +    public String getInternalState() {
  981. +        return null;
  982. +    }
  983. +
  984. +    @Override
  985. +    public String getName() {
  986. +        return LocationManager.GPS_PROVIDER;
  987. +    }
  988. +
  989. +    /**
  990. +     * Returns the power requirement for this provider.
  991. +     *
  992. +     * @return the power requirement for this provider, as one of the
  993. +     * constants Criteria.POWER_REQUIREMENT_*.
  994. +     */
  995. +    public int getPowerRequirement() {
  996. +        return Criteria.POWER_MEDIUM;
  997. +    }
  998. +
  999. +    /**
  1000. +     * Returns true if this provider meets the given criteria,
  1001. +     * false otherwise.
  1002. +     */
  1003. +    public boolean meetsCriteria(Criteria criteria) {
  1004. +        return (criteria.getPowerRequirement() != Criteria.POWER_LOW);
  1005. +    }
  1006. +
  1007. +    @Override
  1008. +    public int getStatus(Bundle extras) {
  1009. +        if (extras != null) {
  1010. +            extras.putInt("satellites", mSvCount);
  1011. +        }
  1012. +        return mStatus;
  1013. +    }
  1014. +
  1015. +    @Override
  1016. +    public long getStatusUpdateTime() {
  1017. +        return mStatusUpdateTime;
  1018. +    }
  1019. +
  1020. +    @Override
  1021. +    public boolean hasMonetaryCost() {
  1022. +        return false;
  1023. +    }
  1024. +
  1025. +    @Override
  1026. +    public boolean isEnabled() {
  1027. +        return mEnabled;
  1028. +    }
  1029. +
  1030. +
  1031. +    @Override
  1032. +    public boolean requestSingleShotFix() {
  1033. +        return false;
  1034. +    }
  1035. +
  1036. +    @Override
  1037. +    public boolean requiresCell() {
  1038. +        return false;
  1039. +    }
  1040. +
  1041. +    @Override
  1042. +    public boolean requiresNetwork() {
  1043. +        return false;
  1044. +    }
  1045. +
  1046. +    @Override
  1047. +    public boolean requiresSatellite() {
  1048. +        return true;
  1049. +    }
  1050. +
  1051. +    @Override
  1052. +    public boolean sendExtraCommand(String command, Bundle extras) {
  1053. +        if (TextUtils.isEmpty(command)) return false;
  1054. +        synchronized (mHandler) {
  1055. +            String customCommand = command + "\r\n";
  1056. +            sendMessage(GPS_CUSTOM_COMMAND, customCommand.length(), customComma
  1057. +        }
  1058. +        return true;
  1059. +    }
  1060. +
  1061. +    /* GPS scheduling stuff, not needed
  1062. +     * @see com.android.server.location.LocationProviderInterface#setMinTime(lo
  1063. +     */
  1064. +    @Override
  1065. +    public void setMinTime(long minTime, WorkSource ws) {
  1066. +
  1067. +    }
  1068. +
  1069. +    @Override
  1070. +    public boolean supportsAltitude() {
  1071. +        return mLocation.hasAltitude();
  1072. +    }
  1073. +
  1074. +    @Override
  1075. +    public boolean supportsBearing() {
  1076. +        return mLocation.hasBearing();
  1077. +    }
  1078. +
  1079. +    @Override
  1080. +    public boolean supportsSpeed() {
  1081. +        return mLocation.hasSpeed();
  1082. +    }
  1083. +
  1084. +    @Override
  1085. +    /**
  1086. +     * This is called to inform us when another location provider returns a loc
  1087. +     * Someday we might use this for network location injection to aid the GPS
  1088. +     */
  1089. +    public void updateLocation(Location location) {
  1090. +        sendMessage(UPDATE_LOCATION, 0, location);
  1091. +    }
  1092. +
  1093. +    private void handleUpdateLocation(Location location) {
  1094. +        if (location.hasAccuracy()) {
  1095. +            // Allow other provider GPS data ? discard for now
  1096. +        }
  1097. +    }
  1098. +
  1099. +    /* unneeded by BT GPS provider
  1100. +     * @see com.android.server.location.LocationProviderInterface#updateNetwork
  1101. +     */
  1102. +    @Override
  1103. +    public void updateNetworkState(int state, NetworkInfo info) {
  1104. +        // TODO Auto-generated method stub
  1105. +
  1106. +    }
  1107. +
  1108. +    /**
  1109. +     * @param loc   Location object representing the fix
  1110. +     * @param isValid   true if fix was valid
  1111. +     */
  1112. +    private void reportLocation(Location loc, boolean isValid) {
  1113. +
  1114. +        if (!isValid) {
  1115. +            if (mStatus == LocationProvider.AVAILABLE && mTTFF > 0) {
  1116. +                if (D) Log.d(TAG, "Invalid sat fix -> sending notification to s
  1117. +                // send an intent to notify that the GPS is no longer receiving
  1118. +                Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTIO
  1119. +                intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
  1120. +                mContext.sendBroadcast(intent);
  1121. +                updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount
  1122. +            }
  1123. +            return;
  1124. +        }
  1125. +
  1126. +        synchronized (mLocation) {
  1127. +            mLocation.set(loc);
  1128. +            mLocation.setProvider(this.getName());
  1129. +            if (D) {
  1130. +                Log.d(TAG, "reportLocation lat: " + mLocation.getLatitude() +
  1131. +                    " long: " + mLocation.getLongitude() + " alt: " + mLocation
  1132. +                    " accuracy: " + mLocation.getAccuracy() + " timestamp: " +
  1133. +            }
  1134. +            try {
  1135. +                mLocationManager.reportLocation(mLocation, false);
  1136. +            } catch (RemoteException e) {
  1137. +                Log.e(TAG, "RemoteException calling reportLocation");
  1138. +            }
  1139. +        }
  1140. +
  1141. +        mLastFixTime = System.currentTimeMillis();
  1142. +        // report time to first fix
  1143. +        if ((mTTFF == 0) && (isValid)) {
  1144. +            mTTFF = (int)(mLastFixTime - mFixRequestTime);
  1145. +            if (D) Log.d(TAG, "TTFF: " + mTTFF);
  1146. +
  1147. +            // notify status listeners
  1148. +            synchronized(mListeners) {
  1149. +                int size = mListeners.size();
  1150. +                for (int i = 0; i < size; i++) {
  1151. +                    Listener listener = mListeners.get(i);
  1152. +                    try {
  1153. +                        listener.mListener.onFirstFix(mTTFF);
  1154. +                    } catch (RemoteException e) {
  1155. +                        Log.w(TAG, "RemoteException in first fix notification")
  1156. +                        mListeners.remove(listener);
  1157. +                        // adjust for size of list changing
  1158. +                        size--;
  1159. +                    }
  1160. +                }
  1161. +            }
  1162. +        }
  1163. +
  1164. +        if (mStatus != LocationProvider.AVAILABLE) {
  1165. +            if (D) Log.d(TAG,"Notify that we're receiving fixes");
  1166. +            // send an intent to notify that the GPS is receiving fixes.
  1167. +            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
  1168. +            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
  1169. +            mContext.sendBroadcast(intent);
  1170. +            updateStatus(LocationProvider.AVAILABLE, mSvCount);
  1171. +        }
  1172. +
  1173. +    }
  1174. +
  1175. +    /* report sats status
  1176. +     */
  1177. +    private void reportSvStatus(int svCount, int mSvs[], float mSnrs[],
  1178. +            float mSvElevations[],  float mSvAzimuths[], int mSvMasks[]) {
  1179. +
  1180. +        if (D) Log.d(TAG,"About to report sat status svcount: " + svCount);
  1181. +        synchronized(mListeners) {
  1182. +            int size = mListeners.size();
  1183. +            for (int i = 0; i < size; i++) {
  1184. +                Listener listener = mListeners.get(i);
  1185. +                try {
  1186. +                    listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
  1187. +                            mSvAzimuths, mSvMasks[NMEAParser.EPHEMERIS_MASK],
  1188. +                            mSvMasks[NMEAParser.ALMANAC_MASK],
  1189. +                            mSvMasks[NMEAParser.USED_FOR_FIX_MASK]);
  1190. +                } catch (RemoteException e) {
  1191. +                    Log.w(TAG, "RemoteException in reportSvInfo");
  1192. +                    mListeners.remove(listener);
  1193. +                    // adjust for size of list changing
  1194. +                    size--;
  1195. +                }
  1196. +            }
  1197. +        }
  1198. +
  1199. +        // return number of sets used in fix instead of total
  1200. +        updateStatus(mStatus, Integer.bitCount(mSvMasks[NMEAParser.USED_FOR_FIX
  1201. +    }
  1202. +
  1203. +    /**
  1204. +     * Handles GPS status.
  1205. +     * will also inform listeners when GPS started/stopped
  1206. +     * @param status    new GPS status
  1207. +     */
  1208. +    private void notifyEnableDisableGPS(boolean status) {
  1209. +        if (D) Log.v(TAG, "notifyEnableDisableGPS status: " + status);
  1210. +
  1211. +        synchronized(mListeners) {
  1212. +            mNavigating = status;
  1213. +            int size = mListeners.size();
  1214. +            for (int i = 0; i < size; i++) {
  1215. +                Listener listener = mListeners.get(i);
  1216. +                try {
  1217. +                    if (status) {
  1218. +                        listener.mListener.onGpsStarted();
  1219. +                    } else {
  1220. +                        listener.mListener.onGpsStopped();
  1221. +                    }
  1222. +                } catch (RemoteException e) {
  1223. +                    Log.w(TAG, "RemoteException in reportStatus");
  1224. +                    mListeners.remove(listener);
  1225. +                    // adjust for size of list changing
  1226. +                    size--;
  1227. +                }
  1228. +            }
  1229. +            try {
  1230. +                // update battery stats
  1231. +                for (int i=mClientUids.size() - 1; i >= 0; i--) {
  1232. +                    int uid = mClientUids.keyAt(i);
  1233. +                    if (mNavigating) {
  1234. +                        mBatteryStats.noteStartGps(uid);
  1235. +                    } else {
  1236. +                        mBatteryStats.noteStopGps(uid);
  1237. +                    }
  1238. +                }
  1239. +            } catch (RemoteException e) {
  1240. +                Log.w(TAG, "RemoteException in reportStatus");
  1241. +            }
  1242. +            // send an intent to notify that the GPS has been enabled or disabl
  1243. +            Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTIO
  1244. +            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, status);
  1245. +            mContext.sendBroadcast(intent);
  1246. +        }
  1247. +        try {
  1248. +            if (D) Log.d(TAG, "Setting System GPS status to " + status);
  1249. +            Settings.Secure.setLocationProviderEnabled(mContext.getContentResol
  1250. +                    LocationManager.GPS_PROVIDER, status);
  1251. +        } catch (Exception e) {
  1252. +            Log.e(TAG, e.getMessage());
  1253. +        }
  1254. +    }
  1255. +
  1256. +    /**
  1257. +     * sends nmea sentences to NMEA parsers. Some apps use raw nmea data
  1258. +     * @param nmeaString    nmea string
  1259. +     * @param timestamp     time stamp
  1260. +     */
  1261. +    private void reportNmea(String nmeaString, long timestamp) {
  1262. +        synchronized(mListeners) {
  1263. +            int size = mListeners.size();
  1264. +            if (size > 0) {
  1265. +                // don't bother creating the String if we have no listeners
  1266. +                for (int i = 0; i < size; i++) {
  1267. +                    Listener listener = mListeners.get(i);
  1268. +                    try {
  1269. +                        listener.mListener.onNmeaReceived(timestamp, nmeaString
  1270. +                    } catch (RemoteException e) {
  1271. +                        Log.w(TAG, "RemoteException in reportNmea");
  1272. +                        mListeners.remove(listener);
  1273. +                        // adjust for size of list changing
  1274. +                        size--;
  1275. +                    }
  1276. +                }
  1277. +            }
  1278. +        }
  1279. +    }
  1280. +
  1281. +    /**
  1282. +     * This methods parses the nmea sentences and sends the location updates
  1283. +     * and sats updates to listeners.
  1284. +     * @param sentences     raw nmea sentences received by BT GPS Mouse
  1285. +     */
  1286. +    private void handleNMEAMessages(String sentences) {
  1287. +        String sentenceArray[] = sentences.split("\r\n");
  1288. +        nmeaparser.reset();
  1289. +        for (int i = 0; i < sentenceArray.length; i++) {
  1290. +            if (D) Log.d(TAG, "About to parse: " + sentenceArray[i]);
  1291. +            if ((sentenceArray[i] != null) && ("".equals(sentenceArray[i]))) co
  1292. +            boolean parsed = nmeaparser.parseNMEALine(sentenceArray[i]);
  1293. +            // handle nmea message. Also report messages that we could not pars
  1294. +            // might be propriatery messages that other listeners could support
  1295. +            reportNmea(sentenceArray[i], System.currentTimeMillis());
  1296. +        }
  1297. +        Location loc = nmeaparser.getLocation();
  1298. +        // handle location update if valid
  1299. +        reportLocation(loc , nmeaparser.isValid());
  1300. +        if (nmeaparser.isSatdataReady()) {
  1301. +            reportSvStatus(nmeaparser.getmSvCount(), nmeaparser.getmSvs(), nmea
  1302. +                nmeaparser.getmSvElevations(), nmeaparser.getmSvAzimuths(),
  1303. +                nmeaparser.getmSvMasks());
  1304. +        }
  1305. +
  1306. +        // adjust refresh rate based on received timestamp of mouse
  1307. +        // min 1hz and max 10 hz
  1308. +        long newRate = nmeaparser.getApproximatedRefreshRate();
  1309. +        if (btsvc.getRefreshRate() != newRate) {
  1310. +            if (D) Log.d(TAG, "Setting refresh rate to: " + newRate
  1311. +                    + " was: " + btsvc.getRefreshRate());
  1312. +            btsvc.setRefreshRate(newRate);
  1313. +        }
  1314. +    }
  1315. +
  1316. +
  1317. +    /*
  1318. +     * Stuff below is taken from the android GPS location provider.
  1319. +     * Does handling of messages/listeners and so on.
  1320. +     */
  1321. +
  1322. +    private void sendMessage(int message, int arg, Object obj) {
  1323. +        // hold a wake lock while messages are pending
  1324. +        synchronized (mWakeLock) {
  1325. +            mPendingMessageBits |= (1 << message);
  1326. +            mWakeLock.acquire();
  1327. +            mHandler.removeMessages(message);
  1328. +            Message m = Message.obtain(mHandler, message);
  1329. +            m.arg1 = arg;
  1330. +            m.obj = obj;
  1331. +            mHandler.sendMessage(m);
  1332. +        }
  1333. +    }
  1334. +
  1335. +
  1336. +    private void updateStatus(int status, int svCount) {
  1337. +        if (status != mStatus || svCount != mSvCount) {
  1338. +            mStatus = status;
  1339. +            mSvCount = svCount;
  1340. +            mLocationExtras.putInt("satellites", svCount);
  1341. +            mStatusUpdateTime = SystemClock.elapsedRealtime();
  1342. +        }
  1343. +    }
  1344. +    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
  1345. +
  1346. +    private final class Listener implements IBinder.DeathRecipient {
  1347. +        final IGpsStatusListener mListener;
  1348. +
  1349. +        Listener(IGpsStatusListener listener) {
  1350. +            mListener = listener;
  1351. +        }
  1352. +
  1353. +        public void binderDied() {
  1354. +            if (D) Log.d(TAG, "GPS status listener died");
  1355. +
  1356. +            synchronized(mListeners) {
  1357. +                mListeners.remove(this);
  1358. +            }
  1359. +            if (mListener != null) {
  1360. +                mListener.asBinder().unlinkToDeath(this, 0);
  1361. +            }
  1362. +        }
  1363. +    }
  1364. +
  1365. +
  1366. +    private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvide
  1367. +        public void addGpsStatusListener(IGpsStatusListener listener) throws Re
  1368. +            if (listener == null) {
  1369. +                throw new NullPointerException("listener is null in addGpsStatu
  1370. +            }
  1371. +            synchronized(mListeners) {
  1372. +                IBinder binder = listener.asBinder();
  1373. +                int size = mListeners.size();
  1374. +                for (int i = 0; i < size; i++) {
  1375. +                    Listener test = mListeners.get(i);
  1376. +                    if (binder.equals(test.mListener.asBinder())) {
  1377. +                        // listener already added
  1378. +                        return;
  1379. +                    }
  1380. +                }
  1381. +                Listener l = new Listener(listener);
  1382. +                binder.linkToDeath(l, 0);
  1383. +                mListeners.add(l);
  1384. +            }
  1385. +        }
  1386. +
  1387. +        public void removeGpsStatusListener(IGpsStatusListener listener) {
  1388. +            if (listener == null) {
  1389. +                throw new NullPointerException("listener is null in addGpsStatu
  1390. +            }
  1391. +
  1392. +            synchronized(mListeners) {
  1393. +                IBinder binder = listener.asBinder();
  1394. +                Listener l = null;
  1395. +                int size = mListeners.size();
  1396. +                for (int i = 0; i < size && l == null; i++) {
  1397. +                    Listener test = mListeners.get(i);
  1398. +                    if (binder.equals(test.mListener.asBinder())) {
  1399. +                        l = test;
  1400. +                    }
  1401. +                }
  1402. +
  1403. +                if (l != null) {
  1404. +                    mListeners.remove(l);
  1405. +                    binder.unlinkToDeath(l, 0);
  1406. +                }
  1407. +            }
  1408. +        }
  1409. +    };
  1410. +
  1411. +    public IGpsStatusProvider getGpsStatusProvider() {
  1412. +        return mGpsStatusProvider;
  1413. +    }
  1414. +
  1415. +    public void addListener(int uid) {
  1416. +        synchronized (mWakeLock) {
  1417. +            mPendingListenerMessages++;
  1418. +            mWakeLock.acquire();
  1419. +            Message m = Message.obtain(mHandler, ADD_LISTENER);
  1420. +            m.arg1 = uid;
  1421. +            mHandler.sendMessage(m);
  1422. +        }
  1423. +    }
  1424. +
  1425. +    private void handleAddListener(int uid) {
  1426. +        synchronized(mListeners) {
  1427. +            if (mClientUids.indexOfKey(uid) >= 0) {
  1428. +                // Shouldn't be here -- already have this uid.
  1429. +                Log.w(TAG, "Duplicate add listener for uid " + uid);
  1430. +                return;
  1431. +            }
  1432. +            mClientUids.put(uid, 0);
  1433. +            if (mNavigating) {
  1434. +                try {
  1435. +                    mBatteryStats.noteStartGps(uid);
  1436. +                } catch (RemoteException e) {
  1437. +                    Log.w(TAG, "RemoteException in addListener");
  1438. +                }
  1439. +            }
  1440. +        }
  1441. +    }
  1442. +
  1443. +    public void removeListener(int uid) {
  1444. +        synchronized (mWakeLock) {
  1445. +            mPendingListenerMessages++;
  1446. +            mWakeLock.acquire();
  1447. +            Message m = Message.obtain(mHandler, REMOVE_LISTENER);
  1448. +            m.arg1 = uid;
  1449. +            mHandler.sendMessage(m);
  1450. +        }
  1451. +    }
  1452. +
  1453. +    private void handleRemoveListener(int uid) {
  1454. +        synchronized(mListeners) {
  1455. +            if (mClientUids.indexOfKey(uid) < 0) {
  1456. +                // Shouldn't be here -- don't have this uid.
  1457. +                Log.w(TAG, "Unneeded remove listener for uid " + uid);
  1458. +                return;
  1459. +            }
  1460. +            mClientUids.delete(uid);
  1461. +            if (mNavigating) {
  1462. +                try {
  1463. +                    mBatteryStats.noteStopGps(uid);
  1464. +                } catch (RemoteException e) {
  1465. +                    Log.w(TAG, "RemoteException in removeListener");
  1466. +                }
  1467. +            }
  1468. +        }
  1469. +    }
  1470. +}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement