Skip to content
Snippets Groups Projects
Commit 96da6335 authored by Kurt Partridge's avatar Kurt Partridge Committed by Android (Google) Code Review
Browse files

Revert "ResearchLogging upload via service"

This reverts commit baf1f0bd

Change-Id: I7d959b9b626c8fb69a57788e243752952258fa80
parent baf1f0bd
No related branches found
No related tags found
No related merge requests found
...@@ -289,10 +289,6 @@ ...@@ -289,10 +289,6 @@
<!-- TODO: remove translatable=false attribute once text is stable --> <!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_send_usage_info" translatable="false">Send usage info</string> <string name="research_send_usage_info" translatable="false">Send usage info</string>
<!-- Name for the research uploading service to be displayed to users. [CHAR LIMIT=50] -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_log_uploader_name" translatable="false">Research Uploader Service</string>
<!-- Preference for input language selection --> <!-- Preference for input language selection -->
<string name="select_language">Input languages</string> <string name="select_language">Input languages</string>
......
/*
* Copyright (C) 2012 The Android Open Source 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.inputmethod.research;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* Arrange for the uploading service to be run on regular intervals.
*/
public final class BootBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
ResearchLogger.scheduleUploadingService(context);
}
}
}
/*
* Copyright (C) 2012 The Android Open Source 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.inputmethod.research;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.BatteryManager;
import android.util.Log;
import com.android.inputmethod.latin.R;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public final class ResearchLogUploader {
private static final String TAG = ResearchLogUploader.class.getSimpleName();
private static final int UPLOAD_INTERVAL_IN_MS = 1000 * 60 * 15; // every 15 min
private static final int BUF_SIZE = 1024 * 8;
protected static final int TIMEOUT_IN_MS = 1000 * 4;
private final boolean mCanUpload;
private final Context mContext;
private final File mFilesDir;
private final URL mUrl;
private final ScheduledExecutorService mExecutor;
public ResearchLogUploader(final Context context, final File filesDir) {
mContext = context;
mFilesDir = filesDir;
final PackageManager packageManager = context.getPackageManager();
final boolean hasPermission = packageManager.checkPermission(Manifest.permission.INTERNET,
context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
mCanUpload = false;
mUrl = null;
mExecutor = null;
return;
}
URL tempUrl = null;
boolean canUpload = false;
ScheduledExecutorService executor = null;
try {
final String urlString = context.getString(R.string.research_logger_upload_url);
if (urlString == null || urlString.equals("")) {
return;
}
tempUrl = new URL(urlString);
canUpload = true;
executor = Executors.newSingleThreadScheduledExecutor();
} catch (MalformedURLException e) {
tempUrl = null;
e.printStackTrace();
return;
} finally {
mCanUpload = canUpload;
mUrl = tempUrl;
mExecutor = executor;
}
}
public void start() {
if (mCanUpload) {
mExecutor.scheduleWithFixedDelay(new UploadRunnable(null /* logToWaitFor */,
null /* callback */, false /* forceUpload */),
UPLOAD_INTERVAL_IN_MS, UPLOAD_INTERVAL_IN_MS, TimeUnit.MILLISECONDS);
}
}
public void uploadAfterCompletion(final ResearchLog researchLog, final Callback callback) {
if (mCanUpload) {
mExecutor.submit(new UploadRunnable(researchLog, callback, true /* forceUpload */));
}
}
public void uploadNow(final Callback callback) {
// Perform an immediate upload. Note that this should happen even if there is
// another upload happening right now, as it may have missed the latest changes.
// TODO: Reschedule regular upload tests starting from now.
if (mCanUpload) {
mExecutor.submit(new UploadRunnable(null /* logToWaitFor */, callback,
true /* forceUpload */));
}
}
public interface Callback {
public void onUploadCompleted(final boolean success);
}
private boolean isExternallyPowered() {
final Intent intent = mContext.registerReceiver(null, new IntentFilter(
Intent.ACTION_BATTERY_CHANGED));
final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
return pluggedState == BatteryManager.BATTERY_PLUGGED_AC
|| pluggedState == BatteryManager.BATTERY_PLUGGED_USB;
}
private boolean hasWifiConnection() {
final ConnectivityManager manager =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return wifiInfo.isConnected();
}
class UploadRunnable implements Runnable {
private final ResearchLog mLogToWaitFor;
private final Callback mCallback;
private final boolean mForceUpload;
public UploadRunnable(final ResearchLog logToWaitFor, final Callback callback,
final boolean forceUpload) {
mLogToWaitFor = logToWaitFor;
mCallback = callback;
mForceUpload = forceUpload;
}
@Override
public void run() {
if (mLogToWaitFor != null) {
waitFor(mLogToWaitFor);
}
doUpload();
}
private void waitFor(final ResearchLog researchLog) {
try {
researchLog.awaitTermination(TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void doUpload() {
if (!mForceUpload && (!isExternallyPowered() || !hasWifiConnection())) {
return;
}
if (mFilesDir == null) {
return;
}
final File[] files = mFilesDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().startsWith(ResearchLogger.FILENAME_PREFIX)
&& !pathname.canWrite();
}
});
boolean success = true;
if (files.length == 0) {
success = false;
}
for (final File file : files) {
if (!uploadFile(file)) {
success = false;
}
}
if (mCallback != null) {
mCallback.onUploadCompleted(success);
}
}
private boolean uploadFile(File file) {
Log.d(TAG, "attempting upload of " + file.getAbsolutePath());
boolean success = false;
final int contentLength = (int) file.length();
HttpURLConnection connection = null;
InputStream fileIs = null;
try {
fileIs = new FileInputStream(file);
connection = (HttpURLConnection) mUrl.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setFixedLengthStreamingMode(contentLength);
final OutputStream os = connection.getOutputStream();
final byte[] buf = new byte[BUF_SIZE];
int numBytesRead;
while ((numBytesRead = fileIs.read(buf)) != -1) {
os.write(buf, 0, numBytesRead);
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "upload failed: " + connection.getResponseCode());
InputStream netIs = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(netIs));
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, "| " + reader.readLine());
}
reader.close();
return success;
}
file.delete();
success = true;
Log.d(TAG, "upload successful");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileIs != null) {
try {
fileIs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
return success;
}
}
}
...@@ -18,14 +18,11 @@ package com.android.inputmethod.research; ...@@ -18,14 +18,11 @@ package com.android.inputmethod.research;
import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
import android.app.AlarmManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
...@@ -136,9 +133,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ...@@ -136,9 +133,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private KeyboardSwitcher mKeyboardSwitcher; private KeyboardSwitcher mKeyboardSwitcher;
private InputMethodService mInputMethodService; private InputMethodService mInputMethodService;
private final Statistics mStatistics; private final Statistics mStatistics;
private ResearchLogUploader mResearchLogUploader;
private Intent mUploadIntent;
private PendingIntent mUploadPendingIntent;
private LogUnit mCurrentLogUnit = new LogUnit(); private LogUnit mCurrentLogUnit = new LogUnit();
...@@ -181,34 +176,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ...@@ -181,34 +176,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
e.apply(); e.apply();
} }
} }
mResearchLogUploader = new ResearchLogUploader(ims, mFilesDir);
mResearchLogUploader.start();
mKeyboardSwitcher = keyboardSwitcher; mKeyboardSwitcher = keyboardSwitcher;
mInputMethodService = ims; mInputMethodService = ims;
mPrefs = prefs; mPrefs = prefs;
mUploadIntent = new Intent(mInputMethodService, UploaderService.class);
mUploadPendingIntent = PendingIntent.getService(mInputMethodService, 0, mUploadIntent, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
scheduleUploadingService(mInputMethodService);
}
}
/**
* Arrange for the UploaderService to be run on a regular basis.
*
* Any existing scheduled invocation of UploaderService is removed and rescheduled. This may
* cause problems if this method is called often and frequent updates are required, but since
* the user will likely be sleeping at some point, if the interval is less that the expected
* sleep duration and this method is not called during that time, the service should be invoked
* at some point.
*/
public static void scheduleUploadingService(Context context) {
final Intent intent = new Intent(context, UploaderService.class);
final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
final AlarmManager manager =
(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
UploaderService.RUN_INTERVAL, UploaderService.RUN_INTERVAL, pendingIntent);
} }
private void cleanupLoggingDir(final File dir, final long time) { private void cleanupLoggingDir(final File dir, final long time) {
...@@ -285,7 +257,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ...@@ -285,7 +257,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Editor e = mPrefs.edit(); final Editor e = mPrefs.edit();
e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true); e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true);
e.apply(); e.apply();
restart();
} }
private void setLoggingAllowed(boolean enableLogging) { private void setLoggingAllowed(boolean enableLogging) {
...@@ -508,11 +479,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ...@@ -508,11 +479,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (mFeedbackLogBuffer == null) { if (mFeedbackLogBuffer == null) {
return; return;
} }
if (includeHistory) { if (!includeHistory) {
commitCurrentLogUnit();
} else {
mFeedbackLogBuffer.clear(); mFeedbackLogBuffer.clear();
} }
commitCurrentLogUnit();
final LogUnit feedbackLogUnit = new LogUnit(); final LogUnit feedbackLogUnit = new LogUnit();
final Object[] values = { final Object[] values = {
feedbackContents feedbackContents
...@@ -522,14 +492,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ...@@ -522,14 +492,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mFeedbackLogBuffer.shiftIn(feedbackLogUnit); mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */); publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */);
mFeedbackLog.close(); mFeedbackLog.close();
uploadNow(); mResearchLogUploader.uploadAfterCompletion(mFeedbackLog, null);
mFeedbackLog = new ResearchLog(createLogFile(mFilesDir)); mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
} }
public void uploadNow() {
mInputMethodService.startService(mUploadIntent);
}
public void onLeavingSendFeedbackDialog() { public void onLeavingSendFeedbackDialog() {
mInFeedbackDialog = false; mInFeedbackDialog = false;
} }
......
/*
* Copyright (C) 2012 The Android Open Source 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.inputmethod.research;
import android.Manifest;
import android.app.AlarmManager;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.BatteryManager;
import android.os.Bundle;
import android.util.Log;
import com.android.inputmethod.latin.R;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public final class UploaderService extends IntentService {
private static final String TAG = UploaderService.class.getSimpleName();
public static final long RUN_INTERVAL = AlarmManager.INTERVAL_HOUR;
private static final String EXTRA_UPLOAD_UNCONDITIONALLY = UploaderService.class.getName()
+ ".extra.UPLOAD_UNCONDITIONALLY";
private static final int BUF_SIZE = 1024 * 8;
protected static final int TIMEOUT_IN_MS = 1000 * 4;
private boolean mCanUpload;
private File mFilesDir;
private URL mUrl;
public UploaderService() {
super("Research Uploader Service");
}
@Override
public void onCreate() {
super.onCreate();
mCanUpload = false;
mFilesDir = null;
mUrl = null;
final PackageManager packageManager = getPackageManager();
final boolean hasPermission = packageManager.checkPermission(Manifest.permission.INTERNET,
getPackageName()) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
return;
}
try {
final String urlString = getString(R.string.research_logger_upload_url);
if (urlString == null || urlString.equals("")) {
return;
}
mFilesDir = getFilesDir();
mUrl = new URL(urlString);
mCanUpload = true;
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
protected void onHandleIntent(Intent intent) {
if (!mCanUpload) {
return;
}
boolean isUploadingUnconditionally = false;
Bundle bundle = intent.getExtras();
if (bundle != null && bundle.containsKey(EXTRA_UPLOAD_UNCONDITIONALLY)) {
isUploadingUnconditionally = bundle.getBoolean(EXTRA_UPLOAD_UNCONDITIONALLY);
}
doUpload(isUploadingUnconditionally);
}
private boolean isExternallyPowered() {
final Intent intent = registerReceiver(null, new IntentFilter(
Intent.ACTION_BATTERY_CHANGED));
final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
return pluggedState == BatteryManager.BATTERY_PLUGGED_AC
|| pluggedState == BatteryManager.BATTERY_PLUGGED_USB;
}
private boolean hasWifiConnection() {
final ConnectivityManager manager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return wifiInfo.isConnected();
}
private void doUpload(final boolean isUploadingUnconditionally) {
if (!isUploadingUnconditionally && (!isExternallyPowered() || !hasWifiConnection())) {
return;
}
if (mFilesDir == null) {
return;
}
final File[] files = mFilesDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().startsWith(ResearchLogger.FILENAME_PREFIX)
&& !pathname.canWrite();
}
});
boolean success = true;
if (files.length == 0) {
success = false;
}
for (final File file : files) {
if (!uploadFile(file)) {
success = false;
}
}
}
private boolean uploadFile(File file) {
Log.d(TAG, "attempting upload of " + file.getAbsolutePath());
boolean success = false;
final int contentLength = (int) file.length();
HttpURLConnection connection = null;
InputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
connection = (HttpURLConnection) mUrl.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setFixedLengthStreamingMode(contentLength);
final OutputStream os = connection.getOutputStream();
final byte[] buf = new byte[BUF_SIZE];
int numBytesRead;
while ((numBytesRead = fileInputStream.read(buf)) != -1) {
os.write(buf, 0, numBytesRead);
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "upload failed: " + connection.getResponseCode());
InputStream netInputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(netInputStream));
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, "| " + reader.readLine());
}
reader.close();
return success;
}
file.delete();
success = true;
Log.d(TAG, "upload successful");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
return success;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment