merge from open-source master
This commit is contained in:
10
tests/LocationTracker/Android.mk
Normal file
10
tests/LocationTracker/Android.mk
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := LocationTracker
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
30
tests/LocationTracker/AndroidManifest.xml
Normal file
30
tests/LocationTracker/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.locationtracker">
|
||||||
|
|
||||||
|
<!-- Permissions for the Location Service -->
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
|
||||||
|
<!-- Permission for wifi -->
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
|
||||||
|
<!-- give the location tracker ability to induce device insomnia -->
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
|
<!-- Permission for SD card -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<application android:label="@string/app_label">
|
||||||
|
<activity android:name="TrackerActivity" android:label="Location Tracker">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<service android:name=".TrackerService" />
|
||||||
|
<activity android:label="@string/settings_menu" android:name="SettingsActivity" />
|
||||||
|
<provider android:name=".data.TrackerProvider"
|
||||||
|
android:authorities="com.android.locationtracker" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
25
tests/LocationTracker/res/layout/entrylist_item.xml
Normal file
25
tests/LocationTracker/res/layout/entrylist_item.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/entrylist_item"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
/>
|
||||||
37
tests/LocationTracker/res/menu/menu.xml
Normal file
37
tests/LocationTracker/res/menu/menu.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@+id/start_service_menu"
|
||||||
|
android:title="@string/start_service_menu" />
|
||||||
|
<item android:id="@+id/stop_service_menu"
|
||||||
|
android:title="@string/stop_service_menu" />
|
||||||
|
<item android:id="@+id/settings_menu"
|
||||||
|
android:title="@string/settings_menu" />
|
||||||
|
<item android:id="@+id/export_sub_menu"
|
||||||
|
android:title="@string/export_sub_menu">
|
||||||
|
<menu>
|
||||||
|
<item android:id="@+id/export_kml"
|
||||||
|
android:title="@string/export_kml" />
|
||||||
|
<item android:id="@+id/export_csv"
|
||||||
|
android:title="@string/export_csv" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
<item android:title="@string/clear_data"
|
||||||
|
android:id="@+id/clear_data_menu"/>
|
||||||
|
</menu>
|
||||||
48
tests/LocationTracker/res/values/strings.xml
Normal file
48
tests/LocationTracker/res/values/strings.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="start_service_menu">Start Service</string>
|
||||||
|
<string name="stop_service_menu">Stop Service</string>
|
||||||
|
<string name="settings_menu">Settings</string>
|
||||||
|
<string name="update_preference">Update frequency</string>
|
||||||
|
<string name="title_mintime_preference">Minimum update time</string>
|
||||||
|
<string name="summary_mintime_preference">The suggested minimum time interval for location updates, in seconds</string>
|
||||||
|
<string name="dialog_title_mintime_preference">Minimum update time</string>
|
||||||
|
<string name="title_mindistance_preference">Minimum distance</string>
|
||||||
|
<string name="summary_mindistance_preference">Minimum distance interval for location updates, in meters</string>
|
||||||
|
<string name="dialog_title_mindistance_preference">Minimum distance</string>
|
||||||
|
<string name="provider_preferences">Location providers</string>
|
||||||
|
<string name="title_network_preference">Network location</string>
|
||||||
|
<string name="summary_network_preference">Listen for updates to network location (Wi-Fi/cellid)</string>
|
||||||
|
<string name="title_gps_preference">GPS location</string>
|
||||||
|
<string name="summary_gps_preference">Listen for updates to GPS location</string>
|
||||||
|
<string name="title_signal_preference">Signal strength</string>
|
||||||
|
<string name="summary_signal_preference">Listen for updates to signal strength</string>
|
||||||
|
<string name="advanced_preferences">Advanced</string>
|
||||||
|
<string name="title_advanced_log_preference">Location debug logging</string>
|
||||||
|
<string name="summary_advanced_preference">Logs detailed location data, only relevant for location/test engineers</string>
|
||||||
|
<string name="app_label">Location Tracker</string>
|
||||||
|
<string name="export_sub_menu">Export\u2026</string>
|
||||||
|
<string name="export_kml">Export As KML</string>
|
||||||
|
<string name="export_csv">Export As CSV</string>
|
||||||
|
<string name="clear_data">Clear data</string>
|
||||||
|
<string name="delete_confirm">All current tracking data will be deleted.</string>
|
||||||
|
<string name="confirm_title">Clear data</string>
|
||||||
|
</resources>
|
||||||
63
tests/LocationTracker/res/xml/preferences.xml
Executable file
63
tests/LocationTracker/res/xml/preferences.xml
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- The Location preferences UI -->
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/update_preference">
|
||||||
|
<EditTextPreference android:key="mintime_preference"
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:title="@string/title_mintime_preference"
|
||||||
|
android:summary="@string/summary_mintime_preference"
|
||||||
|
android:dialogTitle="@string/dialog_title_mintime_preference" />
|
||||||
|
|
||||||
|
<EditTextPreference android:key="mindistance_preference"
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:title="@string/title_mindistance_preference"
|
||||||
|
android:summary="@string/summary_mindistance_preference"
|
||||||
|
android:dialogTitle="@string/dialog_title_mindistance_preference" />
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/provider_preferences">
|
||||||
|
|
||||||
|
<CheckBoxPreference android:key="network_preference"
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:title="@string/title_network_preference"
|
||||||
|
android:summary="@string/summary_network_preference" />
|
||||||
|
|
||||||
|
<CheckBoxPreference android:key="gps_preference"
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:title="@string/title_gps_preference"
|
||||||
|
android:summary="@string/summary_gps_preference" />
|
||||||
|
|
||||||
|
<CheckBoxPreference android:key="signal_preference"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:title="@string/title_signal_preference"
|
||||||
|
android:summary="@string/summary_signal_preference" />
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/advanced_preferences">
|
||||||
|
|
||||||
|
<CheckBoxPreference android:key="advanced_log_preference"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:title="@string/title_advanced_log_preference"
|
||||||
|
android:summary="@string/summary_advanced_preference" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
35
tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
Executable file
35
tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings preference screen for location tracker
|
||||||
|
*/
|
||||||
|
public class SettingsActivity extends PreferenceActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// Load the preferences from an XML resource
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker;
|
||||||
|
|
||||||
|
import com.android.locationtracker.data.DateUtils;
|
||||||
|
import com.android.locationtracker.data.TrackerDataHelper;
|
||||||
|
import com.android.locationtracker.data.TrackerListHelper;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity for location tracker service
|
||||||
|
*
|
||||||
|
* Contains facilities for starting and
|
||||||
|
* stopping location tracker service, as well as displaying the current location
|
||||||
|
* data
|
||||||
|
*
|
||||||
|
* Future enhancements:
|
||||||
|
* - export data as dB
|
||||||
|
* - enable/disable "start service" and "stop service" menu items as
|
||||||
|
* appropriate
|
||||||
|
*/
|
||||||
|
public class TrackerActivity extends ListActivity {
|
||||||
|
|
||||||
|
static final String LOG_TAG = "LocationTracker";
|
||||||
|
|
||||||
|
private TrackerListHelper mDataHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves and displays the currently logged location data from file
|
||||||
|
*
|
||||||
|
* @param icicle
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
mDataHelper = new TrackerListHelper(this);
|
||||||
|
mDataHelper.bindListUI(R.layout.entrylist_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the menu
|
||||||
|
*
|
||||||
|
* @param menu - menu to add items to
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater menuInflater = getMenuInflater();
|
||||||
|
menuInflater.inflate(R.menu.menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles menu item selection
|
||||||
|
*
|
||||||
|
* @param item - the selected menu item
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.start_service_menu: {
|
||||||
|
startService(new Intent(TrackerActivity.this,
|
||||||
|
TrackerService.class));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case R.id.stop_service_menu: {
|
||||||
|
stopService(new Intent(TrackerActivity.this,
|
||||||
|
TrackerService.class));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case R.id.settings_menu: {
|
||||||
|
launchSettings();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case R.id.export_kml: {
|
||||||
|
exportKML();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case R.id.export_csv: {
|
||||||
|
exportCSV();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case R.id.clear_data_menu: {
|
||||||
|
clearData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearData() {
|
||||||
|
Runnable clearAction = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
TrackerDataHelper helper =
|
||||||
|
new TrackerDataHelper(TrackerActivity.this);
|
||||||
|
helper.deleteAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
showConfirm(R.string.delete_confirm, clearAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showConfirm(int textId, final Runnable onConfirmAction) {
|
||||||
|
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
dialogBuilder.setTitle(R.string.confirm_title);
|
||||||
|
dialogBuilder.setMessage(textId);
|
||||||
|
dialogBuilder.setPositiveButton(android.R.string.ok,
|
||||||
|
new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
onConfirmAction.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogBuilder.setNegativeButton(android.R.string.cancel,
|
||||||
|
new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogBuilder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportCSV() {
|
||||||
|
String exportFileName = getUniqueFileName("csv");
|
||||||
|
exportFile(null, exportFileName, new TrackerDataHelper(this,
|
||||||
|
TrackerDataHelper.CSV_FORMATTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportKML() {
|
||||||
|
String exportFileName = getUniqueFileName(
|
||||||
|
LocationManager.NETWORK_PROVIDER + ".kml");
|
||||||
|
exportFile(LocationManager.NETWORK_PROVIDER, exportFileName,
|
||||||
|
new TrackerDataHelper(this, TrackerDataHelper.KML_FORMATTER));
|
||||||
|
exportFileName = getUniqueFileName(
|
||||||
|
LocationManager.GPS_PROVIDER + ".kml");
|
||||||
|
exportFile(LocationManager.GPS_PROVIDER, exportFileName,
|
||||||
|
new TrackerDataHelper(this, TrackerDataHelper.KML_FORMATTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportFile(String tagFilter,
|
||||||
|
String exportFileName,
|
||||||
|
TrackerDataHelper trackerData) {
|
||||||
|
BufferedWriter exportWriter = null;
|
||||||
|
Cursor cursor = trackerData.query(tagFilter);
|
||||||
|
try {
|
||||||
|
exportWriter = new BufferedWriter(new FileWriter(exportFileName));
|
||||||
|
exportWriter.write(trackerData.getOutputHeader());
|
||||||
|
|
||||||
|
String line = null;
|
||||||
|
|
||||||
|
while ((line = trackerData.getNextOutput(cursor)) != null) {
|
||||||
|
exportWriter.write(line);
|
||||||
|
}
|
||||||
|
exportWriter.write(trackerData.getOutputFooter());
|
||||||
|
Toast.makeText(this, "Successfully exported data to " +
|
||||||
|
exportFileName, Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(this, "Error exporting file: " +
|
||||||
|
e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
Log.e(LOG_TAG, "Error exporting file", e);
|
||||||
|
} finally {
|
||||||
|
closeWriter(exportWriter);
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeWriter(Writer exportWriter) {
|
||||||
|
if (exportWriter != null) {
|
||||||
|
try {
|
||||||
|
exportWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(LOG_TAG, "error closing file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUniqueFileName(String ext) {
|
||||||
|
File dir = new File("/sdcard/locationtracker");
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdir();
|
||||||
|
}
|
||||||
|
return "/sdcard/locationtracker/tracking-" +
|
||||||
|
DateUtils.getCurrentTimestamp() + "." + ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchSettings() {
|
||||||
|
Intent settingsIntent = new Intent();
|
||||||
|
settingsIntent.setClass(this, SettingsActivity.class);
|
||||||
|
startActivity(settingsIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker;
|
||||||
|
|
||||||
|
import com.android.locationtracker.data.TrackerDataHelper;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.wifi.ScanResult;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.telephony.CellLocation;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.SignalStrength;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.telephony.cdma.CdmaCellLocation;
|
||||||
|
import android.telephony.gsm.GsmCellLocation;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Location Tracking service
|
||||||
|
*
|
||||||
|
* Records location updates for all registered location providers, and cell
|
||||||
|
* location updates
|
||||||
|
*/
|
||||||
|
public class TrackerService extends Service {
|
||||||
|
|
||||||
|
private List<LocationTrackingListener> mListeners;
|
||||||
|
|
||||||
|
private static final String LOG_TAG = TrackerActivity.LOG_TAG;
|
||||||
|
|
||||||
|
// controls which location providers to track
|
||||||
|
private Set<String> mTrackedProviders;
|
||||||
|
|
||||||
|
private TrackerDataHelper mTrackerData;
|
||||||
|
|
||||||
|
private TelephonyManager mTelephonyManager;
|
||||||
|
private Location mNetworkLocation;
|
||||||
|
|
||||||
|
// Handlers and Receivers for phone and network state
|
||||||
|
private NetworkStateBroadcastReceiver mNetwork;
|
||||||
|
private static final String CELL_PROVIDER_TAG = "cell";
|
||||||
|
// signal strength updates
|
||||||
|
private static final String SIGNAL_PROVIDER_TAG = "signal";
|
||||||
|
private static final String WIFI_PROVIDER_TAG = "wifi";
|
||||||
|
// tracking tag for data connectivity issues
|
||||||
|
private static final String DATA_CONN_PROVIDER_TAG = "data";
|
||||||
|
|
||||||
|
// preference constants
|
||||||
|
private static final String MIN_TIME_PREF = "mintime_preference";
|
||||||
|
private static final String MIN_DIS_PREF = "mindistance_preference";
|
||||||
|
private static final String GPS_PREF = "gps_preference";
|
||||||
|
private static final String NETWORK_PREF = "network_preference";
|
||||||
|
private static final String SIGNAL_PREF = "signal_preference";
|
||||||
|
private static final String DEBUG_PREF = "advanced_log_preference";
|
||||||
|
|
||||||
|
private PreferenceListener mPrefListener;
|
||||||
|
|
||||||
|
public TrackerService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
// ignore - nothing to do
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registers location listeners
|
||||||
|
*
|
||||||
|
* @param intent
|
||||||
|
* @param startId
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onStart(Intent intent, int startId) {
|
||||||
|
super.onStart(intent, startId);
|
||||||
|
mNetworkLocation = null;
|
||||||
|
|
||||||
|
initLocationListeners();
|
||||||
|
Toast.makeText(this, "Tracking service started", Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void initLocationListeners() {
|
||||||
|
mTrackerData = new TrackerDataHelper(this);
|
||||||
|
LocationManager lm = getLocationManager();
|
||||||
|
|
||||||
|
mTrackedProviders = getTrackedProviders();
|
||||||
|
|
||||||
|
List<String> locationProviders = lm.getAllProviders();
|
||||||
|
mListeners = new ArrayList<LocationTrackingListener>(
|
||||||
|
locationProviders.size());
|
||||||
|
|
||||||
|
long minUpdateTime = getLocationUpdateTime();
|
||||||
|
float minDistance = getLocationMinDistance();
|
||||||
|
|
||||||
|
for (String providerName : locationProviders) {
|
||||||
|
if (mTrackedProviders.contains(providerName)) {
|
||||||
|
Log.d(LOG_TAG, "Adding location listener for provider " +
|
||||||
|
providerName);
|
||||||
|
if (doDebugLogging()) {
|
||||||
|
mTrackerData.writeEntry("init", String.format(
|
||||||
|
"start listening to %s : %d ms; %f meters",
|
||||||
|
providerName, minUpdateTime, minDistance));
|
||||||
|
}
|
||||||
|
LocationTrackingListener listener =
|
||||||
|
new LocationTrackingListener();
|
||||||
|
lm.requestLocationUpdates(providerName, minUpdateTime,
|
||||||
|
minDistance, listener);
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
|
||||||
|
if (doDebugLogging()) {
|
||||||
|
// register for cell location updates
|
||||||
|
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION);
|
||||||
|
|
||||||
|
// Register for Network (Wifi or Mobile) updates
|
||||||
|
mNetwork = new NetworkStateBroadcastReceiver();
|
||||||
|
IntentFilter mIntentFilter;
|
||||||
|
mIntentFilter = new IntentFilter();
|
||||||
|
mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
|
||||||
|
mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||||
|
mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
|
Log.d(LOG_TAG, "registering receiver");
|
||||||
|
registerReceiver(mNetwork, mIntentFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trackSignalStrength()) {
|
||||||
|
mTelephonyManager.listen(mPhoneStateListener,
|
||||||
|
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// register for preference changes, so we can restart listeners on
|
||||||
|
// pref changes
|
||||||
|
mPrefListener = new PreferenceListener();
|
||||||
|
getPreferences().registerOnSharedPreferenceChangeListener(mPrefListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getTrackedProviders() {
|
||||||
|
Set<String> providerSet = new HashSet<String>();
|
||||||
|
|
||||||
|
if (trackGPS()) {
|
||||||
|
providerSet.add(LocationManager.GPS_PROVIDER);
|
||||||
|
}
|
||||||
|
if (trackNetwork()) {
|
||||||
|
providerSet.add(LocationManager.NETWORK_PROVIDER);
|
||||||
|
}
|
||||||
|
return providerSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SharedPreferences getPreferences() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean trackNetwork() {
|
||||||
|
return getPreferences().getBoolean(NETWORK_PREF, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean trackGPS() {
|
||||||
|
return getPreferences().getBoolean(GPS_PREF, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doDebugLogging() {
|
||||||
|
return getPreferences().getBoolean(DEBUG_PREF, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean trackSignalStrength() {
|
||||||
|
return getPreferences().getBoolean(SIGNAL_PREF, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getLocationMinDistance() {
|
||||||
|
try {
|
||||||
|
String disString = getPreferences().getString(MIN_DIS_PREF, "0");
|
||||||
|
return Float.parseFloat(disString);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
Log.e(LOG_TAG, "Invalid preference for location min distance", e);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getLocationUpdateTime() {
|
||||||
|
try {
|
||||||
|
String timeString = getPreferences().getString(MIN_TIME_PREF, "0");
|
||||||
|
long secondsTime = Long.valueOf(timeString);
|
||||||
|
return secondsTime * 1000;
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
Log.e(LOG_TAG, "Invalid preference for location min time", e);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuts down this service
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
Log.d(LOG_TAG, "Removing location listeners");
|
||||||
|
stopListeners();
|
||||||
|
Toast.makeText(this, "Tracking service stopped", Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* De-registers all location listeners, closes persistent storage
|
||||||
|
*/
|
||||||
|
protected synchronized void stopListeners() {
|
||||||
|
LocationManager lm = getLocationManager();
|
||||||
|
if (mListeners != null) {
|
||||||
|
for (LocationTrackingListener listener : mListeners) {
|
||||||
|
lm.removeUpdates(listener);
|
||||||
|
}
|
||||||
|
mListeners.clear();
|
||||||
|
}
|
||||||
|
mListeners = null;
|
||||||
|
|
||||||
|
// stop cell state listener
|
||||||
|
if (mTelephonyManager != null) {
|
||||||
|
mTelephonyManager.listen(mPhoneStateListener, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop network/wifi listener
|
||||||
|
if (mNetwork != null) {
|
||||||
|
unregisterReceiver(mNetwork);
|
||||||
|
}
|
||||||
|
mNetwork = null;
|
||||||
|
|
||||||
|
mTrackerData = null;
|
||||||
|
if (mPrefListener != null) {
|
||||||
|
getPreferences().unregisterOnSharedPreferenceChangeListener(mPrefListener);
|
||||||
|
mPrefListener = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocationManager getLocationManager() {
|
||||||
|
return (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the current distance from given location to the last
|
||||||
|
* approximated network location
|
||||||
|
*
|
||||||
|
* @param location - new location
|
||||||
|
*
|
||||||
|
* @return float distance in meters
|
||||||
|
*/
|
||||||
|
private synchronized float getDistanceFromNetwork(Location location) {
|
||||||
|
float value = 0;
|
||||||
|
if (mNetworkLocation != null) {
|
||||||
|
value = location.distanceTo(mNetworkLocation);
|
||||||
|
}
|
||||||
|
if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
|
||||||
|
mNetworkLocation = location;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LocationTrackingListener implements LocationListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes details of location update to tracking file, including
|
||||||
|
* recording the distance between this location update and the last
|
||||||
|
* network location update
|
||||||
|
*
|
||||||
|
* @param location - new location
|
||||||
|
*/
|
||||||
|
public void onLocationChanged(Location location) {
|
||||||
|
if (location == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float distance = getDistanceFromNetwork(location);
|
||||||
|
mTrackerData.writeEntry(location, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes update to tracking file
|
||||||
|
*
|
||||||
|
* @param provider - name of disabled provider
|
||||||
|
*/
|
||||||
|
public void onProviderDisabled(String provider) {
|
||||||
|
if (doDebugLogging()) {
|
||||||
|
mTrackerData.writeEntry(provider, "provider disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes update to tracking file
|
||||||
|
*
|
||||||
|
* @param provider - name of enabled provider
|
||||||
|
*/
|
||||||
|
public void onProviderEnabled(String provider) {
|
||||||
|
if (doDebugLogging()) {
|
||||||
|
mTrackerData.writeEntry(provider, "provider enabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes update to tracking file
|
||||||
|
*
|
||||||
|
* @param provider - name of provider whose status changed
|
||||||
|
* @param status - new status
|
||||||
|
* @param extras - optional set of extra status messages
|
||||||
|
*/
|
||||||
|
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||||
|
if (doDebugLogging()) {
|
||||||
|
mTrackerData.writeEntry(provider, "status change: " + status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onCellLocationChanged(CellLocation location) {
|
||||||
|
try {
|
||||||
|
if (location instanceof GsmCellLocation) {
|
||||||
|
GsmCellLocation cellLocation = (GsmCellLocation)location;
|
||||||
|
String updateMsg = "cid=" + cellLocation.getCid() +
|
||||||
|
", lac=" + cellLocation.getLac();
|
||||||
|
mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg);
|
||||||
|
} else if (location instanceof CdmaCellLocation) {
|
||||||
|
CdmaCellLocation cellLocation = (CdmaCellLocation)location;
|
||||||
|
String updateMsg = "BID=" + cellLocation.getBaseStationId() +
|
||||||
|
", SID=" + cellLocation.getSystemId() +
|
||||||
|
", NID=" + cellLocation.getNetworkId() +
|
||||||
|
", lat=" + cellLocation.getBaseStationLatitude() +
|
||||||
|
", long=" + cellLocation.getBaseStationLongitude() +
|
||||||
|
", SID=" + cellLocation.getSystemId() +
|
||||||
|
", NID=" + cellLocation.getNetworkId();
|
||||||
|
mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOG_TAG, "Exception in CellStateHandler.handleMessage:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
|
||||||
|
if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
|
||||||
|
String updateMsg = "cdma dBM=" + signalStrength.getCdmaDbm();
|
||||||
|
mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg);
|
||||||
|
} else if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
|
||||||
|
String updateMsg = "gsm signal=" + signalStrength.getGsmSignalStrength();
|
||||||
|
mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener + recorder for mobile or wifi updates
|
||||||
|
*/
|
||||||
|
private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
|
||||||
|
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
|
||||||
|
WifiManager wifiManager =
|
||||||
|
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
List<ScanResult> wifiScanResults = wifiManager.getScanResults();
|
||||||
|
String updateMsg = "num scan results=" +
|
||||||
|
(wifiScanResults == null ? "0" : wifiScanResults.size());
|
||||||
|
mTrackerData.writeEntry(WIFI_PROVIDER_TAG, updateMsg);
|
||||||
|
|
||||||
|
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||||
|
String updateMsg;
|
||||||
|
boolean noConnectivity =
|
||||||
|
intent.getBooleanExtra(
|
||||||
|
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
|
||||||
|
if (noConnectivity) {
|
||||||
|
updateMsg = "no connectivity";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updateMsg = "connection available";
|
||||||
|
}
|
||||||
|
mTrackerData.writeEntry(DATA_CONN_PROVIDER_TAG, updateMsg);
|
||||||
|
|
||||||
|
} else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
|
||||||
|
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
|
||||||
|
WifiManager.WIFI_STATE_UNKNOWN);
|
||||||
|
|
||||||
|
String stateString = "unknown";
|
||||||
|
switch (state) {
|
||||||
|
case WifiManager.WIFI_STATE_DISABLED:
|
||||||
|
stateString = "disabled";
|
||||||
|
break;
|
||||||
|
case WifiManager.WIFI_STATE_DISABLING:
|
||||||
|
stateString = "disabling";
|
||||||
|
break;
|
||||||
|
case WifiManager.WIFI_STATE_ENABLED:
|
||||||
|
stateString = "enabled";
|
||||||
|
break;
|
||||||
|
case WifiManager.WIFI_STATE_ENABLING:
|
||||||
|
stateString = "enabling";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mTrackerData.writeEntry(WIFI_PROVIDER_TAG,
|
||||||
|
"state = " + stateString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PreferenceListener implements OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
public void onSharedPreferenceChanged(
|
||||||
|
SharedPreferences sharedPreferences, String key) {
|
||||||
|
Log.d(LOG_TAG, "restarting listeners due to preference change");
|
||||||
|
synchronized (TrackerService.this) {
|
||||||
|
stopListeners();
|
||||||
|
initLocationListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import com.android.locationtracker.data.TrackerEntry.EntryType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats tracker data as CSV output
|
||||||
|
*/
|
||||||
|
class CSVFormatter implements IFormatter {
|
||||||
|
|
||||||
|
private static final String DELIMITER = ", ";
|
||||||
|
|
||||||
|
public String getHeader() {
|
||||||
|
StringBuilder csvBuilder = new StringBuilder();
|
||||||
|
for (String col : TrackerEntry.ATTRIBUTES) {
|
||||||
|
// skip type and id column
|
||||||
|
if (!TrackerEntry.ENTRY_TYPE.equals(col) &&
|
||||||
|
!TrackerEntry.ID_COL.equals(col)) {
|
||||||
|
csvBuilder.append(col);
|
||||||
|
csvBuilder.append(DELIMITER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csvBuilder.append("\n");
|
||||||
|
return csvBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutput(TrackerEntry entry) {
|
||||||
|
StringBuilder rowOutput = new StringBuilder();
|
||||||
|
// these must match order of columns added in getHeader
|
||||||
|
rowOutput.append(entry.getTimestamp());
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
rowOutput.append(entry.getTag());
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
//rowOutput.append(entry.getType());
|
||||||
|
//rowOutput.append(DELIMITER);
|
||||||
|
if (entry.getType() == EntryType.LOCATION_TYPE) {
|
||||||
|
if (entry.getLocation().hasAccuracy()) {
|
||||||
|
rowOutput.append(entry.getLocation().getAccuracy());
|
||||||
|
}
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
rowOutput.append(entry.getLocation().getLatitude());
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
rowOutput.append(entry.getLocation().getLongitude());
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
if (entry.getLocation().hasAltitude()) {
|
||||||
|
rowOutput.append(entry.getLocation().getAltitude());
|
||||||
|
}
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
if (entry.getLocation().hasSpeed()) {
|
||||||
|
rowOutput.append(entry.getLocation().getSpeed());
|
||||||
|
}
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
if (entry.getLocation().hasBearing()) {
|
||||||
|
rowOutput.append(entry.getLocation().getBearing());
|
||||||
|
}
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
rowOutput.append(entry.getDistFromNetLocation());
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
rowOutput.append(DateUtils.getKMLTimestamp(entry.getLocation()
|
||||||
|
.getTime()));
|
||||||
|
rowOutput.append(DELIMITER);
|
||||||
|
}
|
||||||
|
rowOutput.append(entry.getLogMsg());
|
||||||
|
rowOutput.append("\n");
|
||||||
|
return rowOutput.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFooter() {
|
||||||
|
// not needed, return empty string
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides formatting date as string utilities
|
||||||
|
*/
|
||||||
|
public class DateUtils {
|
||||||
|
|
||||||
|
private DateUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns timestamp given by param in KML format ie yyyy-mm-ddThh:mm:ssZ,
|
||||||
|
* where T is the separator between the date and the time and the time zone
|
||||||
|
* is Z (for UTC)
|
||||||
|
*
|
||||||
|
* @return KML timestamp as String
|
||||||
|
*/
|
||||||
|
public static String getKMLTimestamp(long when) {
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("GMT");
|
||||||
|
Calendar c = Calendar.getInstance(tz);
|
||||||
|
c.setTimeInMillis(when);
|
||||||
|
return String.format("%tY-%tm-%tdT%tH:%tM:%tSZ", c, c, c, c, c, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper version of getKMLTimestamp, that returns timestamp for current
|
||||||
|
* time
|
||||||
|
*/
|
||||||
|
public static String getCurrentKMLTimestamp() {
|
||||||
|
return getKMLTimestamp(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns timestamp in following format: yyyy-mm-dd-hh-mm-ss
|
||||||
|
*/
|
||||||
|
public static String getCurrentTimestamp() {
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
return String.format("%tY-%tm-%td-%tH-%tM-%tS", c, c, c, c, c, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interface for formatting tracker data output
|
||||||
|
*/
|
||||||
|
interface IFormatter {
|
||||||
|
|
||||||
|
String getHeader();
|
||||||
|
String getOutput(TrackerEntry entry);
|
||||||
|
String getFooter();
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import com.android.locationtracker.data.TrackerEntry.EntryType;
|
||||||
|
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats tracker data as KML output
|
||||||
|
*/
|
||||||
|
class KMLFormatter implements IFormatter {
|
||||||
|
|
||||||
|
public String getHeader() {
|
||||||
|
LineBuilder builder = new LineBuilder();
|
||||||
|
builder.addLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
|
builder.addLine("<kml xmlns=\"http://earth.google.com/kml/2.2\">");
|
||||||
|
builder.addLine("<Document>");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFooter() {
|
||||||
|
LineBuilder builder = new LineBuilder();
|
||||||
|
builder.addLine("</Document>");
|
||||||
|
builder.addLine("</kml>");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutput(TrackerEntry entry) {
|
||||||
|
LineBuilder builder = new LineBuilder();
|
||||||
|
|
||||||
|
if (entry.getType() == EntryType.LOCATION_TYPE) {
|
||||||
|
|
||||||
|
Location loc = entry.getLocation();
|
||||||
|
builder.addLine("<Placemark>");
|
||||||
|
builder.addLine("<description>");
|
||||||
|
builder.addLine("accuracy = " + loc.getAccuracy());
|
||||||
|
builder.addLine("distance from last network location = "
|
||||||
|
+ entry.getDistFromNetLocation());
|
||||||
|
builder.addLine("</description>");
|
||||||
|
builder.addLine("<TimeStamp>");
|
||||||
|
builder.addLine("<when>" + entry.getTimestamp() + "</when>");
|
||||||
|
builder.addLine("</TimeStamp>");
|
||||||
|
builder.addLine("<Point>");
|
||||||
|
builder.addLine("<coordinates>");
|
||||||
|
builder.addLine(loc.getLongitude() + "," + loc.getLatitude() + ","
|
||||||
|
+ loc.getAltitude());
|
||||||
|
builder.addLine("</coordinates>");
|
||||||
|
builder.addLine("</Point>");
|
||||||
|
builder.addLine("</Placemark>");
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LineBuilder {
|
||||||
|
private StringBuilder mBuilder;
|
||||||
|
|
||||||
|
public LineBuilder() {
|
||||||
|
mBuilder = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLine(String line) {
|
||||||
|
mBuilder.append(line);
|
||||||
|
mBuilder.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for writing and retrieving data using the TrackerProvider
|
||||||
|
* content provider
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TrackerDataHelper {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
/** formats data output */
|
||||||
|
protected IFormatter mFormatter;
|
||||||
|
|
||||||
|
/** formats output as Comma separated value CSV file */
|
||||||
|
public static final IFormatter CSV_FORMATTER = new CSVFormatter();
|
||||||
|
/** formats output as KML file */
|
||||||
|
public static final IFormatter KML_FORMATTER = new KMLFormatter();
|
||||||
|
/** provides no formatting */
|
||||||
|
public static final IFormatter NO_FORMATTER = new IFormatter() {
|
||||||
|
public String getFooter() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeader() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutput(TrackerEntry entry) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates instance
|
||||||
|
*
|
||||||
|
* @param context - content context
|
||||||
|
* @param formatter - formats the output from the get*Output* methods
|
||||||
|
*/
|
||||||
|
public TrackerDataHelper(Context context, IFormatter formatter) {
|
||||||
|
mContext = context;
|
||||||
|
mFormatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a instance with no output formatting capabilities. Useful for
|
||||||
|
* clients that require write-only access
|
||||||
|
*/
|
||||||
|
public TrackerDataHelper(Context context) {
|
||||||
|
this(context, NO_FORMATTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert given TrackerEntry into content provider
|
||||||
|
*/
|
||||||
|
void writeEntry(TrackerEntry entry) {
|
||||||
|
mContext.getContentResolver().insert(TrackerProvider.CONTENT_URI,
|
||||||
|
entry.getAsContentValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert given location into tracker data
|
||||||
|
*/
|
||||||
|
public void writeEntry(Location loc, float distFromNetLoc) {
|
||||||
|
writeEntry(TrackerEntry.createEntry(loc, distFromNetLoc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert given log message into tracker data
|
||||||
|
*/
|
||||||
|
public void writeEntry(String tag, String logMsg) {
|
||||||
|
writeEntry(TrackerEntry.createEntry(tag, logMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all tracker entries
|
||||||
|
*/
|
||||||
|
public void deleteAll() {
|
||||||
|
mContext.getContentResolver().delete(TrackerProvider.CONTENT_URI, null,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query tracker data, filtering by given tag
|
||||||
|
*
|
||||||
|
* @param tag
|
||||||
|
* @return Cursor to data
|
||||||
|
*/
|
||||||
|
public Cursor query(String tag, int limit) {
|
||||||
|
String selection = (tag == null ? null : TrackerEntry.TAG + "=?");
|
||||||
|
String[] selectionArgs = (tag == null ? null : new String[] {tag});
|
||||||
|
Cursor cursor = mContext.getContentResolver().query(
|
||||||
|
TrackerProvider.CONTENT_URI, TrackerEntry.ATTRIBUTES,
|
||||||
|
selection, selectionArgs, null);
|
||||||
|
if (cursor == null) {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
int pos = (cursor.getCount() < limit ? 0 : cursor.getCount() - limit);
|
||||||
|
cursor.moveToPosition(pos);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a cursor that starts at the last limit rows
|
||||||
|
*
|
||||||
|
* @param limit
|
||||||
|
* @return a cursor, null if bad things happened
|
||||||
|
*/
|
||||||
|
public Cursor query(int limit) {
|
||||||
|
return query(null, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query tracker data, filtering by given tag. mo limit to number of rows
|
||||||
|
* returned
|
||||||
|
*
|
||||||
|
* @param tag
|
||||||
|
* @return Cursor to data
|
||||||
|
*/
|
||||||
|
public Cursor query(String tag) {
|
||||||
|
return query(tag, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output header particular to the associated formatter
|
||||||
|
*/
|
||||||
|
public String getOutputHeader() {
|
||||||
|
return mFormatter.getHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output footer particular to the associated formatter
|
||||||
|
*/
|
||||||
|
public String getOutputFooter() {
|
||||||
|
return mFormatter.getFooter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method which converts row referenced by given cursor to a string
|
||||||
|
* output
|
||||||
|
*
|
||||||
|
* @param cursor
|
||||||
|
* @return CharSequence output, null if given cursor is invalid or no more
|
||||||
|
* data
|
||||||
|
*/
|
||||||
|
public String getNextOutput(Cursor cursor) {
|
||||||
|
if (cursor == null || cursor.isAfterLast()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String output = mFormatter.getOutput(TrackerEntry.createEntry(cursor));
|
||||||
|
cursor.moveToNext();
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that holds a tracker entry. An entry can be either a valid location, or
|
||||||
|
* a simple log msg
|
||||||
|
*
|
||||||
|
* It provides a concrete data structure to represent data stored in the
|
||||||
|
* TrackerProvider
|
||||||
|
*/
|
||||||
|
class TrackerEntry {
|
||||||
|
|
||||||
|
static final String TIMESTAMP = "Timestamp";
|
||||||
|
static final String TAG = "Tag";
|
||||||
|
static final String ENTRY_TYPE = "Type";
|
||||||
|
|
||||||
|
private Location mLocation;
|
||||||
|
private float mDistFromNetLocation;
|
||||||
|
private String mLogMsg;
|
||||||
|
|
||||||
|
static final String ID_COL = "_id";
|
||||||
|
static final String ACCURACY = "Accuracy";
|
||||||
|
static final String LATITUDE = "Latitude";
|
||||||
|
static final String LONGITUDE = "Longitude";
|
||||||
|
static final String ALTITUDE = "Altitude";
|
||||||
|
static final String SPEED = "Speed";
|
||||||
|
static final String BEARING = "Bearing";
|
||||||
|
static final String DIST_NET_LOCATION = "DistFromNetLocation";
|
||||||
|
static final String LOC_TIME = "LocationTime";
|
||||||
|
static final String DEBUG_INFO = "DebugInfo";
|
||||||
|
|
||||||
|
static final String STRING_DATA = "STRING";
|
||||||
|
static final String INT_DATA = "INTEGER";
|
||||||
|
static final String REAL_DATA = "REAL";
|
||||||
|
static final String BLOB_DATA = "BLOB";
|
||||||
|
|
||||||
|
static final String[] ATTRIBUTES = {
|
||||||
|
ID_COL, TIMESTAMP, TAG, ENTRY_TYPE, ACCURACY, LATITUDE, LONGITUDE,
|
||||||
|
ALTITUDE, SPEED, BEARING, DIST_NET_LOCATION, LOC_TIME, DEBUG_INFO};
|
||||||
|
static final String[] ATTRIBUTES_DATA_TYPE = {
|
||||||
|
INT_DATA + " PRIMARY KEY", STRING_DATA, STRING_DATA, STRING_DATA,
|
||||||
|
REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA,
|
||||||
|
REAL_DATA, INT_DATA, STRING_DATA};
|
||||||
|
|
||||||
|
// location extra keys used to retrieve debug info
|
||||||
|
private static final String NETWORK_LOCATION_SOURCE_KEY =
|
||||||
|
"networkLocationSource";
|
||||||
|
private static final String NETWORK_LOCATION_TYPE_KEY =
|
||||||
|
"networkLocationType";
|
||||||
|
private static final String[] LOCATION_DEBUG_KEYS = {
|
||||||
|
NETWORK_LOCATION_SOURCE_KEY, NETWORK_LOCATION_TYPE_KEY};
|
||||||
|
|
||||||
|
enum EntryType {
|
||||||
|
LOCATION_TYPE, LOG_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
private String mTimestamp;
|
||||||
|
private String mTag;
|
||||||
|
private EntryType mType;
|
||||||
|
|
||||||
|
private TrackerEntry(String tag, EntryType type) {
|
||||||
|
mType = type;
|
||||||
|
mTag = tag;
|
||||||
|
mLocation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrackerEntry(Location loc) {
|
||||||
|
this(loc.getProvider(), EntryType.LOCATION_TYPE);
|
||||||
|
mLocation = new Location(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a TrackerEntry from a Location
|
||||||
|
*/
|
||||||
|
static TrackerEntry createEntry(Location loc, float distFromNetLocation) {
|
||||||
|
TrackerEntry entry = new TrackerEntry(loc);
|
||||||
|
|
||||||
|
String timestampVal = DateUtils.getCurrentKMLTimestamp();
|
||||||
|
entry.setTimestamp(timestampVal);
|
||||||
|
entry.setDistFromNetLocation(distFromNetLocation);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a TrackerEntry from a log msg
|
||||||
|
*/
|
||||||
|
static TrackerEntry createEntry(String tag, String msg) {
|
||||||
|
TrackerEntry entry = new TrackerEntry(tag, EntryType.LOG_TYPE);
|
||||||
|
String timestampVal = DateUtils.getCurrentKMLTimestamp();
|
||||||
|
entry.setTimestamp(timestampVal);
|
||||||
|
entry.setLogMsg(msg);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTimestamp(String timestamp) {
|
||||||
|
mTimestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryType getType() {
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDistFromNetLocation(float distFromNetLocation) {
|
||||||
|
mDistFromNetLocation = distFromNetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLogMsg(String msg) {
|
||||||
|
mLogMsg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocation(Location location) {
|
||||||
|
mLocation = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getTimestamp() {
|
||||||
|
return mTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getTag() {
|
||||||
|
return mTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location getLocation() {
|
||||||
|
return mLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLogMsg() {
|
||||||
|
return mLogMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getDistFromNetLocation() {
|
||||||
|
return mDistFromNetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buildCreationString(StringBuilder builder) {
|
||||||
|
if (ATTRIBUTES.length != ATTRIBUTES_DATA_TYPE.length) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Attribute length does not match data type length");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ATTRIBUTES_DATA_TYPE.length; i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
builder.append(String.format("%s %s", ATTRIBUTES[i],
|
||||||
|
ATTRIBUTES_DATA_TYPE[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues getAsContentValues() {
|
||||||
|
ContentValues cValues = new ContentValues(ATTRIBUTES.length);
|
||||||
|
cValues.put(TIMESTAMP, mTimestamp);
|
||||||
|
cValues.put(TAG, mTag);
|
||||||
|
cValues.put(ENTRY_TYPE, mType.toString());
|
||||||
|
if (mType == EntryType.LOCATION_TYPE) {
|
||||||
|
cValues.put(LATITUDE, mLocation.getLatitude());
|
||||||
|
cValues.put(LONGITUDE, mLocation.getLongitude());
|
||||||
|
if (mLocation.hasAccuracy()) {
|
||||||
|
cValues.put(ACCURACY, mLocation.getAccuracy());
|
||||||
|
}
|
||||||
|
if (mLocation.hasAltitude()) {
|
||||||
|
cValues.put(ALTITUDE, mLocation.getAltitude());
|
||||||
|
}
|
||||||
|
if (mLocation.hasSpeed()) {
|
||||||
|
cValues.put(SPEED, mLocation.getSpeed());
|
||||||
|
}
|
||||||
|
if (mLocation.hasBearing()) {
|
||||||
|
cValues.put(BEARING, mLocation.getBearing());
|
||||||
|
}
|
||||||
|
cValues.put(DIST_NET_LOCATION, mDistFromNetLocation);
|
||||||
|
cValues.put(LOC_TIME, mLocation.getTime());
|
||||||
|
StringBuilder debugBuilder = new StringBuilder("");
|
||||||
|
if (mLocation.getExtras() != null) {
|
||||||
|
for (String key : LOCATION_DEBUG_KEYS) {
|
||||||
|
Object val = mLocation.getExtras().get(key);
|
||||||
|
if (val != null) {
|
||||||
|
debugBuilder.append(String.format("%s=%s; ", key, val
|
||||||
|
.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cValues.put(DEBUG_INFO, debugBuilder.toString());
|
||||||
|
} else {
|
||||||
|
cValues.put(DEBUG_INFO, mLogMsg);
|
||||||
|
}
|
||||||
|
return cValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TrackerEntry createEntry(Cursor cursor) {
|
||||||
|
String timestamp = cursor.getString(cursor.getColumnIndex(TIMESTAMP));
|
||||||
|
String tag = cursor.getString(cursor.getColumnIndex(TAG));
|
||||||
|
String sType = cursor.getString(cursor.getColumnIndex(ENTRY_TYPE));
|
||||||
|
TrackerEntry entry = new TrackerEntry(tag, EntryType.valueOf(sType));
|
||||||
|
entry.setTimestamp(timestamp);
|
||||||
|
if (entry.getType() == EntryType.LOCATION_TYPE) {
|
||||||
|
Location location = new Location(tag);
|
||||||
|
location.setLatitude(cursor.getFloat(cursor
|
||||||
|
.getColumnIndexOrThrow(LATITUDE)));
|
||||||
|
location.setLongitude(cursor.getFloat(cursor
|
||||||
|
.getColumnIndexOrThrow(LONGITUDE)));
|
||||||
|
|
||||||
|
Float accuracy = getNullableFloat(cursor, ACCURACY);
|
||||||
|
if (accuracy != null) {
|
||||||
|
location.setAccuracy(accuracy);
|
||||||
|
}
|
||||||
|
Float altitude = getNullableFloat(cursor, ALTITUDE);
|
||||||
|
if (altitude != null) {
|
||||||
|
location.setAltitude(altitude);
|
||||||
|
}
|
||||||
|
Float bearing = getNullableFloat(cursor, BEARING);
|
||||||
|
if (bearing != null) {
|
||||||
|
location.setBearing(bearing);
|
||||||
|
}
|
||||||
|
Float speed = getNullableFloat(cursor, SPEED);
|
||||||
|
if (speed != null) {
|
||||||
|
location.setSpeed(speed);
|
||||||
|
}
|
||||||
|
location.setTime(cursor.getLong(cursor.getColumnIndex(LOC_TIME)));
|
||||||
|
entry.setLocation(location);
|
||||||
|
}
|
||||||
|
entry.setLogMsg(cursor.getString(cursor.getColumnIndex(DEBUG_INFO)));
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Float getNullableFloat(Cursor cursor, String colName) {
|
||||||
|
Float retValue = null;
|
||||||
|
int colIndex = cursor.getColumnIndexOrThrow(colName);
|
||||||
|
if (!cursor.isNull(colIndex)) {
|
||||||
|
retValue = cursor.getFloat(colIndex);
|
||||||
|
}
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ResourceCursorAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.locationtracker.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to bind Tracker data to a list view UI
|
||||||
|
*/
|
||||||
|
public class TrackerListHelper extends TrackerDataHelper {
|
||||||
|
|
||||||
|
private ListActivity mActivity;
|
||||||
|
|
||||||
|
// sort entries by most recent first
|
||||||
|
private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
|
||||||
|
|
||||||
|
public TrackerListHelper(ListActivity activity) {
|
||||||
|
super(activity, TrackerDataHelper.CSV_FORMATTER);
|
||||||
|
mActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for binding the list activities UI to the tracker data
|
||||||
|
* Tracker data will be sorted in most-recent first order
|
||||||
|
* Will enable automatic UI changes as tracker data changes
|
||||||
|
*
|
||||||
|
* @param layout - layout to populate data
|
||||||
|
*/
|
||||||
|
public void bindListUI(int layout) {
|
||||||
|
Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
|
||||||
|
TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
|
||||||
|
// Used to map tracker entries from the database to views
|
||||||
|
TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
|
||||||
|
mActivity.setListAdapter(adapter);
|
||||||
|
cursor.setNotificationUri(mActivity.getContentResolver(),
|
||||||
|
TrackerProvider.CONTENT_URI);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TrackerAdapter extends ResourceCursorAdapter {
|
||||||
|
|
||||||
|
public TrackerAdapter(Context context, int layout, Cursor c) {
|
||||||
|
super(context, layout, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
|
final TextView v = (TextView) view
|
||||||
|
.findViewById(R.id.entrylist_item);
|
||||||
|
String rowText = mFormatter.getOutput(TrackerEntry
|
||||||
|
.createEntry(cursor));
|
||||||
|
v.setText(rowText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.locationtracker.data;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content provider for location tracking.
|
||||||
|
*
|
||||||
|
* It is recommended to use the TrackerDataHelper class to access this data
|
||||||
|
* rather than this class directly
|
||||||
|
*/
|
||||||
|
public class TrackerProvider extends ContentProvider {
|
||||||
|
|
||||||
|
public static final Uri CONTENT_URI = Uri
|
||||||
|
.parse("content://com.android.locationtracker");
|
||||||
|
|
||||||
|
private static final String DB_NAME = "tracking.db";
|
||||||
|
private static final String TABLE_NAME = "tracking";
|
||||||
|
private static final int DB_VERSION = 1;
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "TrackerProvider";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class helps open, create, and upgrade the database file.
|
||||||
|
*/
|
||||||
|
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
|
DatabaseHelper(Context context) {
|
||||||
|
super(context, DB_NAME, null, DB_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
StringBuilder queryBuilder = new StringBuilder();
|
||||||
|
queryBuilder.append(String.format("CREATE TABLE %s (", TABLE_NAME));
|
||||||
|
TrackerEntry.buildCreationString(queryBuilder);
|
||||||
|
|
||||||
|
queryBuilder.append(");");
|
||||||
|
db.execSQL(queryBuilder.toString());
|
||||||
|
db.setVersion(DB_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
// TODO: reimplement this when dB version changes
|
||||||
|
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion
|
||||||
|
+ " to " + newVersion
|
||||||
|
+ ", which will destroy all old data");
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatabaseHelper mOpenHelper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
mOpenHelper = new DatabaseHelper(getContext());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||||
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||||
|
int result = db.delete(TABLE_NAME, selection, selectionArgs);
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||||
|
long rowId = db.insert(TABLE_NAME, null, values);
|
||||||
|
if (rowId > 0) {
|
||||||
|
Uri addedUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
|
||||||
|
getContext().getContentResolver().notifyChange(addedUri, null);
|
||||||
|
return addedUri;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] projection, String selection,
|
||||||
|
String[] selectionArgs, String sortOrder) {
|
||||||
|
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||||
|
// TODO: extract limit from URI ?
|
||||||
|
Cursor cursor = db.query(TABLE_NAME, projection, selection,
|
||||||
|
selectionArgs, null, null, sortOrder);
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues values, String selection,
|
||||||
|
String[] selectionArgs) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user