1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.research; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.pm.PackageManager; 24 import android.net.ConnectivityManager; 25 import android.net.NetworkInfo; 26 import android.os.BatteryManager; 27 import android.text.TextUtils; 28 import android.util.Log; 29 30 import com.android.inputmethod.latin.R; 31 import com.android.inputmethod.latin.define.ProductionFlag; 32 33 import java.io.BufferedReader; 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.InputStreamReader; 39 import java.io.OutputStream; 40 import java.net.HttpURLConnection; 41 import java.net.MalformedURLException; 42 import java.net.URL; 43 44 /** 45 * Manages the uploading of ResearchLog files. 46 */ 47 public final class Uploader { 48 private static final String TAG = Uploader.class.getSimpleName(); 49 private static final boolean DEBUG = false 50 && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; 51 // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing 52 private static final boolean IS_INHIBITING_UPLOAD = false 53 && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; 54 private static final int BUF_SIZE = 1024 * 8; 55 56 private final Context mContext; 57 private final ResearchLogDirectory mResearchLogDirectory; 58 private final URL mUrl; 59 60 public Uploader(final Context context) { 61 mContext = context; 62 mResearchLogDirectory = new ResearchLogDirectory(context); 63 64 final String urlString = context.getString(R.string.research_logger_upload_url); 65 if (TextUtils.isEmpty(urlString)) { 66 mUrl = null; 67 return; 68 } 69 URL url = null; 70 try { 71 url = new URL(urlString); 72 } catch (final MalformedURLException e) { 73 Log.e(TAG, "Bad URL for uploading", e); 74 } 75 mUrl = url; 76 } 77 78 public boolean isPossibleToUpload() { 79 return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_UPLOAD; 80 } 81 82 private boolean hasUploadingPermission() { 83 final PackageManager packageManager = mContext.getPackageManager(); 84 return packageManager.checkPermission(Manifest.permission.INTERNET, 85 mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED; 86 } 87 88 public boolean isConvenientToUpload() { 89 return isExternallyPowered() && hasWifiConnection(); 90 } 91 92 private boolean isExternallyPowered() { 93 final Intent intent = mContext.registerReceiver(null, new IntentFilter( 94 Intent.ACTION_BATTERY_CHANGED)); 95 final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 96 return pluggedState == BatteryManager.BATTERY_PLUGGED_AC 97 || pluggedState == BatteryManager.BATTERY_PLUGGED_USB; 98 } 99 100 private boolean hasWifiConnection() { 101 final ConnectivityManager manager = 102 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 103 final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 104 return wifiInfo.isConnected(); 105 } 106 107 public void doUpload() { 108 final File[] files = mResearchLogDirectory.getUploadableLogFiles(); 109 if (files == null) return; 110 for (final File file : files) { 111 uploadFile(file); 112 } 113 } 114 115 private void uploadFile(final File file) { 116 if (DEBUG) { 117 Log.d(TAG, "attempting upload of " + file.getAbsolutePath()); 118 } 119 final int contentLength = (int) file.length(); 120 HttpURLConnection connection = null; 121 InputStream fileInputStream = null; 122 try { 123 fileInputStream = new FileInputStream(file); 124 connection = (HttpURLConnection) mUrl.openConnection(); 125 connection.setRequestMethod("PUT"); 126 connection.setDoOutput(true); 127 connection.setFixedLengthStreamingMode(contentLength); 128 final OutputStream outputStream = connection.getOutputStream(); 129 uploadContents(fileInputStream, outputStream); 130 if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { 131 Log.d(TAG, "upload failed: " + connection.getResponseCode()); 132 final InputStream netInputStream = connection.getInputStream(); 133 final BufferedReader reader = new BufferedReader(new InputStreamReader( 134 netInputStream)); 135 String line; 136 while ((line = reader.readLine()) != null) { 137 Log.d(TAG, "| " + reader.readLine()); 138 } 139 reader.close(); 140 return; 141 } 142 file.delete(); 143 if (DEBUG) { 144 Log.d(TAG, "upload successful"); 145 } 146 } catch (final IOException e) { 147 Log.e(TAG, "Exception uploading file", e); 148 } finally { 149 if (fileInputStream != null) { 150 try { 151 fileInputStream.close(); 152 } catch (final IOException e) { 153 Log.e(TAG, "Exception closing uploaded file", e); 154 } 155 } 156 if (connection != null) { 157 connection.disconnect(); 158 } 159 } 160 } 161 162 private static void uploadContents(final InputStream is, final OutputStream os) 163 throws IOException { 164 // TODO: Switch to NIO. 165 final byte[] buf = new byte[BUF_SIZE]; 166 int numBytesRead; 167 while ((numBytesRead = is.read(buf)) != -1) { 168 os.write(buf, 0, numBytesRead); 169 } 170 } 171 } 172