summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJorge Ruesga <jorge@ruesga.com>2013-10-06 00:45:02 +0200
committerAdnan Begovic <adnan@cyngn.com>2015-10-29 17:36:31 -0700
commit14c91238695b94d3bdff6404e3b791fb00a4375f (patch)
tree3b636ed96d51d6506bd35f889d0b14a67a579933 /src
parent5a0870b86f0ea1c6b327f9b7c42fd5c3e4b3b2d7 (diff)
downloadpackages_apps_Settings-14c91238695b94d3bdff6404e3b791fb00a4375f.zip
packages_apps_Settings-14c91238695b94d3bdff6404e3b791fb00a4375f.tar.gz
packages_apps_Settings-14c91238695b94d3bdff6404e3b791fb00a4375f.tar.bz2
Settings: Long Term Orbits (LTO)
Change-Id: I1fbdba644fc05d55fc096b47bfac3f9903383370 Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
Diffstat (limited to 'src')
-rw-r--r--src/com/android/settings/cyanogenmod/BootReceiver.java2
-rw-r--r--src/com/android/settings/cyanogenmod/LtoService.java337
-rw-r--r--src/com/android/settings/location/LocationSettings.java96
3 files changed, 434 insertions, 1 deletions
diff --git a/src/com/android/settings/cyanogenmod/BootReceiver.java b/src/com/android/settings/cyanogenmod/BootReceiver.java
index 4d56e60..d1a16ea 100644
--- a/src/com/android/settings/cyanogenmod/BootReceiver.java
+++ b/src/com/android/settings/cyanogenmod/BootReceiver.java
@@ -26,6 +26,7 @@ import com.android.settings.Utils;
import com.android.settings.hardware.VibratorIntensity;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.livedisplay.DisplayGamma;
+import com.android.settings.location.LocationSettings;
public class BootReceiver extends BroadcastReceiver {
@@ -40,5 +41,6 @@ public class BootReceiver extends BroadcastReceiver {
VibratorIntensity.restore(ctx);
DisplaySettings.restore(ctx);
InputMethodAndLanguageSettings.restore(ctx);
+ LocationSettings.restore(ctx);
}
}
diff --git a/src/com/android/settings/cyanogenmod/LtoService.java b/src/com/android/settings/cyanogenmod/LtoService.java
new file mode 100644
index 0000000..8bbf8c8
--- /dev/null
+++ b/src/com/android/settings/cyanogenmod/LtoService.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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.settings.cyanogenmod;
+
+import static android.hardware.CmHardwareManager.FEATURE_LONG_TERM_ORBITS;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.hardware.CmHardwareManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.UserHandle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.android.settings.location.LocationSettings;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+
+public class LtoService extends Service {
+ private static final String TAG = "LtoService";
+ private static final boolean ALOGV = true;
+
+ private static final String KEY_LAST_DOWNLOAD = "lto_last_download";
+
+ public static final String ACTION_NEW_GPS_DATA = "com.cyanogenmod.actions.NEW_GPS_DATA";
+
+ private static final int DOWNLOAD_TIMEOUT = 45000; /* 45 seconds */
+
+ private CmHardwareManager mCmHardwareManager;
+ private LtoDownloadTask mTask;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (mCmHardwareManager == null ||
+ !mCmHardwareManager.isSupported(FEATURE_LONG_TERM_ORBITS)) {
+ if (ALOGV) Log.v(TAG, "LTO is not supported by this device");
+ return START_NOT_STICKY;
+ }
+ if (!LocationSettings.isLocationModeEnabled(this)) {
+ if (ALOGV) Log.v(TAG, "Location mode not enabled in this device");
+ return START_NOT_STICKY;
+ }
+
+ if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED) {
+ if (ALOGV) Log.v(TAG, "LTO download is still active, not starting new download");
+ return START_REDELIVER_INTENT;
+ }
+
+ if (!shouldDownload()) {
+ Log.d(TAG, "Service started, but shouldn't download ... stopping");
+ stopSelf();
+ return START_NOT_STICKY;
+ }
+
+ mTask = new LtoDownloadTask(mCmHardwareManager.getLtoSource(),
+ new File(mCmHardwareManager.getLtoDestination()));
+ mTask.execute();
+
+ return START_REDELIVER_INTENT;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mCmHardwareManager = (CmHardwareManager) getSystemService(Context.CMHW_SERVICE);
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED) {
+ mTask.cancel(true);
+ mTask = null;
+ }
+ }
+
+ private boolean shouldDownload() {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
+ NetworkInfo info = cm.getActiveNetworkInfo();
+
+ if (info == null || !info.isConnected()) {
+ if (ALOGV) Log.v(TAG, "No network connection is available for LTO download");
+ } else {
+ boolean wifiOnly = prefs.getBoolean(
+ LocationSettings.KEY_LTO_DOWNLOAD_DATA_WIFI_ONLY, false);
+ if (wifiOnly && info.getType() != ConnectivityManager.TYPE_WIFI) {
+ if (ALOGV) {
+ Log.v(TAG, "Active network is of type " +
+ info.getTypeName() + ", but Wifi only was selected");
+ }
+ return false;
+ }
+ }
+
+ long now = System.currentTimeMillis();
+ long lastDownload = getLastDownload();
+ long due = lastDownload + mCmHardwareManager.getLtoDownloadInterval();
+
+ if (ALOGV) {
+ Log.v(TAG, "Now " + now + " due " + due + "(" + new Date(due) + ")");
+ }
+
+ if (lastDownload != 0 && now < due) {
+ if (ALOGV) Log.v(TAG, "LTO download is not due yet");
+ return false;
+ }
+
+ return true;
+ }
+
+ private class LtoDownloadTask extends AsyncTask<Void, Integer, Integer> {
+ private String mSource;
+ private File mDestination;
+ private File mTempFile;
+ private WakeLock mWakeLock;
+
+ private static final int RESULT_SUCCESS = 0;
+ private static final int RESULT_FAILURE = 1;
+ private static final int RESULT_CANCELLED = 2;
+
+ public LtoDownloadTask(String source, File destination) {
+ mSource = source;
+ mDestination = destination;
+ try {
+ mTempFile = File.createTempFile("lto-download", null, getCacheDir());
+ } catch (IOException e) {
+ Log.w(TAG, "Could not create temporary file", e);
+ }
+
+ PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mWakeLock.acquire();
+ }
+
+ @Override
+ protected Integer doInBackground(Void... params) {
+ BufferedInputStream in = null;
+ BufferedOutputStream out = null;
+ int result = RESULT_SUCCESS;
+
+ try {
+ final URLConnection connection = new URL(mSource).openConnection();
+ connection.setRequestProperty("Connection", "close");
+ connection.setConnectTimeout(DOWNLOAD_TIMEOUT);
+ connection.setReadTimeout(DOWNLOAD_TIMEOUT);
+ final Thread interruptThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(DOWNLOAD_TIMEOUT);
+ ((HttpURLConnection)connection).disconnect();
+ } catch (InterruptedException e) {
+ }
+ }
+ });
+ interruptThread.start();
+
+ File outputFile = mTempFile != null ? mTempFile : mDestination;
+
+ in = new BufferedInputStream(connection.getInputStream());
+ out = new BufferedOutputStream(new FileOutputStream(outputFile));
+
+ byte[] buffer = new byte[2048];
+ int count, total = 0;
+ long length = 0;
+ try {
+ String value = connection.getHeaderField("Content-Length");
+ if (value != null) {
+ length = Long.parseLong(value);
+ }
+ } catch (NumberFormatException ex) {
+ // Ignore
+ }
+
+ // Read all the buffer
+ while ((count = in.read(buffer, 0, buffer.length)) != -1) {
+ if (isCancelled()) {
+ result = RESULT_CANCELLED;
+ break;
+ }
+ out.write(buffer, 0, count);
+ total += count;
+
+ if (length > 0) {
+ float progress = (float) total * 100 / length;
+ publishProgress((int) progress);
+ }
+ }
+
+ // The file is currently downloaded. Interrupt the timeout thread
+ interruptThread.interrupt();
+
+ Log.d(TAG, "Downloaded " + total + "/" + length + " bytes of LTO data");
+ if (total == 0 || (length > 0 && total != length)) {
+ result = RESULT_FAILURE;
+ }
+ in.close();
+ out.close();
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "URI syntax wrong", e);
+ result = RESULT_FAILURE;
+ } catch (IOException e) {
+ Log.e(TAG, "Failed downloading LTO data", e);
+ result = RESULT_FAILURE;
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Log.d(TAG, "return " + result);
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ if (result != null) {
+ finish(result);
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ finish(RESULT_CANCELLED);
+ }
+
+ private void finish(int result) {
+ final Context context = LtoService.this;
+
+ if (mTempFile != null) {
+ if (result == RESULT_SUCCESS) {
+ mDestination.delete();
+ if (!mTempFile.renameTo(mDestination)) {
+ Log.w(TAG, "Could not move temporary file to destination");
+ } else {
+ mDestination.setReadable(true, false);
+ }
+ }
+ mTempFile.delete();
+ } else if (result != RESULT_SUCCESS) {
+ mDestination.delete();
+ } else {
+ mDestination.setReadable(true, false);
+ }
+
+ if (result == RESULT_SUCCESS) {
+ long now = System.currentTimeMillis();
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putLong(KEY_LAST_DOWNLOAD, now);
+ editor.apply();
+ scheduleNextDownload(now);
+ notifyNewGpsData();
+
+ } else if (result == RESULT_FAILURE) {
+ /* failure, schedule next download in 1 hour */
+ long lastDownload = getLastDownload() + (60 * 60 * 1000);
+ scheduleNextDownload(lastDownload);
+ } else {
+ /* cancelled, likely due to lost network - we'll get restarted
+ * when network comes back */
+ }
+
+ mWakeLock.release();
+ stopSelf();
+ }
+ }
+
+ private void notifyNewGpsData() {
+ Intent intent = new Intent(ACTION_NEW_GPS_DATA);
+ sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ private PendingIntent scheduleNextDownload(long lastDownload) {
+ AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(this, LtoService.class);
+ PendingIntent pi = PendingIntent.getService(this, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+
+ long nextLtoDownload = lastDownload + mCmHardwareManager.getLtoDownloadInterval();
+ am.set(AlarmManager.RTC, nextLtoDownload, pi);
+ return pi;
+ }
+
+ private long getLastDownload() {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ return prefs.getLong(LtoService.KEY_LAST_DOWNLOAD, 0);
+ }
+}
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index b78cd31..d3f0ac8 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +17,17 @@
package com.android.settings.location;
+import static android.hardware.CmHardwareManager.FEATURE_LONG_TERM_ORBITS;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.hardware.CmHardwareManager;
import android.location.SettingInjectorService;
import android.os.Bundle;
import android.os.UserHandle;
@@ -27,7 +35,10 @@ import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -37,6 +48,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
+import com.android.settings.cyanogenmod.LtoService;
import com.android.settings.widget.SwitchBar;
import java.util.Collections;
@@ -69,7 +81,7 @@ import java.util.List;
* implementation.
*/
public class LocationSettings extends LocationSettingsBase
- implements SwitchBar.OnSwitchChangeListener {
+ implements SwitchBar.OnSwitchChangeListener, OnPreferenceChangeListener {
private static final String TAG = "LocationSettings";
@@ -93,12 +105,16 @@ public class LocationSettings extends LocationSettingsBase
private static final int MENU_SCANNING = Menu.FIRST;
+ /** Key for preference LTO over Wi-Fi only */
+ public static final String KEY_LTO_DOWNLOAD_DATA_WIFI_ONLY = "lto_download_data_wifi_only";
+
private SwitchBar mSwitchBar;
private Switch mSwitch;
private boolean mValidListener = false;
private UserHandle mManagedProfile;
private Preference mManagedProfilePreference;
private Preference mLocationMode;
+ private SwitchPreference mLtoDownloadDataWifiOnly;
private PreferenceCategory mCategoryRecentLocationRequests;
/** Receives UPDATE_INTENT */
private BroadcastReceiver mReceiver;
@@ -191,6 +207,17 @@ public class LocationSettings extends LocationSettingsBase
}
});
+ mLtoDownloadDataWifiOnly =
+ (SwitchPreference) root.findPreference(KEY_LTO_DOWNLOAD_DATA_WIFI_ONLY);
+ if (mLtoDownloadDataWifiOnly != null) {
+ if (!isLtoSupported(activity) || !checkGpsDownloadWiFiOnly(activity)) {
+ root.removePreference(mLtoDownloadDataWifiOnly);
+ mLtoDownloadDataWifiOnly = null;
+ } else {
+ mLtoDownloadDataWifiOnly.setOnPreferenceChangeListener(this);
+ }
+ }
+
mCategoryRecentLocationRequests =
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
RecentLocationApps recentApps = new RecentLocationApps(activity);
@@ -334,6 +361,9 @@ public class LocationSettings extends LocationSettingsBase
// Disable the whole switch bar instead of the switch itself. If we disabled the switch
// only, it would be re-enabled again if the switch bar is not disabled.
mSwitchBar.setEnabled(!restricted);
+ if (mLtoDownloadDataWifiOnly != null) {
+ mLtoDownloadDataWifiOnly.setEnabled(enabled && !restricted);
+ }
mLocationMode.setEnabled(enabled && !restricted);
mCategoryRecentLocationRequests.setEnabled(enabled);
@@ -377,4 +407,68 @@ public class LocationSettings extends LocationSettingsBase
setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
}
}
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (mLtoDownloadDataWifiOnly != null && preference.equals(mLtoDownloadDataWifiOnly)) {
+ updateLtoServiceStatus(getActivity(), isLocationModeEnabled(getActivity()));
+ }
+ return true;
+ }
+
+ private static void updateLtoServiceStatus(Context context, boolean start) {
+ Intent intent = new Intent(context, LtoService.class);
+ if (start) {
+ context.startService(intent);
+ } else {
+ context.stopService(intent);
+ }
+ }
+
+ private static boolean checkGpsDownloadWiFiOnly(Context context) {
+ PackageManager pm = context.getPackageManager();
+ boolean supportsTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ boolean supportsWifi = pm.hasSystemFeature(PackageManager.FEATURE_WIFI);
+ if (!supportsWifi || !supportsTelephony) {
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putBoolean(KEY_LTO_DOWNLOAD_DATA_WIFI_ONLY, supportsWifi);
+ editor.apply();
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isLocationModeEnabled(Context context) {
+ int mode = android.provider.Settings.Secure.getInt(context.getContentResolver(),
+ android.provider.Settings.Secure.LOCATION_MODE,
+ android.provider.Settings.Secure.LOCATION_MODE_OFF);
+ return (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF);
+ }
+
+ /**
+ * Restore the properties associated with this preference on boot
+ * @param ctx A valid context
+ */
+ public static void restore(final Context context) {
+ if (isLtoSupported(context) && isLocationModeEnabled(context)) {
+ // Check and adjust the value for Gps download data on wifi only
+ checkGpsDownloadWiFiOnly(context);
+
+ // Starts the LtoService, but delayed 2 minutes after boot (this should give a
+ // proper time to start all device services)
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(context, LtoService.class);
+ PendingIntent pi = PendingIntent.getService(context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+ long nextLtoDownload = System.currentTimeMillis() + (1000 * 60 * 2L);
+ am.set(AlarmManager.RTC, nextLtoDownload, pi);
+ }
+ }
+
+ private static boolean isLtoSupported(Context context) {
+ final CmHardwareManager hwManager =
+ (CmHardwareManager) context.getSystemService(Context.CMHW_SERVICE);
+ return hwManager != null && hwManager.isSupported(FEATURE_LONG_TERM_ORBITS);
+ }
}