diff --git a/app/build.gradle b/app/build.gradle index f24121309..688f072b1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId 'com.seafile.seadroid2' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 134 - versionName "2.3.3" + versionCode 137 + versionName "2.3.4" multiDexEnabled true resValue "string", "authorities", applicationId + '.cameraupload.provider' resValue "string", "account_type", "com.seafile.seadroid2.account.api2" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85a42d4fb..31d0b8652 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,7 +26,7 @@ - + diff --git a/app/src/main/java/com/seafile/seadroid2/SeadroidApplication.java b/app/src/main/java/com/seafile/seadroid2/SeadroidApplication.java index 70a841e15..62289cc2a 100644 --- a/app/src/main/java/com/seafile/seadroid2/SeadroidApplication.java +++ b/app/src/main/java/com/seafile/seadroid2/SeadroidApplication.java @@ -10,6 +10,8 @@ import com.seafile.seadroid2.gesturelock.AppLockManager; import com.seafile.seadroid2.ui.CustomNotificationBuilder; import com.seafile.seadroid2.util.CrashHandler; +import com.seafile.seadroid2.util.DeviceIdManager; +import com.seafile.seadroid2.util.SeafileLog; import com.seafile.seadroid2.util.Utils; public class SeadroidApplication extends Application { diff --git a/app/src/main/java/com/seafile/seadroid2/account/ui/SingleSignOnAuthorizeActivity.java b/app/src/main/java/com/seafile/seadroid2/account/ui/SingleSignOnAuthorizeActivity.java index b76e9f8ae..3183e672c 100644 --- a/app/src/main/java/com/seafile/seadroid2/account/ui/SingleSignOnAuthorizeActivity.java +++ b/app/src/main/java/com/seafile/seadroid2/account/ui/SingleSignOnAuthorizeActivity.java @@ -32,6 +32,7 @@ import com.seafile.seadroid2.ui.activity.BaseActivity; import com.seafile.seadroid2.ui.dialog.SslConfirmDialog; import com.seafile.seadroid2.util.ConcurrentAsyncTask; +import com.seafile.seadroid2.util.DeviceIdManager; import com.seafile.seadroid2.util.Utils; import org.json.JSONException; @@ -89,8 +90,6 @@ private void openAuthorizePage(String url) { return; } - String deviceId = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID); - String appVersion = ""; Context context = SeadroidApplication.getAppContext(); try { @@ -105,18 +104,20 @@ private void openAuthorizePage(String url) { } else url += "shib-login"; + //local device id + String deviceId = DeviceIdManager.getInstance().getOrSet(); + try { url += String.format("?shib_platform_version=%s&shib_device_name=%s&shib_platform=%s&shib_device_id=%s&shib_client_version=%s", URLEncoder.encode(Build.VERSION.RELEASE, "UTF-8"), URLEncoder.encode(Build.MODEL, "UTF-8"), "android", - URLEncoder.encode(deviceId, "UTF-8"), + deviceId, appVersion); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } - Log.d(DEBUG_TAG, "url " + url); mWebview.loadUrl(url); diff --git a/app/src/main/java/com/seafile/seadroid2/ui/WidgetUtils.java b/app/src/main/java/com/seafile/seadroid2/ui/WidgetUtils.java index 0492a8a77..9b91b414f 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/WidgetUtils.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/WidgetUtils.java @@ -1,11 +1,24 @@ package com.seafile.seadroid2.ui; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.content.Context.NOTIFICATION_SERVICE; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + import android.app.Activity; +import android.app.DownloadManager; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.ActivityNotFoundException; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.support.v4.app.NotificationCompat; import android.support.v4.content.FileProvider; import android.text.ClipboardManager; import android.webkit.MimeTypeMap; @@ -23,16 +36,21 @@ import com.seafile.seadroid2.ui.dialog.GetShareLinkDialog; import com.seafile.seadroid2.ui.dialog.GetShareLinkEncryptDialog; import com.seafile.seadroid2.ui.dialog.TaskDialog; +import com.seafile.seadroid2.util.FileExports; import com.seafile.seadroid2.util.Utils; import java.io.File; +import java.io.IOException; import java.net.HttpURLConnection; +import java.security.SecureRandom; import java.util.List; +import java.util.Random; /** * Activity Utils */ public class WidgetUtils { + public static final String MIME_ANDROID = "application/vnd.android.package-archive"; public static void chooseShareApp(final BaseActivity activity, final String repoID, @@ -226,17 +244,23 @@ public static void showFile(final BaseActivity activity, File file, boolean isOp } else if (mime == null) { mime = "*/*"; // forces app chooser dialog on unknown type// } + + if (MIME_ANDROID.equals(mime)) { +// showFileForAndroid(activity,file,name); + return; + } + Intent open = new Intent(Intent.ACTION_VIEW); - open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + open.addFlags(FLAG_ACTIVITY_NEW_TASK); - if (android.os.Build.VERSION.SDK_INT > 23) { + if (Build.VERSION.SDK_INT > 23) { Uri photoURI = FileProvider.getUriForFile(activity, activity.getApplicationContext().getPackageName(), file); open.setDataAndType(photoURI, mime); open.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { open.setDataAndType((Uri.fromFile(file)), mime); } - if (android.os.Build.VERSION.SDK_INT < 30) { + if (Build.VERSION.SDK_INT < 30) { if (activity.getPackageManager().resolveActivity(open, 0) == null) { String message = String.format(activity.getString(R.string.op_exception_suitable_app_not_found), mime); activity.showShortToast(activity, message); @@ -252,6 +276,39 @@ public static void showFile(final BaseActivity activity, File file, boolean isOp } } + private static void showFileForAndroid(final BaseActivity activity, File file, String fileName) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ContentResolver contentResolver = activity.getContentResolver(); + FileExports.exportFileAndroid10AndAbove(fileName, MIME_ANDROID, contentResolver, file); + } + } catch (IOException e) { + e.printStackTrace(); + } + + int nId = new Random(10000).nextInt(); + String channelName = "seadroid-downloader"; + + NotificationManager manager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + NotificationChannel channel = new NotificationChannel(channelName, channelName, NotificationManager.IMPORTANCE_HIGH); + manager.createNotificationChannel(channel); + + + Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS); + intent.addFlags(FLAG_ACTIVITY_NEW_TASK); + + PendingIntent pendingIntent = PendingIntent.getActivity(activity, nId, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); + + Notification notification = new NotificationCompat.Builder(activity, channelName) + .setContentTitle(fileName + " " + activity.getString(R.string.download_finished)) + .setContentText(activity.getString(R.string.open)) + .setSmallIcon(R.drawable.icon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build(); + manager.notify(nId, notification); + } + public static void showRepo(Context context, String repoID, String repoName, String path, String dirID) { Intent intent = new Intent(context, BrowserActivity.class); intent.putExtra("repoID", repoID); diff --git a/app/src/main/java/com/seafile/seadroid2/util/DeviceIdManager.java b/app/src/main/java/com/seafile/seadroid2/util/DeviceIdManager.java new file mode 100644 index 000000000..ae8339dba --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/util/DeviceIdManager.java @@ -0,0 +1,71 @@ +package com.seafile.seadroid2.util; + +import android.bluetooth.le.AdvertiseData; +import android.bluetooth.le.AdvertiseSettings; + +import com.blankj.utilcode.util.FileUtils; +import com.seafile.seadroid2.SeadroidApplication; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.UUID; + +public class DeviceIdManager { + private static volatile DeviceIdManager mSingleton = null; + public static final String PREFIX = ".sd-"; + public final File LOCAL_FOLDER = SeadroidApplication.getAppContext().getExternalCacheDir(); + + private DeviceIdManager() { + + } + + public static DeviceIdManager getInstance() { + if (mSingleton == null) { + synchronized (DeviceIdManager.class) { + if (mSingleton == null) { + mSingleton = new DeviceIdManager(); + } + } + } + return mSingleton; + } + + public String getOrSet() { + File stFile = checkLocalDeviceIdFileExistsState(); + if (stFile != null) { + String name = stFile.getName().replace(PREFIX, ""); + return name.substring(0, 16); + } + + String uid = UUID.randomUUID().toString().replace("-", ""); + File file = new File(LOCAL_FOLDER.getAbsolutePath() + "/" + PREFIX + uid); + FileUtils.createOrExistsFile(file); + return uid.substring(0, 16); + } + + public File checkLocalDeviceIdFileExistsState() { + if (LOCAL_FOLDER == null) { + return null; + } + + File[] temp = LOCAL_FOLDER.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith(PREFIX); + } + }); + + if (temp == null) { + return null; + } + + if (temp.length == 1) { + return temp[0]; + } + + for (File file : temp) { + file.delete(); + } + return null; + } +} diff --git a/app/src/main/java/com/seafile/seadroid2/util/FileExports.java b/app/src/main/java/com/seafile/seadroid2/util/FileExports.java new file mode 100644 index 000000000..b1f2818bc --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/util/FileExports.java @@ -0,0 +1,54 @@ +package com.seafile.seadroid2.util; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.provider.MediaStore; +import android.support.annotation.RequiresApi; + +import com.blankj.utilcode.util.FileUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class FileExports { + @RequiresApi(api = Build.VERSION_CODES.Q) + public static void exportFileAndroid10AndAbove(String fileName, String mimeType, ContentResolver contentResolver, File file) throws IOException { + ContentValues cv = new ContentValues(); + cv.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); + cv.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); + cv.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); + + Uri uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, cv); + if (uri != null) { + ParcelFileDescriptor descriptor = contentResolver.openFileDescriptor(uri, "w"); + if (descriptor != null) { + FileOutputStream fos = new FileOutputStream(descriptor.getFileDescriptor()); + FileInputStream fis = new FileInputStream(file); + copyStream(fis, fos); + } + } else { + File downloadFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + // + File dest = new File(downloadFolder.getPath() + "/" + fileName); + if (!dest.exists()) { + FileUtils.copy(file, dest); + } + } + } + + private static void copyStream(InputStream inputStream, FileOutputStream outputStream) throws IOException { + byte[] buffer = new byte[1024]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); + } + } + +}