1b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge/* 2b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * Copyright (C) 2012 The Android Open Source Project 3b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * 4b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * use this file except in compliance with the License. You may obtain a copy of 6b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * the License at 7b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * 8b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * http://www.apache.org/licenses/LICENSE-2.0 9b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * 10b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * Unless required by applicable law or agreed to in writing, software 11b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * License for the specific language governing permissions and limitations under 14b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge * the License. 15b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge */ 16b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 17b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgepackage com.android.inputmethod.research; 18b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 19b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.Manifest; 20b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.app.AlarmManager; 21b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.app.IntentService; 22b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.content.Context; 23b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.content.Intent; 24b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.content.IntentFilter; 25b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.content.pm.PackageManager; 26b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.net.ConnectivityManager; 27b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.net.NetworkInfo; 28b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.os.BatteryManager; 29b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.os.Bundle; 30b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.util.Log; 31b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 32b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport com.android.inputmethod.latin.R; 33b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 34b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.BufferedReader; 35b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.File; 36b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.FileFilter; 37b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.FileInputStream; 38b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.IOException; 39b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.InputStream; 40b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.InputStreamReader; 41b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.io.OutputStream; 42b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.net.HttpURLConnection; 43b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.net.MalformedURLException; 44b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport java.net.URL; 45b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 46b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgepublic final class UploaderService extends IntentService { 47b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private static final String TAG = UploaderService.class.getSimpleName(); 48b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge public static final long RUN_INTERVAL = AlarmManager.INTERVAL_HOUR; 49b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private static final String EXTRA_UPLOAD_UNCONDITIONALLY = UploaderService.class.getName() 50b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge + ".extra.UPLOAD_UNCONDITIONALLY"; 51b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private static final int BUF_SIZE = 1024 * 8; 52b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge protected static final int TIMEOUT_IN_MS = 1000 * 4; 53b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 54b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private boolean mCanUpload; 55b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private File mFilesDir; 56b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private URL mUrl; 57b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 58b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge public UploaderService() { 59b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge super("Research Uploader Service"); 60b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 61b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 62b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge @Override 63b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge public void onCreate() { 64b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge super.onCreate(); 65b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 66b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mCanUpload = false; 67b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mFilesDir = null; 68b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mUrl = null; 69b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 70b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final PackageManager packageManager = getPackageManager(); 71b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final boolean hasPermission = packageManager.checkPermission(Manifest.permission.INTERNET, 72b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge getPackageName()) == PackageManager.PERMISSION_GRANTED; 73b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (!hasPermission) { 74b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return; 75b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 76b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 77b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge try { 78b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final String urlString = getString(R.string.research_logger_upload_url); 79b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (urlString == null || urlString.equals("")) { 80b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return; 81b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 82b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mFilesDir = getFilesDir(); 83b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mUrl = new URL(urlString); 84b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge mCanUpload = true; 85b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } catch (MalformedURLException e) { 86b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge e.printStackTrace(); 87b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 88b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 89b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 90b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge @Override 91b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge protected void onHandleIntent(Intent intent) { 92b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (!mCanUpload) { 93b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return; 94b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 95b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge boolean isUploadingUnconditionally = false; 96b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Bundle bundle = intent.getExtras(); 97b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (bundle != null && bundle.containsKey(EXTRA_UPLOAD_UNCONDITIONALLY)) { 98b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge isUploadingUnconditionally = bundle.getBoolean(EXTRA_UPLOAD_UNCONDITIONALLY); 99b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 100b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge doUpload(isUploadingUnconditionally); 101b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 102b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 103b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private boolean isExternallyPowered() { 104b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final Intent intent = registerReceiver(null, new IntentFilter( 105b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Intent.ACTION_BATTERY_CHANGED)); 106b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 107b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return pluggedState == BatteryManager.BATTERY_PLUGGED_AC 108b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge || pluggedState == BatteryManager.BATTERY_PLUGGED_USB; 109b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 110b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 111b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private boolean hasWifiConnection() { 112b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final ConnectivityManager manager = 113b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 114b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 115b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return wifiInfo.isConnected(); 116b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 117b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 118b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private void doUpload(final boolean isUploadingUnconditionally) { 119b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (!isUploadingUnconditionally && (!isExternallyPowered() || !hasWifiConnection())) { 120b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return; 121b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 122b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (mFilesDir == null) { 123b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return; 124b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 125b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final File[] files = mFilesDir.listFiles(new FileFilter() { 126b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge @Override 127b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge public boolean accept(File pathname) { 128b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return pathname.getName().startsWith(ResearchLogger.FILENAME_PREFIX) 129b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge && !pathname.canWrite(); 130b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 131b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge }); 132b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge boolean success = true; 133b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (files.length == 0) { 134b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge success = false; 135b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 136b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge for (final File file : files) { 137b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (!uploadFile(file)) { 138b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge success = false; 139b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 140b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 141b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 142b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge 143b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge private boolean uploadFile(File file) { 144b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Log.d(TAG, "attempting upload of " + file.getAbsolutePath()); 145b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge boolean success = false; 146b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final int contentLength = (int) file.length(); 147b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge HttpURLConnection connection = null; 148b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge InputStream fileInputStream = null; 149b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge try { 150b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge fileInputStream = new FileInputStream(file); 151b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge connection = (HttpURLConnection) mUrl.openConnection(); 152b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge connection.setRequestMethod("PUT"); 153b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge connection.setDoOutput(true); 154b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge connection.setFixedLengthStreamingMode(contentLength); 155b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final OutputStream os = connection.getOutputStream(); 156b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge final byte[] buf = new byte[BUF_SIZE]; 157b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge int numBytesRead; 158b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge while ((numBytesRead = fileInputStream.read(buf)) != -1) { 159b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge os.write(buf, 0, numBytesRead); 160b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 161b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { 162b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Log.d(TAG, "upload failed: " + connection.getResponseCode()); 163b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge InputStream netInputStream = connection.getInputStream(); 164b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge BufferedReader reader = new BufferedReader(new InputStreamReader(netInputStream)); 165b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge String line; 166b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge while ((line = reader.readLine()) != null) { 167b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Log.d(TAG, "| " + reader.readLine()); 168b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 169b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge reader.close(); 170b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return success; 171b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 172b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge file.delete(); 173b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge success = true; 174b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge Log.d(TAG, "upload successful"); 175b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } catch (Exception e) { 176b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge e.printStackTrace(); 177b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } finally { 178b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (fileInputStream != null) { 179b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge try { 180b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge fileInputStream.close(); 181b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } catch (IOException e) { 182b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge e.printStackTrace(); 183b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 184b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 185b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge if (connection != null) { 186b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge connection.disconnect(); 187b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 188b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 189b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge return success; 190b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge } 191b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge} 192