forked from upstream-mirrors/OpenTracks
sync from main
This commit is contained in:
@@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.google.android.maps.mytracks"
|
package="com.google.android.maps.mytracks"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="33"
|
android:versionCode="34"
|
||||||
android:versionName="1.1.10">
|
android:versionName="1.1.11">
|
||||||
<application android:icon="@drawable/arrow_icon"
|
<application android:icon="@drawable/arrow_icon"
|
||||||
android:label="@string/my_tracks_app_name"
|
android:label="@string/my_tracks_app_name"
|
||||||
android:name="com.google.android.apps.mytracks.MyTracksApplication"
|
android:name="com.google.android.apps.mytracks.MyTracksApplication"
|
||||||
|
|||||||
@@ -15,110 +15,121 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/screen"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:background="@drawable/list_bar"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/list_bar">
|
android:layout_width="fill_parent">
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dip"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:text="@string/send_google_title"
|
android:text="@string/send_google_title"
|
||||||
android:textSize="20dip"
|
|
||||||
android:textColor="#fff"
|
android:textColor="#fff"
|
||||||
android:layout_marginLeft="10dip"/>
|
android:textSize="20dip"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<ScrollView android:id="@+id/sendtogoogle_scrollview"
|
<ScrollView
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="0dip"
|
android:layout_height="0dip"
|
||||||
android:layout_weight="1">
|
android:layout_marginBottom="5dip"
|
||||||
|
android:layout_marginLeft="5dip"
|
||||||
|
android:layout_marginTop="5dip"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
<TableLayout
|
<TableLayout
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:stretchColumns="1"
|
android:layout_width="fill_parent"
|
||||||
android:layout_marginTop="5dip"
|
android:stretchColumns="1">
|
||||||
android:layout_marginLeft="5dip">
|
|
||||||
|
|
||||||
<!-- My Maps -->
|
<!-- Google My Maps -->
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<ImageView android:src="@drawable/mymaps_icon"
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginLeft="10dip">
|
android:src="@drawable/mymaps_icon"/>
|
||||||
<CheckBox android:id="@+id/sendtogoogle_google_mymaps"
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dip"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<CheckBox
|
||||||
|
android:checked="true"
|
||||||
|
android:id="@+id/send_google_my_maps"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/send_google_my_maps"
|
|
||||||
android:textSize="20dip"
|
|
||||||
android:checked="true"/>
|
|
||||||
<RadioGroup android:id="@+id/sendtogoogle_group_mymaps"
|
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content">
|
android:text="@string/send_google_my_maps"
|
||||||
<RadioButton android:id="@+id/sendtogoogle_create_new_map"
|
android:textSize="18dip"/>
|
||||||
android:layout_width="fill_parent"
|
<RadioGroup
|
||||||
|
android:id="@+id/send_google_my_maps_group"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/send_google_new_map"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:text="@string/send_google_new_map"/>
|
android:text="@string/send_google_new_map"/>
|
||||||
<RadioButton android:id="@+id/sendtogoogle_pick_existing_map"
|
<RadioButton
|
||||||
android:layout_width="fill_parent"
|
android:id="@+id/send_google_existing_map"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:text="@string/send_google_existing_map"/>
|
android:text="@string/send_google_existing_map"/>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<!-- Fusion Tables -->
|
<!-- Google Fusion Tables -->
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<ImageView android:src="@drawable/googledocs_icon"
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginLeft="10dip">
|
android:src="@drawable/googledocs_icon"/>
|
||||||
<CheckBox android:id="@+id/sendtogoogle_google_fusiontables"
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dip"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<CheckBox
|
||||||
|
android:checked="true"
|
||||||
|
android:id="@+id/send_google_fusion_tables"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:text="@string/send_google_fusion_tables"
|
android:text="@string/send_google_fusion_tables"
|
||||||
android:textSize="20dip"
|
android:textSize="18dip"/>
|
||||||
android:checked="true"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<!-- Google Docs -->
|
<!-- Google Docs -->
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<ImageView android:src="@drawable/googledocs_icon"
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginLeft="10dip">
|
android:src="@drawable/googledocs_icon"/>
|
||||||
<CheckBox android:id="@+id/sendtogoogle_google_docs"
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dip"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<CheckBox
|
||||||
|
android:checked="true"
|
||||||
|
android:id="@+id/send_google_docs"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
android:text="@string/send_google_docs"
|
android:text="@string/send_google_docs"
|
||||||
android:textSize="20dip"
|
android:textSize="18dip"/>
|
||||||
android:checked="true"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<LinearLayout style="@style/ButtonLayout">
|
<LinearLayout style="@style/ButtonLayout">
|
||||||
<LinearLayout style="@style/ButtonSpacer"/>
|
<LinearLayout style="@style/ButtonSpacer"/>
|
||||||
<Button android:id="@+id/sendtogoogle_send_now"
|
<Button
|
||||||
|
android:id="@+id/send_google_send_now"
|
||||||
android:layout_gravity="left"
|
android:layout_gravity="left"
|
||||||
android:text="@string/send_google_send_now"
|
android:text="@string/send_google_send_now"
|
||||||
style="@style/Button"/>
|
style="@style/Button"/>
|
||||||
<Button android:id="@+id/sendtogoogle_cancel"
|
<Button
|
||||||
|
android:id="@+id/send_google_cancel"
|
||||||
android:layout_gravity="right"
|
android:layout_gravity="right"
|
||||||
android:text="@string/generic_cancel"
|
android:text="@string/generic_cancel"
|
||||||
style="@style/Button"/>
|
style="@style/Button"/>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
@@ -40,11 +41,11 @@ import android.widget.RadioGroup;
|
|||||||
*/
|
*/
|
||||||
public class SendDialog extends Dialog {
|
public class SendDialog extends Dialog {
|
||||||
|
|
||||||
private RadioButton createNewMapRadioButton;
|
private RadioButton newMapRadioButton;
|
||||||
private RadioButton pickMapRadioButton;
|
private RadioButton existingMapRadioButton;
|
||||||
private CheckBox sendToMyMapsCheckBox;
|
private CheckBox myMapsCheckBox;
|
||||||
private CheckBox sendToFusionTablesCheckBox;
|
private CheckBox fusionTablesCheckBox;
|
||||||
private CheckBox sendToDocsCheckBox;
|
private CheckBox docsCheckBox;
|
||||||
private OnClickListener clickListener;
|
private OnClickListener clickListener;
|
||||||
|
|
||||||
public SendDialog(Context context) {
|
public SendDialog(Context context) {
|
||||||
@@ -57,19 +58,17 @@ public class SendDialog extends Dialog {
|
|||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
setContentView(R.layout.mytracks_send_to_google);
|
setContentView(R.layout.mytracks_send_to_google);
|
||||||
|
|
||||||
final Button sendButton = (Button) findViewById(R.id.sendtogoogle_send_now);
|
final Button sendButton = (Button) findViewById(R.id.send_google_send_now);
|
||||||
final RadioGroup groupMyMaps = (RadioGroup) findViewById(R.id.sendtogoogle_group_mymaps);
|
|
||||||
sendToMyMapsCheckBox =
|
|
||||||
(CheckBox) findViewById(R.id.sendtogoogle_google_mymaps);
|
|
||||||
sendToFusionTablesCheckBox =
|
|
||||||
(CheckBox) findViewById(R.id.sendtogoogle_google_fusiontables);
|
|
||||||
sendToDocsCheckBox = (CheckBox) findViewById(R.id.sendtogoogle_google_docs);
|
|
||||||
createNewMapRadioButton =
|
|
||||||
(RadioButton) findViewById(R.id.sendtogoogle_create_new_map);
|
|
||||||
pickMapRadioButton =
|
|
||||||
(RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map);
|
|
||||||
|
|
||||||
Button cancel = (Button) findViewById(R.id.sendtogoogle_cancel);
|
final RadioGroup myMapsGroup = (RadioGroup) findViewById(R.id.send_google_my_maps_group);
|
||||||
|
newMapRadioButton = (RadioButton) findViewById(R.id.send_google_new_map);
|
||||||
|
existingMapRadioButton = (RadioButton) findViewById(R.id.send_google_existing_map);
|
||||||
|
|
||||||
|
myMapsCheckBox = (CheckBox) findViewById(R.id.send_google_my_maps);
|
||||||
|
fusionTablesCheckBox = (CheckBox) findViewById(R.id.send_google_fusion_tables);
|
||||||
|
docsCheckBox = (CheckBox) findViewById(R.id.send_google_docs);
|
||||||
|
|
||||||
|
Button cancel = (Button) findViewById(R.id.send_google_cancel);
|
||||||
cancel.setOnClickListener(new View.OnClickListener() {
|
cancel.setOnClickListener(new View.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (clickListener != null) {
|
if (clickListener != null) {
|
||||||
@@ -79,7 +78,7 @@ public class SendDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Button send = (Button) findViewById(R.id.sendtogoogle_send_now);
|
Button send = (Button) findViewById(R.id.send_google_send_now);
|
||||||
send.setOnClickListener(new View.OnClickListener() {
|
send.setOnClickListener(new View.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (clickListener != null) {
|
if (clickListener != null) {
|
||||||
@@ -91,80 +90,72 @@ public class SendDialog extends Dialog {
|
|||||||
|
|
||||||
OnCheckedChangeListener checkBoxListener = new OnCheckedChangeListener() {
|
OnCheckedChangeListener checkBoxListener = new OnCheckedChangeListener() {
|
||||||
public void onCheckedChanged(CompoundButton button, boolean checked) {
|
public void onCheckedChanged(CompoundButton button, boolean checked) {
|
||||||
sendButton.setEnabled(
|
sendButton.setEnabled(myMapsCheckBox.isChecked() || fusionTablesCheckBox.isChecked()
|
||||||
sendToMyMapsCheckBox.isChecked() ||
|
|| docsCheckBox.isChecked());
|
||||||
sendToFusionTablesCheckBox.isChecked() ||
|
myMapsGroup.setVisibility(myMapsCheckBox.isChecked() ? View.VISIBLE : View.GONE);
|
||||||
sendToDocsCheckBox.isChecked());
|
|
||||||
groupMyMaps.setVisibility(sendToMyMapsCheckBox.isChecked() ? View.VISIBLE : View.INVISIBLE);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
sendToMyMapsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
|
||||||
sendToFusionTablesCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
|
||||||
sendToDocsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
|
||||||
|
|
||||||
SharedPreferences prefs =
|
myMapsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||||
getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
fusionTablesCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||||
|
docsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||||
|
|
||||||
|
SharedPreferences prefs = getContext().getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
if (prefs != null) {
|
if (prefs != null) {
|
||||||
sendToMyMapsCheckBox.setChecked(
|
boolean pickExistingMap = prefs.getBoolean(
|
||||||
prefs.getBoolean(
|
getContext().getString(R.string.pick_existing_map_key), false);
|
||||||
getContext().getString(R.string.send_to_my_maps_key), true));
|
|
||||||
sendToFusionTablesCheckBox.setChecked(
|
newMapRadioButton.setChecked(!pickExistingMap);
|
||||||
prefs.getBoolean(
|
existingMapRadioButton.setChecked(pickExistingMap);
|
||||||
getContext().getString(R.string.send_to_fusion_tables_key), true));
|
|
||||||
sendToDocsCheckBox.setChecked(
|
myMapsCheckBox.setChecked(
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(getContext().getString(R.string.send_to_my_maps_key), true));
|
||||||
getContext().getString(R.string.send_to_docs_key), true));
|
fusionTablesCheckBox.setChecked(
|
||||||
pickMapRadioButton.setChecked(
|
prefs.getBoolean(getContext().getString(R.string.send_to_fusion_tables_key), true));
|
||||||
prefs.getBoolean(
|
docsCheckBox.setChecked(
|
||||||
getContext().getString(R.string.pick_existing_map_key), false));
|
prefs.getBoolean(getContext().getString(R.string.send_to_docs_key), true));
|
||||||
createNewMapRadioButton.setChecked(
|
|
||||||
!prefs.getBoolean(
|
|
||||||
getContext().getString(R.string.pick_existing_map_key), false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
SharedPreferences prefs =
|
super.onStop();
|
||||||
getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
SharedPreferences prefs = getContext().getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
if (prefs != null) {
|
if (prefs != null) {
|
||||||
Editor editor = prefs.edit();
|
Editor editor = prefs.edit();
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
editor.putBoolean(
|
editor.putBoolean(getContext().getString(R.string.pick_existing_map_key),
|
||||||
getContext().getString(R.string.send_to_my_maps_key),
|
existingMapRadioButton.isChecked());
|
||||||
sendToMyMapsCheckBox.isChecked());
|
editor.putBoolean(getContext().getString(R.string.send_to_my_maps_key),
|
||||||
editor.putBoolean(
|
myMapsCheckBox.isChecked());
|
||||||
getContext().getString(R.string.send_to_fusion_tables_key),
|
editor.putBoolean(getContext().getString(R.string.send_to_fusion_tables_key),
|
||||||
sendToFusionTablesCheckBox.isChecked());
|
fusionTablesCheckBox.isChecked());
|
||||||
editor.putBoolean(
|
editor.putBoolean(getContext().getString(R.string.send_to_docs_key),
|
||||||
getContext().getString(R.string.send_to_docs_key),
|
docsCheckBox.isChecked());
|
||||||
sendToDocsCheckBox.isChecked());
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
||||||
editor.putBoolean(
|
|
||||||
getContext().getString(R.string.pick_existing_map_key),
|
|
||||||
pickMapRadioButton.isChecked());
|
|
||||||
editor.commit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.onStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnClickListener(OnClickListener clickListener) {
|
public void setOnClickListener(OnClickListener clickListener) {
|
||||||
this.clickListener = clickListener;
|
this.clickListener = clickListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getCreateNewMap() {
|
||||||
|
return newMapRadioButton.isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getSendToMyMaps() {
|
public boolean getSendToMyMaps() {
|
||||||
return sendToMyMapsCheckBox.isChecked();
|
return myMapsCheckBox.isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getSendToFusionTables() {
|
public boolean getSendToFusionTables() {
|
||||||
return sendToFusionTablesCheckBox.isChecked();
|
return fusionTablesCheckBox.isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getSendToDocs() {
|
public boolean getSendToDocs() {
|
||||||
return sendToDocsCheckBox.isChecked();
|
return docsCheckBox.isChecked();
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getCreateNewMap() {
|
|
||||||
return createNewMapRadioButton.isChecked();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -17,7 +17,7 @@ package com.google.android.apps.mytracks.services.sensors;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.services.sensors.ant.AntDirectSensorManager;
|
import com.google.android.apps.mytracks.services.sensors.ant.AntDirectSensorManager;
|
||||||
import com.google.android.apps.mytracks.services.sensors.ant.AntSRMSensorManager;
|
import com.google.android.apps.mytracks.services.sensors.ant.AntSrmBridgeSensorManager;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -56,7 +56,7 @@ public class SensorManagerFactory {
|
|||||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_ant))) {
|
} else if (sensor.equals(context.getString(R.string.sensor_type_value_ant))) {
|
||||||
return new AntDirectSensorManager(context);
|
return new AntDirectSensorManager(context);
|
||||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_srm_ant_bridge))) {
|
} else if (sensor.equals(context.getString(R.string.sensor_type_value_srm_ant_bridge))) {
|
||||||
return new AntSRMSensorManager(context);
|
return new AntSrmBridgeSensorManager(context);
|
||||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_zephyr))) {
|
} else if (sensor.equals(context.getString(R.string.sensor_type_value_zephyr))) {
|
||||||
return new ZephyrSensorManager(context);
|
return new ZephyrSensorManager(context);
|
||||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_polar))) {
|
} else if (sensor.equals(context.getString(R.string.sensor_type_value_polar))) {
|
||||||
|
|||||||
+15
-14
@@ -188,11 +188,12 @@ public abstract class AntSensorManager extends SensorManager {
|
|||||||
private void cleanAntInterface() {
|
private void cleanAntInterface() {
|
||||||
Log.i(TAG, "Destroying AntSensorManager");
|
Log.i(TAG, "Destroying AntSensorManager");
|
||||||
|
|
||||||
|
if (antReceiver == null) {
|
||||||
|
Log.e(TAG, "no ANT receiver");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (antReceiver == null) {
|
|
||||||
Log.e(TAG, "no ANT receiver");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
antReceiver.releaseInterface();
|
antReceiver.releaseInterface();
|
||||||
antReceiver.destroy();
|
antReceiver.destroy();
|
||||||
antReceiver = null;
|
antReceiver = null;
|
||||||
@@ -213,12 +214,12 @@ public abstract class AntSensorManager extends SensorManager {
|
|||||||
private synchronized void serviceConnected() {
|
private synchronized void serviceConnected() {
|
||||||
Log.d(TAG, "ANT service connected");
|
Log.d(TAG, "ANT service connected");
|
||||||
|
|
||||||
try {
|
if (antReceiver == null) {
|
||||||
if (antReceiver == null) {
|
Log.e(TAG, "no ANT receiver");
|
||||||
Log.e(TAG, "no ANT receiver");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
try {
|
||||||
if (!antReceiver.claimInterface()) {
|
if (!antReceiver.claimInterface()) {
|
||||||
Log.e(TAG, "failed to claim ANT interface");
|
Log.e(TAG, "failed to claim ANT interface");
|
||||||
return;
|
return;
|
||||||
@@ -305,12 +306,12 @@ public abstract class AntSensorManager extends SensorManager {
|
|||||||
short deviceNumber, byte deviceType, byte txType, short channelPeriod,
|
short deviceNumber, byte deviceType, byte txType, short channelPeriod,
|
||||||
byte radioFreq, byte proxSearch) {
|
byte radioFreq, byte proxSearch) {
|
||||||
|
|
||||||
try {
|
if (antReceiver == null) {
|
||||||
if (antReceiver == null) {
|
Log.e(TAG, "no ANT receiver");
|
||||||
Log.e(TAG, "no ANT receiver");
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
try {
|
||||||
// Assign as slave channel on selected network (0 = public, 1 = ANT+, 2 =
|
// Assign as slave channel on selected network (0 = public, 1 = ANT+, 2 =
|
||||||
// ANTFS)
|
// ANTFS)
|
||||||
antReceiver.ANTAssignChannel(channelNumber, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
|
antReceiver.ANTAssignChannel(channelNumber, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
|
||||||
|
|||||||
+252
@@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* 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.google.android.apps.mytracks.services.sensors.ant;
|
||||||
|
|
||||||
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.dsi.ant.AntDefine;
|
||||||
|
import com.dsi.ant.AntMesg;
|
||||||
|
import com.dsi.ant.exception.AntInterfaceException;
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sensor manager to the PC7 SRM ANT+ bridge.
|
||||||
|
*
|
||||||
|
* @author Sandor Dornbush
|
||||||
|
* @author Umran Abdulla
|
||||||
|
*/
|
||||||
|
public class AntSrmBridgeSensorManager extends AntSensorManager {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These constants are defined by the ANT+ spec.
|
||||||
|
*/
|
||||||
|
public static final byte CHANNEL_NUMBER = 0;
|
||||||
|
public static final byte NETWORK_NUMBER = 0;
|
||||||
|
public static final byte DEVICE_TYPE = 12;
|
||||||
|
public static final byte NETWORK_ID = 1;
|
||||||
|
public static final short CHANNEL_PERIOD = 8192;
|
||||||
|
public static final byte RF_FREQUENCY = 50;
|
||||||
|
|
||||||
|
private static final int INDEX_MESSAGE_TYPE = 1;
|
||||||
|
private static final int INDEX_MESSAGE_ID = 2;
|
||||||
|
private static final int INDEX_MESSAGE_POWER = 3;
|
||||||
|
private static final int INDEX_MESSAGE_SPEED = 5;
|
||||||
|
private static final int INDEX_MESSAGE_CADENCE = 7;
|
||||||
|
private static final int INDEX_MESSAGE_BPM = 8;
|
||||||
|
|
||||||
|
private static final int MSG_INITIAL = 5;
|
||||||
|
private static final int MSG_DATA = 6;
|
||||||
|
|
||||||
|
private short deviceNumber;
|
||||||
|
|
||||||
|
public AntSrmBridgeSensorManager(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
Log.i(TAG, "new ANT SRM Bridge Sensor Manager created");
|
||||||
|
|
||||||
|
deviceNumber = WILDCARD;
|
||||||
|
|
||||||
|
// First read the the device id that we will be pairing with.
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, 0);
|
||||||
|
if (prefs != null) {
|
||||||
|
deviceNumber =
|
||||||
|
(short) prefs.getInt(context.getString(
|
||||||
|
R.string.ant_srm_bridge_sensor_id_key), 0);
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Will pair with device: " + deviceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean handleMessage(byte messageId, byte[] messageData) {
|
||||||
|
if (super.handleMessage(messageId, messageData)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SystemUtils.isRelease(context)) {
|
||||||
|
Log.d(TAG, "Received ANT msg: " + AntUtils.antMessageToString(messageId) + "(" + messageId + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
int channel = messageData[0] & AntDefine.CHANNEL_NUMBER_MASK;
|
||||||
|
switch (channel) {
|
||||||
|
case CHANNEL_NUMBER:
|
||||||
|
decodeChannelMsg(messageId, messageData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "Unhandled message: " + channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode an ant device message.
|
||||||
|
* @param messageData The byte array received from the device.
|
||||||
|
*/
|
||||||
|
private void decodeChannelMsg(int messageId, byte[] messageData) {
|
||||||
|
switch (messageId) {
|
||||||
|
case AntMesg.MESG_BROADCAST_DATA_ID:
|
||||||
|
handleBroadcastData(messageData);
|
||||||
|
break;
|
||||||
|
case AntMesg.MESG_RESPONSE_EVENT_ID:
|
||||||
|
handleMessageResponse(messageData);
|
||||||
|
break;
|
||||||
|
case AntMesg.MESG_CHANNEL_ID_ID:
|
||||||
|
handleChannelId(messageData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Unexpected message id: " + messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleBroadcastData(byte[] antMessage) {
|
||||||
|
if (deviceNumber == WILDCARD) {
|
||||||
|
try {
|
||||||
|
getAntReceiver().ANTRequestMessage(CHANNEL_NUMBER, AntMesg.MESG_CHANNEL_ID_ID);
|
||||||
|
} catch (AntInterfaceException e) {
|
||||||
|
Log.e(TAG, "ANT error handling broadcast data", e);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Requesting channel id id.");
|
||||||
|
}
|
||||||
|
|
||||||
|
setSensorState(Sensor.SensorState.CONNECTED);
|
||||||
|
|
||||||
|
int messageType = antMessage[INDEX_MESSAGE_TYPE] & 0xFF;
|
||||||
|
Log.d(TAG, "Received message-type=" + messageType);
|
||||||
|
|
||||||
|
switch (messageType) {
|
||||||
|
case MSG_INITIAL:
|
||||||
|
break;
|
||||||
|
case MSG_DATA:
|
||||||
|
parseDataMsg(antMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDataMsg(byte[] msg)
|
||||||
|
{
|
||||||
|
int messageId = msg[INDEX_MESSAGE_ID] & 0xFF;
|
||||||
|
Log.d(TAG, "Received message-id=" + messageId);
|
||||||
|
|
||||||
|
int powerVal = (((msg[INDEX_MESSAGE_POWER] & 0xFF) << 8) |
|
||||||
|
(msg[INDEX_MESSAGE_POWER+1] & 0xFF));
|
||||||
|
int speedVal = (((msg[INDEX_MESSAGE_SPEED] & 0xFF) << 8) |
|
||||||
|
(msg[INDEX_MESSAGE_SPEED+1] & 0xFF));
|
||||||
|
int cadenceVal = (msg[INDEX_MESSAGE_CADENCE] & 0xFF);
|
||||||
|
int bpmVal = (msg[INDEX_MESSAGE_BPM] & 0xFF);
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Sensor.SensorData.Builder power =
|
||||||
|
Sensor.SensorData.newBuilder()
|
||||||
|
.setValue(powerVal)
|
||||||
|
.setState(Sensor.SensorState.SENDING);
|
||||||
|
|
||||||
|
// Although speed is available from the SRM Bridge, MyTracks doesn't
|
||||||
|
// use the value, and computes speed from the GPS location data.
|
||||||
|
// Sensor.SensorData.Builder speed =
|
||||||
|
// Sensor.SensorData.newBuilder()
|
||||||
|
// .setValue(speedVal)
|
||||||
|
// .setState(Sensor.SensorState.SENDING);
|
||||||
|
|
||||||
|
Sensor.SensorData.Builder cadence =
|
||||||
|
Sensor.SensorData.newBuilder()
|
||||||
|
.setValue(cadenceVal)
|
||||||
|
.setState(Sensor.SensorState.SENDING);
|
||||||
|
|
||||||
|
Sensor.SensorData.Builder bpm =
|
||||||
|
Sensor.SensorData.newBuilder()
|
||||||
|
.setValue(bpmVal)
|
||||||
|
.setState(Sensor.SensorState.SENDING);
|
||||||
|
|
||||||
|
sensorData =
|
||||||
|
Sensor.SensorDataSet.newBuilder()
|
||||||
|
.setCreationTime(time)
|
||||||
|
.setPower(power)
|
||||||
|
.setCadence(cadence)
|
||||||
|
.setHeartRate(bpm)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleChannelId(byte[] rawMessage) {
|
||||||
|
AntChannelIdMessage message = new AntChannelIdMessage(rawMessage);
|
||||||
|
deviceNumber = message.getDeviceNumber();
|
||||||
|
Log.d(TAG, "Found device id: " + deviceNumber);
|
||||||
|
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceNumber);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMessageResponse(byte[] rawMessage) {
|
||||||
|
AntChannelResponseMessage message =
|
||||||
|
new AntChannelResponseMessage(rawMessage);
|
||||||
|
if (!SystemUtils.isRelease(context)) {
|
||||||
|
Log.d(TAG, "Received ANT Response: " + AntUtils.antMessageToString(message.getMessageId()) +
|
||||||
|
"(" + message.getMessageId() + ")" +
|
||||||
|
", Code: " + AntUtils.antEventToStr(message.getMessageCode()) +
|
||||||
|
"(" + message.getMessageCode() + ")");
|
||||||
|
}
|
||||||
|
switch (message.getMessageId()) {
|
||||||
|
case AntMesg.MESG_EVENT_ID:
|
||||||
|
if (message.getMessageCode() == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
|
||||||
|
// Search timeout
|
||||||
|
Log.w(TAG, "Search timed out. Unassigning channel.");
|
||||||
|
try {
|
||||||
|
getAntReceiver().ANTUnassignChannel((byte) 0);
|
||||||
|
} catch (AntInterfaceException e) {
|
||||||
|
Log.e(TAG, "ANT error unassigning channel", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AntMesg.MESG_UNASSIGN_CHANNEL_ID:
|
||||||
|
setSensorState(Sensor.SensorState.DISCONNECTED);
|
||||||
|
Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void setupAntSensorChannels() {
|
||||||
|
Log.i(TAG, "Setting up ANT sensor channels");
|
||||||
|
setupAntSensorChannel(
|
||||||
|
NETWORK_NUMBER,
|
||||||
|
CHANNEL_NUMBER,
|
||||||
|
deviceNumber,
|
||||||
|
DEVICE_TYPE,
|
||||||
|
(byte) 0x01,
|
||||||
|
CHANNEL_PERIOD,
|
||||||
|
RF_FREQUENCY,
|
||||||
|
(byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getDeviceNumber() {
|
||||||
|
return deviceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDeviceNumber(short deviceNumber) {
|
||||||
|
this.deviceNumber = deviceNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,10 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.sensors.ant;
|
package com.google.android.apps.mytracks.services.sensors.ant;
|
||||||
|
|
||||||
|
import com.dsi.ant.AntDefine;
|
||||||
import com.dsi.ant.AntInterface;
|
import com.dsi.ant.AntInterface;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for ANT functionality.
|
* Utility methods for ANT functionality.
|
||||||
*
|
*
|
||||||
@@ -32,4 +38,47 @@ public class AntUtils {
|
|||||||
public static boolean hasAntSupport(Context context) {
|
public static boolean hasAntSupport(Context context) {
|
||||||
return AntInterface.hasAntSupport(context);
|
return AntInterface.hasAntSupport(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the names of in the messages with the given value
|
||||||
|
*/
|
||||||
|
public static String antMessageToString(byte msg) {
|
||||||
|
return findConstByteInClass(AntDefine.class, msg, "MESG_.*_ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the names of in the events with the given value
|
||||||
|
*/
|
||||||
|
public static String antEventToStr(byte event) {
|
||||||
|
return findConstByteInClass(AntDefine.class, event, ".*EVENT.*");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a set of constant static byte field declarations in the class that have the given value
|
||||||
|
* and whose name match the given pattern
|
||||||
|
* @param cl class to search in
|
||||||
|
* @param value value of constant static byte field declarations to match
|
||||||
|
* @param regexPattern pattern to match against the name of the field
|
||||||
|
* @return a set of the names of fields, expressed as a string
|
||||||
|
*/
|
||||||
|
private static String findConstByteInClass(Class<?> cl, byte value, String regexPattern)
|
||||||
|
{
|
||||||
|
Field[] fields = cl.getDeclaredFields();
|
||||||
|
Set<String> fieldSet = new HashSet<String>();
|
||||||
|
for (Field f : fields) {
|
||||||
|
try {
|
||||||
|
if (f.getType() == Byte.TYPE &&
|
||||||
|
(f.getModifiers() & Modifier.STATIC) != 0 &&
|
||||||
|
f.getName().matches(regexPattern) &&
|
||||||
|
f.getByte(null) == value) {
|
||||||
|
fieldSet.add(f.getName());
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// ignore
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fieldSet.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user