From 1659fe26b9ca7f54f062fbe43b034b866a747dff Mon Sep 17 00:00:00 2001 From: Gabriele M Date: Wed, 19 Jul 2017 21:11:47 +0200 Subject: [PATCH] Allow to export verified updates --- AndroidManifest.xml | 1 + res/drawable/ic_save.xml | 9 + res/menu/menu_action_mode.xml | 6 + res/values/strings.xml | 11 ++ .../lineageos/updater/UpdatesListAdapter.java | 28 +++ src/org/lineageos/updater/misc/FileUtils.java | 180 ++++++++++++++++++ .../updater/misc/PermissionsUtils.java | 69 +++++++ src/org/lineageos/updater/misc/Utils.java | 12 ++ 8 files changed, 316 insertions(+) create mode 100644 res/drawable/ic_save.xml create mode 100644 src/org/lineageos/updater/misc/FileUtils.java create mode 100644 src/org/lineageos/updater/misc/PermissionsUtils.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e998849..c356d29 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -8,6 +8,7 @@ + + + diff --git a/res/menu/menu_action_mode.xml b/res/menu/menu_action_mode.xml index 4b27c3c..6b355e6 100644 --- a/res/menu/menu_action_mode.xml +++ b/res/menu/menu_action_mode.xml @@ -1,6 +1,12 @@ + /data/lineageos_updates/ + + LineageOS updates/ + https://download.lineageos.org/api Verification failed @@ -51,6 +55,7 @@ Auto updates check Delete Copy URL + Export update Checking for updates New updates found @@ -89,6 +94,12 @@ Download URL URL Copied + Could not export download + Exporting update + Exporting update as %1$s into the external storage. + Update exported + Export error + 1 second %d seconds diff --git a/src/org/lineageos/updater/UpdatesListAdapter.java b/src/org/lineageos/updater/UpdatesListAdapter.java index 7f722c8..e3d0e1b 100644 --- a/src/org/lineageos/updater/UpdatesListAdapter.java +++ b/src/org/lineageos/updater/UpdatesListAdapter.java @@ -35,11 +35,14 @@ import android.widget.TextView; import org.lineageos.updater.controller.Controller; import org.lineageos.updater.misc.BuildInfoUtils; +import org.lineageos.updater.misc.FileUtils; +import org.lineageos.updater.misc.PermissionsUtils; import org.lineageos.updater.misc.StringGenerator; import org.lineageos.updater.misc.Utils; import org.lineageos.updater.model.UpdateDownload; import org.lineageos.updater.model.UpdateStatus; +import java.io.File; import java.io.IOException; import java.text.DateFormat; import java.text.NumberFormat; @@ -429,6 +432,8 @@ public class UpdatesListAdapter extends RecyclerView.Adapter 0) { + mSizeRead += read; + int progress = mSize > 0 ? Math.round(mSizeRead * 100.f / mSize) : -1; + if (mProgress != progress) { + mCallback.update(progress); + mProgress = progress; + } + } + return read; + } + } + + public static void copyFile(File sourceFile, File destFile, ProgressCallBack progressCallBack) + throws IOException { + try (FileChannel sourceChannel = new FileInputStream(sourceFile).getChannel(); + FileChannel destChannel = new FileOutputStream(destFile).getChannel()) { + if (progressCallBack != null) { + ReadableByteChannel readableByteChannel = new CallbackByteChannel(sourceChannel, + sourceFile.length(), progressCallBack); + destChannel.transferFrom(readableByteChannel, 0, sourceChannel.size()); + } else { + destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); + } + } catch (IOException e) { + Log.e(TAG, "Could not copy file", e); + if (destFile.exists()) { + destFile.delete(); + } + throw e; + } + } + + public static void copyFile(File sourceFile, File destFile) throws IOException { + copyFile(sourceFile, destFile, null); + } + + public static void copyFileWithDialog(Context context, File sourceFile, File destFile) + throws IOException { + + final int NOTIFICATION_ID = 11; + + new AsyncTask() { + + private ProgressDialog mProgressDialog; + private boolean mCancelled; + private ProgressCallBack mProgressCallBack; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + mProgressDialog = new ProgressDialog(context); + mProgressDialog.setTitle(context.getString(R.string.dialog_export_title)); + mProgressDialog.setMessage( + context.getString(R.string.dialog_export_message, destFile.getName())); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + mProgressDialog.setCancelable(true); + mProgressDialog.setProgressNumberFormat(null); + mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + cancel(true); + } + }); + mProgressDialog.setCanceledOnTouchOutside(false); + mProgressCallBack = new ProgressCallBack() { + @Override + public void update(int progress) { + mProgressDialog.setProgress(progress); + } + }; + mProgressDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + try { + copyFile(sourceFile, destFile, mProgressCallBack); + return true; + } catch (IOException e) { + return false; + } + } + + @Override + protected void onCancelled() { + mCancelled = true; + destFile.delete(); + } + + @Override + protected void onPostExecute(Boolean success) { + mProgressDialog.dismiss(); + if (mCancelled) { + destFile.delete(); + } else { + NotificationManager nm = (NotificationManager) context.getSystemService( + Context.NOTIFICATION_SERVICE); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + builder.setSmallIcon(R.drawable.ic_system_update); + builder.setContentTitle( + success ? context.getString(R.string.notification_export_success) + : context.getString(R.string.notification_export_fail)); + builder.setContentText(destFile.getName()); + final String notificationTag = destFile.getAbsolutePath(); + nm.notify(notificationTag, NOTIFICATION_ID, builder.build()); + } + } + }.execute(); + } +} diff --git a/src/org/lineageos/updater/misc/PermissionsUtils.java b/src/org/lineageos/updater/misc/PermissionsUtils.java new file mode 100644 index 0000000..aeaf0dc --- /dev/null +++ b/src/org/lineageos/updater/misc/PermissionsUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 The LineageOS 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 org.lineageos.updater.misc; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; + +import java.util.ArrayList; +import java.util.List; + +public class PermissionsUtils { + + public static boolean hasPermission(Context context, String permission) { + int permissionState = context.checkSelfPermission(permission); + return permissionState == PackageManager.PERMISSION_GRANTED; + } + + /** + * Check the given permissions and requests them if needed. + * + * @param activity The target activity + * @param permissions The permissions to check + * @param requestCode @see Activity#requestPermissions(String[] , int) + * @return true if the permission is granted, false otherwise + */ + public static boolean checkAndRequestPermissions(final Activity activity, + final String[] permissions, final int requestCode) { + List permissionsList = new ArrayList<>(); + for (String permission : permissions) { + if (!hasPermission(activity, permission)) { + permissionsList.add(permission); + } + } + if (permissionsList.size() == 0) { + return true; + } else { + String[] permissionsArray = new String[permissionsList.size()]; + permissionsArray = permissionsList.toArray(permissionsArray); + activity.requestPermissions(permissionsArray, requestCode); + return false; + } + } + + /** + * Check and request the write external storage permission + * + * @see #checkAndRequestPermissions(Activity, String[], int) + */ + public static boolean checkAndRequestStoragePermission(Activity activity, int requestCode) { + return checkAndRequestPermissions(activity, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + requestCode); + } +} diff --git a/src/org/lineageos/updater/misc/Utils.java b/src/org/lineageos/updater/misc/Utils.java index 35fd739..5f7849f 100644 --- a/src/org/lineageos/updater/misc/Utils.java +++ b/src/org/lineageos/updater/misc/Utils.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Environment; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.util.Log; @@ -60,6 +61,17 @@ public class Utils { return new File(context.getString(R.string.download_path)); } + public static File getExportPath(Context context) { + File dir = new File(Environment.getExternalStorageDirectory(), + context.getString(R.string.export_path)); + if (!dir.isDirectory()) { + if (dir.exists() || !dir.mkdirs()) { + throw new RuntimeException("Could not create directory"); + } + } + return dir; + } + public static File getCachedUpdateList(Context context) { return new File(context.getCacheDir(), "updates.json"); }