import android.os.ServiceManager;
import android.util.Log;
+import com.android.server.net.BaseNetworkObserver;
+
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
* ConnectivityService.
* @hide
*/
- public class EthernetDataTracker implements NetworkStateTracker {
+ public class EthernetDataTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "ETHERNET";
private static final String TAG = "Ethernet";
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
private static boolean mLinkUp;
- private LinkProperties mLinkProperties;
- private LinkCapabilities mLinkCapabilities;
- private NetworkInfo mNetworkInfo;
private InterfaceObserver mInterfaceObserver;
private String mHwAddr;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
- private Context mContext;
private static EthernetDataTracker sInstance;
private static String sIfaceMatch = "";
private INetworkManagementService mNMService;
- private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
+ private static class InterfaceObserver extends BaseNetworkObserver {
private EthernetDataTracker mTracker;
InterfaceObserver(EthernetDataTracker tracker) {
mTracker = tracker;
}
+ @Override
public void interfaceStatusChanged(String iface, boolean up) {
Log.d(TAG, "Interface status changed: " + iface + (up ? "up" : "down"));
}
+ @Override
public void interfaceLinkStateChanged(String iface, boolean up) {
if (mIface.equals(iface)) {
Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
}
}
+ @Override
public void interfaceAdded(String iface) {
mTracker.interfaceAdded(iface);
}
+ @Override
public void interfaceRemoved(String iface) {
mTracker.interfaceRemoved(iface);
}
-
- public void limitReached(String limitName, String iface) {
- // Ignored.
- }
-
- public void interfaceClassDataActivityChanged(String label, boolean active) {
- // Ignored.
- }
}
private EthernetDataTracker() {
public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
/**
+ * Location access disabled
+ */
+ public static final int LOCATION_MODE_OFF = 0;
+ /**
+ * Network Location Provider disabled, but GPS and other sensors enabled.
+ */
+ public static final int LOCATION_MODE_SENSORS_ONLY = 1;
+ /**
+ * Reduced power usage, such as limiting the number of GPS updates per hour.
+ */
+ public static final int LOCATION_MODE_BATTERY_SAVING = 2;
+ /**
+ * Best-effort location computation allowed.
+ */
+ public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
+
+ /**
* A flag containing settings used for biometric weak
* @hide
*/
* @param cr the content resolver to use
* @param provider the location provider to query
* @return true if the provider is enabled
+ * @deprecated use {@link #getLocationMode(ContentResolver)}
*/
+ @Deprecated
public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
return isLocationProviderEnabledForUser(cr, provider, UserHandle.myUserId());
}
/**
- * Helper method for determining if the location master switch is enabled.
- * @param cr the content resolver to use
- * @return true if the master switch is enabled
- * @hide
- */
- public static final boolean isLocationMasterSwitchEnabled(ContentResolver cr) {
- int uid = UserHandle.myUserId();
- synchronized (mLocationSettingsLock) {
- return isLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, uid)
- || isLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, uid);
- }
- }
-
- /**
* Helper method for determining if a location provider is enabled.
* @param cr the content resolver to use
* @param provider the location provider to query
* @param userId the userId to query
* @return true if the provider is enabled
+ * @deprecated use {@link #getLocationModeForUser(ContentResolver, int)}
* @hide
*/
+ @Deprecated
public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
String allowedProviders = Settings.Secure.getStringForUser(cr,
LOCATION_PROVIDERS_ALLOWED, userId);
* @param cr the content resolver to use
* @param provider the location provider to enable or disable
* @param enabled true if the provider should be enabled
+ * @deprecated use {@link #setLocationMode(ContentResolver, int)}
*/
+ @Deprecated
public static final void setLocationProviderEnabled(ContentResolver cr,
String provider, boolean enabled) {
setLocationProviderEnabledForUser(cr, provider, enabled, UserHandle.myUserId());
}
/**
- * Thread-safe method for enabling or disabling the location master switch.
- *
- * @param cr the content resolver to use
- * @param enabled true if master switch should be enabled
- * @hide
- */
- public static final void setLocationMasterSwitchEnabled(ContentResolver cr,
- boolean enabled) {
- int uid = UserHandle.myUserId();
- synchronized (mLocationSettingsLock) {
- setLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, enabled, uid);
- setLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, enabled,
- uid);
- }
- }
-
- /**
* Thread-safe method for enabling or disabling a single location provider.
* @param cr the content resolver to use
* @param provider the location provider to enable or disable
* @param enabled true if the provider should be enabled
* @param userId the userId for which to enable/disable providers
+ * @deprecated use {@link #setLocationModeForUser(ContentResolver, int, int)}
* @hide
*/
+ @Deprecated
public static final void setLocationProviderEnabledForUser(ContentResolver cr,
String provider, boolean enabled, int userId) {
synchronized (mLocationSettingsLock) {
userId);
}
}
+
+ /**
+ * Thread-safe method for setting the location mode to one of
+ * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+ * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+ *
+ * @param cr the content resolver to use
+ * @param mode such as {@link #LOCATION_MODE_HIGH_ACCURACY}
+ * @param userId the userId for which to change mode
+ *
+ * @throws IllegalArgumentException if mode is not one of the supported values
+ */
+ public static final void setLocationModeForUser(ContentResolver cr, int mode, int userId) {
+ synchronized (mLocationSettingsLock) {
+ boolean gps = false;
+ boolean network = false;
+ switch (mode) {
+ case LOCATION_MODE_OFF:
+ break;
+ case LOCATION_MODE_SENSORS_ONLY:
+ gps = true;
+ break;
+ case LOCATION_MODE_BATTERY_SAVING:
+ network = true;
+ break;
+ case LOCATION_MODE_HIGH_ACCURACY:
+ gps = true;
+ network = true;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid location mode: " + mode);
+ }
+ Settings.Secure.setLocationProviderEnabledForUser(
+ cr, LocationManager.GPS_PROVIDER, gps, userId);
+ Settings.Secure.setLocationProviderEnabledForUser(
+ cr, LocationManager.NETWORK_PROVIDER, network, userId);
+ }
+ }
+
+ /**
+ * Thread-safe method for setting the location mode to one of
+ * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+ * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+ *
+ * @param cr the content resolver to use
+ * @param mode such as {@link #LOCATION_MODE_HIGH_ACCURACY}
+ *
+ * @throws IllegalArgumentException if mode is not one of the supported values
+ */
+ public static final void setLocationMode(ContentResolver cr, int mode) {
+ setLocationModeForUser(cr, mode, UserHandle.myUserId());
+ }
+
+ /**
+ * Thread-safe method for reading the location mode, returns one of
+ * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+ * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+ *
+ * @param cr the content resolver to use
+ * @param userId the userId for which to read the mode
+ * @return the location mode
+ */
+ public static final int getLocationModeForUser(ContentResolver cr, int userId) {
+ synchronized (mLocationSettingsLock) {
+ boolean gpsEnabled = Settings.Secure.isLocationProviderEnabledForUser(
+ cr, LocationManager.GPS_PROVIDER, userId);
+ boolean networkEnabled = Settings.Secure.isLocationProviderEnabledForUser(
+ cr, LocationManager.NETWORK_PROVIDER, userId);
+ if (gpsEnabled && networkEnabled) {
+ return LOCATION_MODE_HIGH_ACCURACY;
+ } else if (gpsEnabled) {
+ return LOCATION_MODE_SENSORS_ONLY;
+ } else if (networkEnabled) {
+ return LOCATION_MODE_BATTERY_SAVING;
+ } else {
+ return LOCATION_MODE_OFF;
+ }
+ }
+ }
+
+ /**
+ * Thread-safe method for reading the location mode, returns one of
+ * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
+ * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
+ *
+ * @param cr the content resolver to use
+ * @return the location mode
+ */
+ public static final int getLocationMode(ContentResolver cr) {
+ return getLocationModeForUser(cr, UserHandle.myUserId());
+ }
}
/**
*/
public static final String CONNECTIVITY_CHANGE_DELAY = "connectivity_change_delay";
+
+ /**
+ * Network sampling interval, in seconds. We'll generate link information
+ * about bytes/packets sent and error rates based on data sampled in this interval
+ *
+ * @hide
+ */
+
+ public static final String CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS =
+ "connectivity_sampling_interval_in_seconds";
+
/**
* The series of successively longer delays used in retrying to download PAC file.
* Last delay is used between successful PAC downloads.
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
+ <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
+ <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
<protected-broadcast
android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
<protected-broadcast
android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+ <protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+ <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
+ <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_HANDOVER_STARTED" />
+ <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
+ <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
+ <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS" />
+ <protected-broadcast android:name="android.btopp.intent.action.LIST" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN_OUTBOUND" />
+ <protected-broadcast android:name="android.btopp.intent.action.HIDE_COMPLETE" />
+ <protected-broadcast android:name="android.btopp.intent.action.CONFIRM" />
+ <protected-broadcast android:name="android.btopp.intent.action.HIDE" />
+ <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_DONE" />
+ <protected-broadcast android:name="android.btopp.intent.action.RETRY" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
<protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
<protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
<protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
<protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
+ <protected-brodcast
+ android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
<protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
<protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
<protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
<protected-broadcast android:name="android.location.GPS_ENABLED_CHANGE" />
<protected-broadcast android:name="android.location.PROVIDERS_CHANGED" />
<protected-broadcast android:name="android.location.GPS_FIX_CHANGE" />
+ <protected-broadcast android:name="android.net.proxy.PAC_REFRESH" />
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
android:label="@string/permlab_anyCodecForPlayback"
android:description="@string/permdesc_anyCodecForPlayback" />
+ <!-- Allows an application to install and/or uninstall CA certificates on
+ behalf of the user.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
+ android:protectionLevel="signature|system"
+ android:label="@string/permlab_manageCaCertificates"
+ android:description="@string/permdesc_manageCaCertificates" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+ import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.net.INetworkStatsService;
import android.net.LinkAddress;
import android.net.LinkProperties;
+ import android.net.LinkInfo;
import android.net.LinkProperties.CompareResult;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.Proxy;
import android.net.ProxyProperties;
import android.net.RouteInfo;
+ import android.net.SamplingDataTracker;
import android.net.Uri;
import android.net.wifi.WifiStateTracker;
import android.net.wimax.WimaxManagerConstants;
import java.util.Arrays;
import java.util.Collection;
import java.util.GregorianCalendar;
+ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+ import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
private static final String FAIL_FAST_TIME_MS =
"persist.radio.fail_fast_time_ms";
+ private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED =
+ "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED";
+
+ private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0;
+
+ private PendingIntent mSampleIntervalElapsedIntent;
+
+ // Set network sampling interval at 12 minutes, this way, even if the timers get
+ // aggregated, it will fire at around 15 minutes, which should allow us to
+ // aggregate this timer with other timers (specially the socket keep alive timers)
+ private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60);
+
+ // start network sampling a minute after booting ...
+ private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60);
+
+ AlarmManager mAlarmManager;
+
// used in recursive route setting to add gateways for the host for which
// a host route was requested.
private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
*/
private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
+ /**
+ * user internally to indicate that data sampling interval is up
+ */
+ private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
+
/** Handler used for internal events. */
private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
List mProtectedNetworks;
private DataConnectionStats mDataConnectionStats;
+
private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
TelephonyManager mTelephonyManager;
mDataConnectionStats = new DataConnectionStats(mContext);
mDataConnectionStats.startMonitoring();
+ // start network sampling ..
+ Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null);
+ mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
+ SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0);
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) {
+ mHandler.sendMessage(mHandler.obtainMessage
+ (EVENT_SAMPLE_INTERVAL_ELAPSED));
+ }
+ }
+ },
+ new IntentFilter(filter));
+
mPacManager = new PacManager(mContext);
}
// if (mActiveDefaultNetwork != -1) {
// currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
// }
+
for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
if (checkType == prevNetType) continue;
if (mNetConfigs[checkType] == null) continue;
// optimization should work and we need to investigate why it doesn't work.
// This could be related to how DEACTIVATE_DATA_CALL is reporting its
// complete before it is really complete.
+
// if (!mNetTrackers[checkType].isAvailable()) continue;
// if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
}
- /**
+ /**
* Reads the network specific TCP buffer sizes from SystemProperties
* net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
* wide use
*/
- private void updateNetworkSettings(NetworkStateTracker nt) {
+ private void updateNetworkSettings(NetworkStateTracker nt) {
String key = nt.getTcpBufferSizesPropName();
String bufferSizes = key == null ? null : SystemProperties.get(key);
}
}
- /**
+ /**
* Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
* which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
*
+ " != tag:" + tag);
}
}
+ case EVENT_SAMPLE_INTERVAL_ELAPSED:
+ handleNetworkSamplingTimeout();
+ break;
}
}
}
// Get the type of addresses supported by this link
LinkProperties lp = mCs.getLinkProperties(
ConnectivityManager.TYPE_MOBILE_HIPRI);
- boolean linkHasIpv4 = hasIPv4Address(lp);
- boolean linkHasIpv6 = hasIPv6Address(lp);
+ boolean linkHasIpv4 = lp.hasIPv4Address();
+ boolean linkHasIpv6 = lp.hasIPv6Address();
log("isMobileOk: linkHasIpv4=" + linkHasIpv4
+ " linkHasIpv6=" + linkHasIpv6);
}
}
- public boolean hasIPv4Address(LinkProperties lp) {
- return lp.hasIPv4Address();
- }
-
- // Not implemented in LinkProperties, do it here.
- public boolean hasIPv6Address(LinkProperties lp) {
- for (LinkAddress address : lp.getLinkAddresses()) {
- if (address.getAddress() instanceof Inet6Address) {
- return true;
- }
- }
- return false;
- }
-
private void log(String s) {
Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
}
}
}
};
+
+ @Override
+ public LinkInfo getLinkInfo(int networkType) {
+ enforceAccessPermission();
+ if (isNetworkTypeValid(networkType)) {
+ return mNetTrackers[networkType].getLinkInfo();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public LinkInfo getActiveLinkInfo() {
+ enforceAccessPermission();
+ if (isNetworkTypeValid(mActiveDefaultNetwork)) {
+ return mNetTrackers[mActiveDefaultNetwork].getLinkInfo();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public LinkInfo[] getAllLinkInfo() {
+ enforceAccessPermission();
+ final ArrayList<LinkInfo> result = Lists.newArrayList();
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ LinkInfo li = tracker.getLinkInfo();
+ if (li != null) {
+ result.add(li);
+ }
+ }
+ }
+
+ return result.toArray(new LinkInfo[result.size()]);
+ }
+
+ /* Infrastructure for network sampling */
+
+ private void handleNetworkSamplingTimeout() {
+
+ log("Sampling interval elapsed, updating statistics ..");
+
+ // initialize list of interfaces ..
+ Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
+ new HashMap<String, SamplingDataTracker.SamplingSnapshot>();
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ String ifaceName = tracker.getNetworkInterfaceName();
+ if (ifaceName != null) {
+ mapIfaceToSample.put(ifaceName, null);
+ }
+ }
+ }
+
+ // Read samples for all interfaces
+ SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample);
+
+ // process samples for all networks
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ String ifaceName = tracker.getNetworkInterfaceName();
+ SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName);
+ if (ss != null) {
+ // end the previous sampling cycle
+ tracker.stopSampling(ss);
+ // start a new sampling cycle ..
+ tracker.startSampling(ss);
+ }
+ }
+ }
+
+ log("Done.");
+
+ int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
+ DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
+
+ if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
+
+ setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
+ }
+
+ void setAlarm(int timeoutInMilliseconds, PendingIntent intent) {
+ long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
+ }
}
+