Uploader.java revision 4436446e9b173aab17c6927bb78b0f236381f7d1
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
17package com.android.inputmethod.research;
18
19import android.Manifest;
20import android.app.AlarmManager;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.net.ConnectivityManager;
26import android.net.NetworkInfo;
27import android.os.BatteryManager;
28import android.text.TextUtils;
29import android.util.Log;
30
31import com.android.inputmethod.latin.R;
32import com.android.inputmethod.latin.define.ProductionFlag;
33
34import java.io.BufferedReader;
35import java.io.File;
36import java.io.FileFilter;
37import java.io.FileInputStream;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.InputStreamReader;
41import java.io.OutputStream;
42import java.net.HttpURLConnection;
43import java.net.MalformedURLException;
44import java.net.URL;
45
46/**
47 * Manages the uploading of ResearchLog files.
48 */
49public final class Uploader {
50    private static final String TAG = Uploader.class.getSimpleName();
51    private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
52    // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing
53    private static final boolean IS_INHIBITING_AUTO_UPLOAD = false
54            && ProductionFlag.IS_EXPERIMENTAL_DEBUG;  // Force false for non-debug builds
55    private static final int BUF_SIZE = 1024 * 8;
56
57    private final Context mContext;
58    private final File mFilesDir;
59    private final URL mUrl;
60
61    public Uploader(final Context context) {
62        mContext = context;
63        mFilesDir = context.getFilesDir();
64
65        final String urlString = context.getString(R.string.research_logger_upload_url);
66        if (TextUtils.isEmpty(urlString)) {
67            mUrl = null;
68            return;
69        }
70        URL url = null;
71        try {
72            url = new URL(urlString);
73        } catch (final MalformedURLException e) {
74            Log.e(TAG, "Bad URL for uploading", e);
75        }
76        mUrl = url;
77    }
78
79    public boolean isPossibleToUpload() {
80        return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_AUTO_UPLOAD;
81    }
82
83    private boolean hasUploadingPermission() {
84        final PackageManager packageManager = mContext.getPackageManager();
85        return packageManager.checkPermission(Manifest.permission.INTERNET,
86                mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED;
87    }
88
89    public boolean isConvenientToUpload() {
90        return isExternallyPowered() && hasWifiConnection();
91    }
92
93    private boolean isExternallyPowered() {
94        final Intent intent = mContext.registerReceiver(null, new IntentFilter(
95                Intent.ACTION_BATTERY_CHANGED));
96        final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
97        return pluggedState == BatteryManager.BATTERY_PLUGGED_AC
98                || pluggedState == BatteryManager.BATTERY_PLUGGED_USB;
99    }
100
101    private boolean hasWifiConnection() {
102        final ConnectivityManager manager =
103                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
104        final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
105        return wifiInfo.isConnected();
106    }
107
108    public void doUpload() {
109        if (mFilesDir == null) {
110            return;
111        }
112        final File[] files = mFilesDir.listFiles(new FileFilter() {
113            @Override
114            public boolean accept(final File pathname) {
115                return pathname.getName().startsWith(ResearchLogger.LOG_FILENAME_PREFIX)
116                        && !pathname.canWrite();
117            }
118        });
119        // TODO: Remove local variable
120        boolean success = true;
121        if (files.length == 0) {
122            success = false;
123        }
124        for (final File file : files) {
125            if (!uploadFile(file)) {
126                success = false;
127            }
128        }
129    }
130
131    private boolean uploadFile(final File file) {
132        if (DEBUG) {
133            Log.d(TAG, "attempting upload of " + file.getAbsolutePath());
134        }
135        boolean success = false;
136        final int contentLength = (int) file.length();
137        HttpURLConnection connection = null;
138        InputStream fileInputStream = null;
139        try {
140            fileInputStream = new FileInputStream(file);
141            connection = (HttpURLConnection) mUrl.openConnection();
142            connection.setRequestMethod("PUT");
143            connection.setDoOutput(true);
144            connection.setFixedLengthStreamingMode(contentLength);
145            final OutputStream outputStream = connection.getOutputStream();
146            final byte[] buf = new byte[BUF_SIZE];
147            int numBytesRead;
148            while ((numBytesRead = fileInputStream.read(buf)) != -1) {
149                outputStream.write(buf, 0, numBytesRead);
150                if (DEBUG) {
151                    Log.d(TAG, new String(buf));
152                }
153            }
154            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
155                Log.d(TAG, "upload failed: " + connection.getResponseCode());
156                final InputStream netInputStream = connection.getInputStream();
157                final BufferedReader reader = new BufferedReader(new InputStreamReader(
158                        netInputStream));
159                String line;
160                while ((line = reader.readLine()) != null) {
161                    Log.d(TAG, "| " + reader.readLine());
162                }
163                reader.close();
164                return success;
165            }
166            file.delete();
167            success = true;
168            if (DEBUG) {
169                Log.d(TAG, "upload successful");
170            }
171        } catch (final IOException e) {
172            Log.e(TAG, "Exception uploading file", e);
173        } finally {
174            if (fileInputStream != null) {
175                try {
176                    fileInputStream.close();
177                } catch (final IOException e) {
178                    Log.e(TAG, "Exception closing uploaded file", e);
179                }
180            }
181            if (connection != null) {
182                connection.disconnect();
183            }
184        }
185        return success;
186    }
187}
188