diff options
author | Roman Birg <roman@cyngn.com> | 2015-06-15 14:42:37 -0700 |
---|---|---|
committer | Adnan Begovic <adnan@cyngn.com> | 2015-11-23 14:26:12 -0800 |
commit | 0e05f466d0d4f1790542a3e33e9272d285c29c82 (patch) | |
tree | d7792a8fe27edb00a6a69bf7ac25173160d00251 /src/com/android | |
parent | 457a0871f257dd5fc29d24cb0f001db9ab6ed3ca (diff) | |
download | packages_apps_Settings-0e05f466d0d4f1790542a3e33e9272d285c29c82.tar.gz packages_apps_Settings-0e05f466d0d4f1790542a3e33e9272d285c29c82.tar.bz2 packages_apps_Settings-0e05f466d0d4f1790542a3e33e9272d285c29c82.zip |
Settings: update community metrics
- Send community metrics to CM.org as well as Cyanogen server
- Kill off Google Analytics
- Use JobScheduler to intelligently schedule uploads when network
connection is available
Change-Id: Ibd7d84a961dda4af20db9226191380e9f977b5de
Signed-off-by: Roman Birg <roman@cyngn.com>
Diffstat (limited to 'src/com/android')
4 files changed, 460 insertions, 149 deletions
diff --git a/src/com/android/settings/cmstats/AnonymousStats.java b/src/com/android/settings/cmstats/AnonymousStats.java index cd7987034..beffb9ffd 100644 --- a/src/com/android/settings/cmstats/AnonymousStats.java +++ b/src/com/android/settings/cmstats/AnonymousStats.java @@ -20,14 +20,20 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; +import android.util.ArraySet; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import java.util.Set; + public class AnonymousStats extends SettingsPreferenceFragment { private static final String PREF_FILE_NAME = "CMStats"; /* package */ static final String ANONYMOUS_OPT_IN = "pref_anonymous_opt_in"; /* package */ static final String ANONYMOUS_LAST_CHECKED = "pref_anonymous_checked_in"; + /* package */ static final String KEY_JOB_QUEUE = "pref_job_queue"; + /* package */ static final int QUEUE_MAX_THRESHOLD = 1000; + public static SharedPreferences getPreferences(Context context) { return context.getSharedPreferences(PREF_FILE_NAME, 0); } @@ -37,4 +43,56 @@ public class AnonymousStats extends SettingsPreferenceFragment { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.anonymous_stats); } + + public static Set<String> getJobQueue(Context context) { + return getPreferences(context).getStringSet(KEY_JOB_QUEUE, new ArraySet<String>()); + } + + public static void clearJobQueue(Context context) { + getPreferences(context) + .edit() + .remove(KEY_JOB_QUEUE) + .commit(); + } + + public static void addJob(Context context, int jobId) { + Set<String> jobQueue = getJobQueue(context); + jobQueue.add(String.valueOf(jobId)); + + getPreferences(context) + .edit() + .putStringSet(KEY_JOB_QUEUE, jobQueue) + .commit(); + } + + public static void removeJob(Context context, int jobId) { + Set<String> jobQueue = getJobQueue(context); + jobQueue.remove(String.valueOf(jobId)); + getPreferences(context) + .edit() + .putStringSet(KEY_JOB_QUEUE, jobQueue) + .commit(); + } + + /** + * @param context context to use to get prefs + * @return Returns the next unused int in the job queue, up until {@link #QUEUE_MAX_THRESHOLD} + * is reached, then it will return -1 + */ + public static int getNextJobId(Context context) { + Set<String> currentQueue = getJobQueue(context); + + if (currentQueue == null) { + return 1; + } else if (currentQueue.size() >= QUEUE_MAX_THRESHOLD) { + return -1; + } else { + int i = 1; + while (currentQueue.contains(String.valueOf(i))) { + i++; + } + return i; + + } + } } diff --git a/src/com/android/settings/cmstats/ReportingService.java b/src/com/android/settings/cmstats/ReportingService.java index 9087fd7f4..616ac9ba1 100644 --- a/src/com/android/settings/cmstats/ReportingService.java +++ b/src/com/android/settings/cmstats/ReportingService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The CyanogenMod 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,143 +16,105 @@ package com.android.settings.cmstats; -import android.app.Service; +import android.app.IntentService; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.os.IBinder; +import android.os.PersistableBundle; import android.util.Log; -import com.android.settings.R; -import com.android.settings.Settings; - -import com.google.analytics.tracking.android.GoogleAnalytics; -import com.google.analytics.tracking.android.Tracker; -import com.google.analytics.tracking.android.MapBuilder; - -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; - -import java.io.IOException; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -public class ReportingService extends Service { +public class ReportingService extends IntentService { /* package */ static final String TAG = "CMStats"; + private static final boolean DEBUG = false; - private StatsUploadTask mTask; - - @Override - public IBinder onBind(Intent intent) { - return null; + public ReportingService() { + super(ReportingService.class.getSimpleName()); } @Override - public int onStartCommand (Intent intent, int flags, int startId) { - Log.d(TAG, "User has opted in -- reporting."); - - if (mTask == null || mTask.getStatus() == AsyncTask.Status.FINISHED) { - mTask = new StatsUploadTask(); - mTask.execute(); - } - - return Service.START_REDELIVER_INTENT; - } - - private class StatsUploadTask extends AsyncTask<Void, Void, Boolean> { - @Override - protected Boolean doInBackground(Void... params) { - String deviceId = Utilities.getUniqueID(getApplicationContext()); - String deviceName = Utilities.getDevice(); - String deviceVersion = Utilities.getModVersion(); - String deviceCountry = Utilities.getCountryCode(getApplicationContext()); - String deviceCarrier = Utilities.getCarrier(getApplicationContext()); - String deviceCarrierId = Utilities.getCarrierId(getApplicationContext()); - - Log.d(TAG, "SERVICE: Device ID=" + deviceId); - Log.d(TAG, "SERVICE: Device Name=" + deviceName); - Log.d(TAG, "SERVICE: Device Version=" + deviceVersion); - Log.d(TAG, "SERVICE: Country=" + deviceCountry); - Log.d(TAG, "SERVICE: Carrier=" + deviceCarrier); - Log.d(TAG, "SERVICE: Carrier ID=" + deviceCarrierId); - - // report to google analytics - Tracker tracker = GoogleAnalytics.getInstance(ReportingService.this) - .getTracker(getString(R.string.ga_trackingId)); - tracker.send(createMap(deviceName, deviceVersion,deviceCountry)); - - // this really should be set at build time... - // format of version should be: - // version[-date-type]-device - String[] parts = deviceVersion.split("-"); - String deviceVersionNoDevice = null; - if (parts.length == 2) { - deviceVersionNoDevice = parts[0]; - } else if (parts.length == 4) { - deviceVersionNoDevice = parts[0] + "-" + parts[2]; - } - - if (deviceVersionNoDevice != null) { - tracker.send(createMap("checkin", deviceName, deviceVersionNoDevice)); - } - - // report to the cmstats service - HttpClient httpClient = new DefaultHttpClient(); - HttpPost httpPost = new HttpPost("https://stats.cyanogenmod.org/submit"); - boolean success = false; - - try { - List<NameValuePair> kv = new ArrayList<NameValuePair>(5); - kv.add(new BasicNameValuePair("device_hash", deviceId)); - kv.add(new BasicNameValuePair("device_name", deviceName)); - kv.add(new BasicNameValuePair("device_version", deviceVersion)); - kv.add(new BasicNameValuePair("device_country", deviceCountry)); - kv.add(new BasicNameValuePair("device_carrier", deviceCarrier)); - kv.add(new BasicNameValuePair("device_carrier_id", deviceCarrierId)); - - httpPost.setEntity(new UrlEncodedFormEntity(kv)); - httpClient.execute(httpPost); - - success = true; - } catch (IOException e) { - Log.w(TAG, "Could not upload stats checkin", e); - } - - return success; - } - - @Override - protected void onPostExecute(Boolean result) { - final Context context = ReportingService.this; - long interval; - - if (result) { - final SharedPreferences prefs = AnonymousStats.getPreferences(context); - prefs.edit().putLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, - System.currentTimeMillis()).apply(); - // use set interval - interval = 0; + protected void onHandleIntent(Intent intent) { + JobScheduler js = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); + + if (AnonymousStats.getNextJobId(this) == -1) { + // if we've filled up to the threshold, we may have some stale job queue ids, purge them + // then re-add what hasn't executed yet + AnonymousStats.clearJobQueue(this); + + final List<JobInfo> allPendingJobs = js.getAllPendingJobs(); + + // add two extra jobs to the size for what we will schedule below so we *always* + // have room for both. + if (js.getAllPendingJobs().size() + 2 >= AnonymousStats.QUEUE_MAX_THRESHOLD) { + // there are still as many actual pending jobs as our threshold allows. + // since we are past the threshold we will be losing data if we don't schedule + // another job here, so just clear out all the old data and start fresh + js.cancelAll(); } else { - // error, try again in 3 hours - interval = 3L * 60L * 60L * 1000L; + for (JobInfo pendingJob : allPendingJobs) { + AnonymousStats.addJob(this, pendingJob.getId()); + } } - - ReportingServiceManager.setAlarm(context, interval); - stopSelf(); } - } - private Map<String, String> createMap(String category, String action, String label) { - return MapBuilder.createEvent(category, // Event category (required) - action, // Event action (required) - label, // Event label - null) // Event value - .build(); + int cyanogenJobId, cmOrgJobId; + AnonymousStats.addJob(this, cyanogenJobId = AnonymousStats.getNextJobId(this)); + AnonymousStats.addJob(this, cmOrgJobId = AnonymousStats.getNextJobId(this)); + + if (DEBUG) Log.d(TAG, "scheduling jobs id: " + cyanogenJobId + ", " + cmOrgJobId); + + // get snapshot and persist it + String deviceId = Utilities.getUniqueID(getApplicationContext()); + String deviceName = Utilities.getDevice(); + String deviceVersion = Utilities.getModVersion(); + String deviceCountry = Utilities.getCountryCode(getApplicationContext()); + String deviceCarrier = Utilities.getCarrier(getApplicationContext()); + String deviceCarrierId = Utilities.getCarrierId(getApplicationContext()); + + PersistableBundle cyanogenBundle = new PersistableBundle(); + cyanogenBundle.putString(StatsUploadJobService.KEY_DEVICE_NAME, deviceId); + cyanogenBundle.putString(StatsUploadJobService.KEY_UNIQUE_ID, deviceName); + cyanogenBundle.putString(StatsUploadJobService.KEY_VERSION, deviceVersion); + cyanogenBundle.putString(StatsUploadJobService.KEY_COUNTRY, deviceCountry); + cyanogenBundle.putString(StatsUploadJobService.KEY_CARRIER, deviceCarrier); + cyanogenBundle.putString(StatsUploadJobService.KEY_CARRIER_ID, deviceCarrierId); + cyanogenBundle.putLong(StatsUploadJobService.KEY_TIMESTAMP, System.currentTimeMillis()); + + PersistableBundle cmBundle = new PersistableBundle(cyanogenBundle); + + // set job types + cyanogenBundle.putInt(StatsUploadJobService.KEY_JOB_TYPE, + StatsUploadJobService.JOB_TYPE_CYANOGEN); + cmBundle.putInt(StatsUploadJobService.KEY_JOB_TYPE, + StatsUploadJobService.JOB_TYPE_CMORG); + + // schedule cyanogen stats upload + js.schedule(new JobInfo.Builder(cyanogenJobId, new ComponentName(getPackageName(), + StatsUploadJobService.class.getName())) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setMinimumLatency(1000) + .setExtras(cyanogenBundle) + .setPersisted(true) + .build()); + + // schedule cmorg stats upload + js.schedule(new JobInfo.Builder(cmOrgJobId, new ComponentName(getPackageName(), + StatsUploadJobService.class.getName())) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setMinimumLatency(1000) + .setExtras(cmBundle) + .setPersisted(true) + .build()); + + // reschedule + final SharedPreferences prefs = AnonymousStats.getPreferences(this); + prefs.edit().putLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, + System.currentTimeMillis()).apply(); + ReportingServiceManager.setAlarm(this, 0); } + } diff --git a/src/com/android/settings/cmstats/ReportingServiceManager.java b/src/com/android/settings/cmstats/ReportingServiceManager.java index 4fc42424e..e7ca159e8 100644 --- a/src/com/android/settings/cmstats/ReportingServiceManager.java +++ b/src/com/android/settings/cmstats/ReportingServiceManager.java @@ -22,9 +22,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.provider.Settings; import android.util.Log; public class ReportingServiceManager extends BroadcastReceiver { @@ -32,12 +29,16 @@ public class ReportingServiceManager extends BroadcastReceiver { private static final long MILLIS_PER_DAY = 24L * MILLIS_PER_HOUR; private static final long UPDATE_INTERVAL = 1L * MILLIS_PER_DAY; + public static final String ACTION_LAUNCH_SERVICE = + "com.android.settings.action.TRIGGER_REPORT_METRICS"; + public static final String EXTRA_FORCE = "force"; + @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { setAlarm(context, 0); - } else { - launchService(context); + } else if (intent.getAction().equals(ACTION_LAUNCH_SERVICE)){ + launchService(context, intent.getBooleanExtra(EXTRA_FORCE, false)); } } @@ -63,7 +64,7 @@ public class ReportingServiceManager extends BroadcastReceiver { millisFromNow = (lastSynced + UPDATE_INTERVAL) - System.currentTimeMillis(); } - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + Intent intent = new Intent(ACTION_LAUNCH_SERVICE); intent.setClass(context, ReportingServiceManager.class); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); @@ -73,32 +74,26 @@ public class ReportingServiceManager extends BroadcastReceiver { + millisFromNow / MILLIS_PER_HOUR + " hours"); } - public static void launchService(Context context) { - ConnectivityManager cm = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - - NetworkInfo networkInfo = cm.getActiveNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - return; - } - + public static void launchService(Context context, boolean force) { SharedPreferences prefs = AnonymousStats.getPreferences(context); if (!Utilities.isStatsCollectionEnabled(context)) { return; } - long lastSynced = prefs.getLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, 0); - if (lastSynced == 0) { - setAlarm(context, 0); - return; - } - long timeElapsed = System.currentTimeMillis() - lastSynced; - if (timeElapsed < UPDATE_INTERVAL) { - long timeLeft = UPDATE_INTERVAL - timeElapsed; - Log.d(ReportingService.TAG, "Waiting for next sync : " - + timeLeft / MILLIS_PER_HOUR + " hours"); - return; + if (!force) { + long lastSynced = prefs.getLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, 0); + if (lastSynced == 0) { + setAlarm(context, 0); + return; + } + long timeElapsed = System.currentTimeMillis() - lastSynced; + if (timeElapsed < UPDATE_INTERVAL) { + long timeLeft = UPDATE_INTERVAL - timeElapsed; + Log.d(ReportingService.TAG, "Waiting for next sync : " + + timeLeft / MILLIS_PER_HOUR + " hours"); + return; + } } Intent intent = new Intent(); diff --git a/src/com/android/settings/cmstats/StatsUploadJobService.java b/src/com/android/settings/cmstats/StatsUploadJobService.java new file mode 100644 index 000000000..367bb1190 --- /dev/null +++ b/src/com/android/settings/cmstats/StatsUploadJobService.java @@ -0,0 +1,296 @@ +/* + * 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.cmstats; + +import android.app.job.JobParameters; +import android.app.job.JobService; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.PersistableBundle; +import android.support.v4.util.ArrayMap; +import android.util.Log; +import com.android.settings.R; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; + +public class StatsUploadJobService extends JobService { + + private static final String TAG = StatsUploadJobService.class.getSimpleName(); + private static final boolean DEBUG = false; + + public static final String KEY_JOB_TYPE = "job_type"; + public static final int JOB_TYPE_CYANOGEN = 1; + public static final int JOB_TYPE_CMORG = 2; + + public static final String KEY_UNIQUE_ID = "uniqueId"; + public static final String KEY_DEVICE_NAME = "deviceName"; + public static final String KEY_VERSION = "version"; + public static final String KEY_COUNTRY = "country"; + public static final String KEY_CARRIER = "carrier"; + public static final String KEY_CARRIER_ID = "carrierId"; + public static final String KEY_TIMESTAMP = "timeStamp"; + + List<JobParameters> mFinishedJobs = new LinkedList<>(); + ArrayMap<JobParameters, StatsUploadTask> mCurrentJobs = new ArrayMap<>(); + + @Override + public boolean onStartJob(JobParameters jobParameters) { + if (DEBUG) + Log.d(TAG, "onStartJob() called with " + "jobParameters = [" + jobParameters + "]"); + final StatsUploadTask uploadTask = new StatsUploadTask(jobParameters); + mCurrentJobs.put(jobParameters, uploadTask); + uploadTask.execute((Void) null); + return true; + } + + @Override + public boolean onStopJob(JobParameters jobParameters) { + if (DEBUG) + Log.d(TAG, "onStopJob() called with " + "jobParameters = [" + jobParameters + "]"); + + final StatsUploadTask cancelledJob = mCurrentJobs.remove(jobParameters); + + // if we can't remove from finished jobs, that means it's not finished! + final boolean jobSuccessfullyFinished = mFinishedJobs.remove(jobParameters); + + if (!jobSuccessfullyFinished) { + // cancel the ongoing background task + if (cancelledJob != null) { + cancelledJob.cancel(true); + } + } + + return !jobSuccessfullyFinished; + } + + private class StatsUploadTask extends AsyncTask<Void, Void, Boolean> { + + private JobParameters mJobParams; + + public StatsUploadTask(JobParameters jobParams) { + this.mJobParams = jobParams; + } + + @Override + protected Boolean doInBackground(Void... params) { + + PersistableBundle extras = mJobParams.getExtras(); + + String deviceId = extras.getString(KEY_UNIQUE_ID); + String deviceName = extras.getString(KEY_DEVICE_NAME); + String deviceVersion = extras.getString(KEY_VERSION); + String deviceCountry = extras.getString(KEY_COUNTRY); + String deviceCarrier = extras.getString(KEY_CARRIER); + String deviceCarrierId = extras.getString(KEY_CARRIER_ID); + long timeStamp = extras.getLong(KEY_TIMESTAMP); + + boolean success = false; + if (!isCancelled()) { + int jobType = extras.getInt(KEY_JOB_TYPE, -1); + + switch (jobType) { + case JOB_TYPE_CYANOGEN: + try { + success = uploadToCyanogen(deviceId, deviceName, deviceVersion, + deviceCountry, deviceCarrier, deviceCarrierId, timeStamp); + } catch (IOException | JSONException e) { + Log.e(TAG, "Could not upload stats checkin to cyanogen server", e); + success = false; + } + break; + + case JOB_TYPE_CMORG: + try { + success = uploadToCM(deviceId, deviceName, deviceVersion, deviceCountry, + deviceCarrier, deviceCarrierId); + } catch (IOException e) { + Log.e(TAG, "Could not upload stats checkin to commnity server", e); + success = false; + } + break; + } + } + + if (success) { + AnonymousStats.removeJob(StatsUploadJobService.this, mJobParams.getJobId()); + } + + return success; + } + + @Override + protected void onPostExecute(Boolean success) { + if (success) { + mFinishedJobs.add(mJobParams); + } + if (DEBUG) + Log.d(TAG, "job id " + mJobParams.getJobId() + ", has finished with success=" + + success); + jobFinished(mJobParams, !success); + } + } + + + private boolean uploadToCM(String deviceId, String deviceName, String deviceVersion, + String deviceCountry, String deviceCarrier, String deviceCarrierId) + throws IOException { + + final Uri uri = Uri.parse(getString(R.string.stats_cm_url)).buildUpon() + .appendQueryParameter("device_hash", deviceId) + .appendQueryParameter("device_name", deviceName) + .appendQueryParameter("device_version", deviceVersion) + .appendQueryParameter("device_country", deviceCountry) + .appendQueryParameter("device_carrier", deviceCarrier) + .appendQueryParameter("device_carrier_id", deviceCarrierId).build(); + URL url = new URL(uri.toString()); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + try { + urlConnection.setInstanceFollowRedirects(true); + urlConnection.setDoOutput(true); + urlConnection.connect(); + + final int responseCode = urlConnection.getResponseCode(); + if (DEBUG) Log.d(TAG, "cm server response code=" + responseCode); + final boolean success = responseCode == HttpURLConnection.HTTP_OK; + if (!success) { + Log.w(TAG, "failed sending, server returned: " + getResponse(urlConnection, + !success)); + } + return success; + } finally { + urlConnection.disconnect(); + } + + } + + private boolean uploadToCyanogen(String deviceId, String deviceName, String deviceVersion, + String deviceCountry, String carrier, String carrierId, + long timeStamp) + throws IOException, JSONException { + String authToken = getAuthToken(); + + if (authToken.isEmpty()) { + Log.w(TAG, "no auth token!"); + } + + JSONObject json = new JSONObject(); + json.put("uniqueId", deviceId); + json.put("deviceName", deviceName); + json.put("version", deviceVersion); + json.put("country", deviceCountry); + json.put("carrier", carrier); + json.put("carrierId", carrierId); + json.put("timestamp", timeStamp); + + URL url = new URL(getString(R.string.stats_cyanogen_url)); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + try { + urlConnection.setInstanceFollowRedirects(true); + urlConnection.setDoInput(true); + urlConnection.setDoOutput(true); + + urlConnection.setRequestProperty("Accept-Encoding", "identity"); + urlConnection.setRequestProperty("Authorization", authToken); + urlConnection.setRequestProperty("Content-Type", "application/json"); + + OutputStream os = urlConnection.getOutputStream(); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); + writer.write(json.toString()); + writer.flush(); + writer.close(); + os.close(); + + urlConnection.connect(); + + final int responseCode = urlConnection.getResponseCode(); + final boolean success = responseCode == HttpURLConnection.HTTP_OK; + if (!success) { + Log.w(TAG, "failed sending, server returned: " + getResponse(urlConnection, + !success)); + } + return success; + } finally { + urlConnection.disconnect(); + } + } + + private String getAuthToken() { + HttpURLConnection urlConnection = null; + try { + URL url = new URL(getString(R.string.stats_cyanogen_token_url)); + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setInstanceFollowRedirects(true); + urlConnection.setDoInput(true); + + urlConnection.setRequestProperty("Accept-Encoding", "identity"); + urlConnection.setRequestProperty("Content-Type", "text/plain"); + + urlConnection.connect(); + + final int responseCode = urlConnection.getResponseCode(); + final boolean success = responseCode == HttpURLConnection.HTTP_OK; + if (DEBUG) Log.d(TAG, "server auth response code=" + responseCode); + final String response = getResponse(urlConnection, !success); + if (DEBUG) + Log.d(TAG, "server auth response=" + response); + + if (success) { + return response; + } + } catch (IOException e) { + Log.e(TAG, "error getting auth token", e); + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + return ""; + } + + private String getResponse(HttpURLConnection httpUrlConnection, boolean errorStream) + throws IOException { + InputStream responseStream = new BufferedInputStream(errorStream + ? httpUrlConnection.getErrorStream() + : httpUrlConnection.getInputStream()); + + BufferedReader responseStreamReader = new BufferedReader( + new InputStreamReader(responseStream)); + String line = ""; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = responseStreamReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + responseStreamReader.close(); + responseStream.close(); + + return stringBuilder.toString(); + } + +} |