merge heads

This commit is contained in:
Jimmy Shih
2011-10-20 18:05:58 -07:00
37 changed files with 848 additions and 144 deletions
+6
View File
@@ -67,3 +67,9 @@
# Needed by Guava
-dontwarn sun.misc.Unsafe
# Keep services needed by ANT+ protocol
-keep public class com.dsi.ant.IAnt_6
-keep public class com.dsi.ant.IAnt
-keep public class com.dsi.ant.IServiceSettings
@@ -86,7 +86,7 @@ class CheckUnits {
}
private static void recordCheckPerformed(SharedPreferences preferences) {
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true));
}
@@ -65,7 +65,7 @@ public class DeleteAllTracks extends Handler {
SharedPreferences.Editor editor = prefs.edit();
// TODO: Go through data manager
editor.putLong(context.getString(R.string.selected_track_key), -1);
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
if (done != null) {
Handler h = new Handler();
h.post(done);
@@ -108,7 +108,7 @@ public class DeleteTrack extends Activity
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
Editor editor = preferences.edit().putLong(selectedKey, -1);
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
}
}
}
@@ -95,7 +95,7 @@ class Eula {
}
private static void accept(Activity activity, SharedPreferences preferences) {
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
Intent startIntent = new Intent(activity, WelcomeActivity.class);
activity.startActivityForResult(startIntent, Constants.WELCOME);
@@ -134,7 +134,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
super.onCreate(savedInstanceState);
ApiFeatures apiFeatures = ApiFeatures.getInstance();
if (!SystemUtils.isRelease(this)) {
apiFeatures.getApiPlatformAdapter().enableStrictMode();
apiFeatures.getApiAdapter().enableStrictMode();
}
tracker = GoogleAnalyticsTracker.getInstance();
@@ -93,7 +93,7 @@ public class SettingsActivity extends PreferenceActivity {
preferenceManager.setSharedPreferencesMode(0);
// Set up automatic preferences backup
backupListener = BackupPreferencesListener.create(this, apiFeatures);
backupListener = apiFeatures.getApiAdapter().getBackupPreferencesListener(this);
preferences = preferenceManager.getSharedPreferences();
preferences.registerOnSharedPreferenceChangeListener(backupListener);
@@ -397,7 +397,7 @@ public class TrackDataHub {
// Save the selection to memory and flush.
selectedTrackId = trackId;
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
// Force it to reload data from the beginning.
@@ -41,8 +41,6 @@ import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.util.Strings;
import android.app.Activity;
@@ -140,8 +138,7 @@ public class SendToFusionTables implements Runnable {
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
HttpTransport transport = ApiFeatures.getInstance().useNetHttpTransport()
? new NetHttpTransport() : new ApacheHttpTransport();
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
}
@@ -15,63 +15,13 @@
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.app.backup.BackupManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
/**
* Shared preferences listener which notifies the backup system about new data
* being available for backup.
* This class is API-version-safe and will provide a dummy implementation if
* the device doesn't support backup services.
*
* @author Rodrigo Damazio
*/
public abstract class BackupPreferencesListener
implements OnSharedPreferenceChangeListener {
/**
* Real implementation of the listener, which calls the {@link BackupManager}.
*/
private static class BackupPreferencesListenerImpl
extends BackupPreferencesListener {
private final BackupManager backupManager;
public BackupPreferencesListenerImpl(Context context) {
this.backupManager = new BackupManager(context);
}
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
backupManager.dataChanged();
}
}
/**
* Dummy implementation of the listener which does nothing.
*/
private static class DummyBackupPreferencesListener
extends BackupPreferencesListener {
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
// Do nothing
}
}
/**
* Creates and returns a proper instance of the listener for this device.
*/
public static BackupPreferencesListener create(
Context context, ApiFeatures apiFeatures) {
if (apiFeatures.hasBackup()) {
return new BackupPreferencesListenerImpl(context);
} else {
return new DummyBackupPreferencesListener();
}
}
public interface BackupPreferencesListener extends OnSharedPreferenceChangeListener {
}
@@ -0,0 +1,40 @@
/*
* 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.io.backup;
import android.app.backup.BackupManager;
import android.content.Context;
import android.content.SharedPreferences;
/**
* Implementation of {@link BackupPreferencesListener} that calls the
* {@link BackupManager}.
*
* @author Jimmy Shih
*/
public class BackupPreferencesListenerImpl implements BackupPreferencesListener {
private final BackupManager backupManager;
public BackupPreferencesListenerImpl(Context context) {
this.backupManager = new BackupManager(context);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
backupManager.dataChanged();
}
}
@@ -48,7 +48,7 @@ import java.util.Locale;
class DocsTagBuilder {
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
ApiFeatures.getInstance().getApiPlatformAdapter().getDecimalFormatSymbols(Locale.ENGLISH);
ApiFeatures.getInstance().getApiAdapter().getDecimalFormatSymbols(Locale.ENGLISH);
private static final NumberFormat LARGE_UNIT_FORMAT =
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
private static final NumberFormat SMALL_UNIT_FORMAT =
@@ -37,7 +37,7 @@ import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.ApiPlatformAdapter;
import com.google.android.apps.mytracks.util.ApiLevelAdapter;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -485,8 +485,8 @@ public class TrackRecordingService extends Service {
* Shows the notification message and icon in the notification bar.
*/
private void showNotification() {
final ApiPlatformAdapter apiPlatformAdapter =
ApiFeatures.getInstance().getApiPlatformAdapter();
final ApiLevelAdapter apiLevelAdapter =
ApiFeatures.getInstance().getApiAdapter();
if (isRecording) {
Notification notification = new Notification(
R.drawable.arrow_320, null /* tickerText */,
@@ -497,10 +497,10 @@ public class TrackRecordingService extends Service {
notification.setLatestEventInfo(this, getString(R.string.app_name),
getString(R.string.recording_your_track), contentIntent);
notification.flags += Notification.FLAG_NO_CLEAR;
apiPlatformAdapter.startForeground(this, notificationManager, 1,
apiLevelAdapter.startForeground(this, notificationManager, 1,
notification);
} else {
apiPlatformAdapter.stopForeground(this, notificationManager, 1);
apiLevelAdapter.stopForeground(this, notificationManager, 1);
}
}
@@ -62,7 +62,7 @@ public class ZephyrMessageParser implements MessageParser {
// 0x1A00316550003162 produces erroneous values for Cadence and needs
// a workaround based on the stride counter.
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
byte[] hardwareFirmwareId = ApiFeatures.getInstance().getApiPlatformAdapter()
byte[] hardwareFirmwareId = ApiFeatures.getInstance().getApiAdapter()
.copyByteArray(buffer, 3, 11);
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
@@ -22,6 +22,7 @@ import com.dsi.ant.AntInterface;
import com.dsi.ant.AntInterfaceIntent;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.dsi.ant.exception.AntServiceNotConnectedException;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.SensorManager;
@@ -142,13 +143,16 @@ public abstract class AntSensorManager extends SensorManager {
Log.w(TAG, "Failed to unregister ANT data receiver", e);
}
try {
antReceiver.releaseInterface();
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to release ANT interface", e);
if (antReceiver != null) {
try {
antReceiver.releaseInterface();
} catch (AntServiceNotConnectedException e) {
Log.i(TAG, "ANT service not connected", e);
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to release ANT interface", e);
}
antReceiver.destroy();
}
antReceiver.destroy();
}
@Override
@@ -236,7 +240,7 @@ public abstract class AntSensorManager extends SensorManager {
/**
* Process a raw ANT message.
* @param antMessage the ANT message, including the size and message ID bytes
* @deprecated Use {@link #handleMessage(int, byte[])} instead.
* @deprecated Use {@link #handleMessage(byte, byte[])} instead.
*/
protected void handleMessage(byte[] antMessage) {
int len = antMessage[0];
@@ -37,11 +37,7 @@ public class StatusAnnouncerFactory implements PeriodicTaskFactory {
@Override
public PeriodicTask create(Context context) {
if (hasTts) {
if (ApiFeatures.getInstance().isAudioFocusSupported()) {
return new FroyoStatusAnnouncerTask(context);
} else {
return new StatusAnnouncerTask(context);
}
return ApiFeatures.getInstance().getApiAdapter().getStatusAnnouncerTask(context);
} else {
return null;
}
@@ -16,11 +16,7 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.Constants;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.util.Log;
@@ -33,7 +29,7 @@ import android.util.Log;
public class ApiFeatures {
/**
* The API level of the Android version we're being run under.
* The API level of the Android version we are being run under.
*/
private static final int ANDROID_API_LEVEL = Integer.parseInt(
Build.VERSION.SDK);
@@ -41,9 +37,9 @@ public class ApiFeatures {
private static ApiFeatures instance;
/**
* The API platform adapter supported by this system.
* The API level adapter for the Android version we are being run under.
*/
private ApiPlatformAdapter apiPlatformAdapter;
private ApiLevelAdapter apiLevelAdapter;
/**
* Returns the singleton instance of this class.
@@ -70,18 +66,20 @@ public class ApiFeatures {
// It is safe to import unsupported classes as long as we only actually
// load the class when supported.
if (getApiLevel() >= 9) {
apiPlatformAdapter = new GingerbreadPlatformAdapter();
apiLevelAdapter = new ApiLevel9Adapter();
} else if (getApiLevel() >= 8) {
apiLevelAdapter = new ApiLevel8Adapter();
} else if (getApiLevel() >= 5) {
apiPlatformAdapter = new EclairPlatformAdapter();
apiLevelAdapter = new ApiLevel5Adapter();
} else {
apiPlatformAdapter = new CupcakePlatformAdapter();
apiLevelAdapter = new ApiLevel3Adapter();
}
Log.i(Constants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
Log.i(Constants.TAG, "Using API level adapter " + apiLevelAdapter.getClass());
}
public ApiPlatformAdapter getApiPlatformAdapter() {
return apiPlatformAdapter;
public ApiLevelAdapter getApiAdapter() {
return apiLevelAdapter;
}
// API Level 4 Changes
@@ -107,35 +105,11 @@ public class ApiFeatures {
return getApiLevel() >= 5;
}
// API Level 8 Changes
public boolean isAudioFocusSupported() {
return getApiLevel() >= 8;
}
/**
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
*/
public boolean hasBackup() {
return getApiLevel() >= 8;
}
// API Level 9 Changes
/**
* Returns true if {@link NetHttpTransport} should be used rather than
* {@link ApacheHttpTransport}. See {@link HttpTransport} for more info.
*/
public boolean useNetHttpTransport() {
return getApiLevel() >= 9;
}
// API Level 10 changes
/**
* Returns true if
* {@link BluetoothDevice#createInsecureRfcommSocketToServiceRecord} is
* available.
* Returns true if BluetoothDevice.createInsecureRfcommSocketToServiceRecord
* is available.
*/
public boolean hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord() {
return getApiLevel() >= 10;
@@ -17,9 +17,17 @@ package com.google.android.apps.mytracks.util;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.apache.ApacheHttpTransport;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;
@@ -29,12 +37,11 @@ import java.text.DecimalFormatSymbols;
import java.util.Locale;
/**
* The Cupcake (API level 3) specific implementation of the
* {@link ApiPlatformAdapter}.
*
* API level 3 specific implementation of the {@link ApiLevelAdapter}.
*
* @author Bartlomiej Niechwiej
*/
public class CupcakePlatformAdapter implements ApiPlatformAdapter {
public class ApiLevel3Adapter implements ApiLevelAdapter {
@Override
public void startForeground(Service service,
@@ -53,6 +60,21 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
notificationManager.cancel(id);
}
}
@Override
public PeriodicTask getStatusAnnouncerTask(Context context) {
return new StatusAnnouncerTask(context);
}
@Override
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
return new BackupPreferencesListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// Do nothing
}
};
}
private void setServiceForeground(Service service, boolean foreground) {
// setForeground has been completely removed in API level 11, so we use reflection.
@@ -94,4 +116,9 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
return new DecimalFormatSymbols(locale);
}
@Override
public HttpTransport getHttpTransport() {
return new ApacheHttpTransport();
}
}
@@ -20,12 +20,11 @@ import android.app.NotificationManager;
import android.app.Service;
/**
* The Eclair (API level 5) specific implementation of the
* {@link ApiPlatformAdapter}.
*
* API level 5 specific implementation of the {@link ApiLevelAdapter}.
*
* @author Bartlomiej Niechwiej
*/
public class EclairPlatformAdapter extends CupcakePlatformAdapter {
public class ApiLevel5Adapter extends ApiLevel3Adapter {
@Override
public void startForeground(Service service,
@@ -0,0 +1,26 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListenerImpl;
import com.google.android.apps.mytracks.services.tasks.FroyoStatusAnnouncerTask;
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
import android.content.Context;
/**
* API level 8 specific implementation of the {@link ApiLevelAdapter}.
*
* @author Jimmy Shih
*/
public class ApiLevel8Adapter extends ApiLevel5Adapter {
@Override
public PeriodicTask getStatusAnnouncerTask(Context context) {
return new FroyoStatusAnnouncerTask(context);
}
@Override
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
return new BackupPreferencesListenerImpl(context);
}
}
@@ -1,6 +1,8 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.Constants;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import android.content.SharedPreferences.Editor;
import android.os.StrictMode;
@@ -11,12 +13,11 @@ import java.util.Arrays;
import java.util.Locale;
/**
* The Gingerbread (API level 9) specific implememntation of the
* {@link ApiPlatformAdapter}.
* API level 9 specific implementation of the {@link ApiLevelAdapter}.
*
* @author Rodrigo Damazio
*/
public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
public class ApiLevel9Adapter extends ApiLevel8Adapter {
@Override
public void applyPreferenceChanges(Editor editor) {
@@ -47,4 +48,9 @@ public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
return DecimalFormatSymbols.getInstance(locale);
}
@Override
public HttpTransport getHttpTransport() {
return new NetHttpTransport();
}
}
@@ -15,24 +15,31 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
import com.google.api.client.http.HttpTransport;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.SharedPreferences;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
/**
* A set of methods that may be implemented in a platform specific way.
* A set of methods that may be implemented differently depending on the Android API level.
*
* @author Bartlomiej Niechwiej
*/
public interface ApiPlatformAdapter {
public interface ApiLevelAdapter {
/**
* Puts the specified service into foreground.
*
* Due to changes in API level 5.
*
* @param service the service to be put in foreground.
* @param notificationManager the notification manager used to post the given
* notification.
@@ -44,6 +51,9 @@ public interface ApiPlatformAdapter {
/**
* Puts the given service into background.
*
* Due to changes in API level 5.
*
* @param service the service to put into background.
* @param notificationManager the notification manager to user when removing
* notifications.
@@ -53,14 +63,32 @@ public interface ApiPlatformAdapter {
void stopForeground(Service service, NotificationManager notificationManager,
int id);
/**
* Gets a status announcer task.
*
* Due to changes in API level 8.
*/
PeriodicTask getStatusAnnouncerTask(Context context);
/**
* Gets a {@link BackupPreferencesListener}.
*
* Due to changes in API level 8.
*/
BackupPreferencesListener getBackupPreferencesListener(Context context);
/**
* Applies all changes done to the given preferences editor.
* Changes may or may not be applied immediately.
*
* Due to changes in API level 9.
*/
void applyPreferenceChanges(SharedPreferences.Editor editor);
/**
* Enables strict mode where supported, only if this is a development build.
*
* Due to changes in API level 9.
*/
void enableStrictMode();
@@ -69,6 +97,8 @@ public interface ApiPlatformAdapter {
* indexes start (inclusive) to end (exclusive). The end index must be less
* than or equal to input.length.
*
* Due to changes in API level 9.
*
* @param input the input byte array
* @param start the start index
* @param end the end index
@@ -80,8 +110,17 @@ public interface ApiPlatformAdapter {
/**
* Gets an instance of {@link DecimalFormatSymbols} for a locale.
*
* Due to changes in API level 9.
*
* @param locale the locale
* @return a new instance of {@link DecimalFormatSymbols}
*/
DecimalFormatSymbols getDecimalFormatSymbols(Locale locale);
/**
* Gets a {@link HttpTransport}.
*
* Due to changes in API level 9.
*/
HttpTransport getHttpTransport();
}