// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.view;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

public final class ResourceUpdater {
    private static final String TAG = "ResourceUpdater";

    private class DownloadTask extends AsyncTask<String, String, Void> {
        @Override
        protected Void doInBackground(String... args) {
            try {
                URL unresolvedURL = new URL(args[0]);
                File localFile = new File(args[1]);

                long startMillis = new Date().getTime();
                Log.i(TAG, "Checking for updates at " + unresolvedURL);

                HttpURLConnection connection =
                        (HttpURLConnection)unresolvedURL.openConnection();

                long lastModified = localFile.lastModified();
                if (lastModified != 0) {
                    Log.i(TAG, "Active update timestamp " + lastModified);
                    connection.setIfModifiedSince(lastModified);
                }

                try (InputStream input = connection.getInputStream()) {
                    URL resolvedURL = connection.getURL();
                    Log.i(TAG, "Resolved update URL " + resolvedURL);

                    if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
                        if (resolvedURL.equals(unresolvedURL)) {
                            Log.i(TAG, "Rolled back all updates");
                            localFile.delete();
                            return null;
                        } else {
                            Log.i(TAG, "Latest update not found");
                            return null;
                        }
                    }

                    if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
                        Log.i(TAG, "Already have latest update");
                        return null;
                    }

                    Log.i(TAG, "Downloading update " + unresolvedURL);
                    try (OutputStream output = new FileOutputStream(localFile)) {
                        int count;
                        byte data[] = new byte[1024];
                        while ((count = input.read(data)) != -1) {
                            output.write(data, 0, count);
                        }

                        long totalMillis = new Date().getTime() - startMillis;
                        Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s");

                        output.flush();
                        return null;
                    }
                }

            } catch (IOException e) {
                Log.w(TAG, "Could not download update " + e.getMessage());
                return null;
            }
        }
    }

    private final Context context;
    private DownloadTask downloadTask;

    public ResourceUpdater(Context context) {
        this.context = context;
    }

    public String getAPKVersion() {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            return packageInfo == null ? null : Integer.toString(packageInfo.versionCode);

        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }

    public String getUpdateInstallationPath() {
        return context.getFilesDir().toString() + "/update.zip";
    }

    public String buildUpdateDownloadURL() {
        Bundle metaData;
        try {
            metaData = context.getPackageManager().getApplicationInfo(
                    context.getPackageName(), PackageManager.GET_META_DATA).metaData;

        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }

        if (metaData == null || metaData.getString("UpdateServerURL") == null) {
            return null;
        }

        URI uri;
        try {
            uri = new URI(metaData.getString("UpdateServerURL") + "/" + getAPKVersion());

        } catch (URISyntaxException e) {
            Log.w(TAG, "Invalid AndroidManifest.xml UpdateServerURL: " + e.getMessage());
            return null;
        }

        return uri.normalize().toString();
    }

    public void startUpdateDownloadOnce() {
        assert downloadTask == null;
        downloadTask = new DownloadTask();
        downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                buildUpdateDownloadURL(), getUpdateInstallationPath());
    }

    public void waitForDownloadCompletion() {
        assert downloadTask != null;
        try {
            downloadTask.get();
        } catch (CancellationException e) {
            Log.w(TAG, "Download cancelled: " + e.getMessage());
            return;
        } catch (ExecutionException e) {
            Log.w(TAG, "Download exception: " + e.getMessage());
            return;
        } catch (InterruptedException e) {
            Log.w(TAG, "Download interrupted: " + e.getMessage());
            return;
        }
    }
}

@@ -371,108 +371,16 @@
 oid.
-os.Handler;%0Aimport android.util.Log;%0Aimport android.widget.Toast;%0Aimport java.io.BufferedInputStream
+util.Log
 ;%0Aim
@@ -633,39 +633,8 @@
 RL;%0A
-import java.net.URLConnection;%0A
 impo
@@ -847,16 +847,16 @@
 ater%22;%0A%0A
-
     priv
@@ -859,16 +859,23 @@
 private 
+static 
 class Do
@@ -2787,15 +2787,15 @@
 byte
+%5B%5D
  data
-%5B%5D
  = n

Fix linter errors in ResourceUpdater (#7240)