File indexing completed on 2024-04-21 04:52:59
0001 /** 0002 * @file Kid3Activity.java 0003 * Specialized QtActivity for Kid3. 0004 * Based on the blog post from Ekkehard Genz. 0005 * https://blog.qt.io/blog/2017/12/01/sharing-files-android-ios-qt-app/ 0006 * 0007 * @b Project: Kid3 0008 * @author Urs Fleisch 0009 * @date 27 Feb 2019 0010 * 0011 * Copyright (C) 2019 Urs Fleisch 0012 * 0013 * This file is part of Kid3. 0014 * 0015 * Kid3 is free software; you can redistribute it and/or modify 0016 * it under the terms of the GNU General Public License as published by 0017 * the Free Software Foundation; either version 2 of the License, or 0018 * (at your option) any later version. 0019 * 0020 * Kid3 is distributed in the hope that it will be useful, 0021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0023 * GNU General Public License for more details. 0024 * 0025 * You should have received a copy of the GNU General Public License 0026 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0027 */ 0028 0029 package net.sourceforge.kid3; 0030 0031 import java.io.File; 0032 import java.lang.String; 0033 import android.content.ContentUris; 0034 import android.content.Context; 0035 import android.content.Intent; 0036 import android.database.Cursor; 0037 import android.os.Build; 0038 import android.os.Bundle; 0039 import android.os.Environment; 0040 import android.net.Uri; 0041 import android.provider.DocumentsContract; 0042 import android.provider.MediaStore; 0043 import android.util.Log; 0044 import org.qtproject.qt5.android.bindings.QtActivity; 0045 0046 public class Kid3Activity extends QtActivity { 0047 // Implemented in androidutils.cpp 0048 public static native void setFilePathFromIntent(String path); 0049 0050 private static boolean isIntentPending; 0051 private static boolean isInitialized; 0052 0053 // Called with intent when app is not yet running. 0054 @Override 0055 public void onCreate(Bundle savedInstanceState) { 0056 super.onCreate(savedInstanceState); 0057 Log.d("Kid3", "onCreate"); 0058 Intent intent = getIntent(); 0059 if (intent != null) { 0060 String action = intent.getAction(); 0061 if (action != null) { 0062 Log.d("Kid3", "intent action " + action); 0063 // Will be processed when C++ application is ready and calling checkPendingIntents() 0064 isIntentPending = true; 0065 } 0066 } 0067 } 0068 0069 // Called with intent when app is already running. 0070 @Override 0071 public void onNewIntent(Intent intent) { 0072 Log.d("Kid3", "onNewIntent"); 0073 super.onNewIntent(intent); 0074 setIntent(intent); 0075 // Intent is processed when C++ application is ready and has called checkPendingIntents() 0076 if (isInitialized) { 0077 processIntent(); 0078 } else { 0079 isIntentPending = true; 0080 } 0081 } 0082 0083 // Called from C++ application to trigger signal emission with intent data. 0084 public void checkPendingIntents() { 0085 isInitialized = true; 0086 if (isIntentPending) { 0087 isIntentPending = false; 0088 Log.d("Kid3", "process intent"); 0089 processIntent(); 0090 } else { 0091 Log.d("Kid3", "no intent pending"); 0092 } 0093 } 0094 0095 // Process the Intent if Action is EDIT or VIEW. 0096 private void processIntent() { 0097 Intent intent = getIntent(); 0098 Log.d("Kid3", "action: " + intent.getAction()); 0099 if ("android.intent.action.VIEW".equals(intent.getAction()) || 0100 "android.intent.action.EDIT".equals(intent.getAction())) { 0101 Uri intentUri = intent.getData(); 0102 if (intentUri != null) { 0103 Log.d("Kid3", "Intent URI: " + intentUri.toString()); 0104 // content or file 0105 String intentScheme = intentUri.getScheme(); 0106 if ("file".equals(intentScheme)) { 0107 String filePath = intentUri.getPath(); 0108 if (filePath == null) { 0109 filePath = intentUri.toString(); 0110 } 0111 setFilePathFromIntent(filePath); 0112 } else if ("content".equals(intentScheme)) { 0113 String filePath = getRealPathFromURI(this, intentUri); 0114 if (filePath != null) { 0115 Log.d("Kid3", "Real path: " + filePath); 0116 setFilePathFromIntent(filePath); 0117 } 0118 } 0119 } 0120 } 0121 } 0122 0123 private static String getRealPathFromURI(final Context context, final Uri uri) { 0124 final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 0125 final String authority = uri.getAuthority(); 0126 if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 0127 // DocumentProvider 0128 if ("com.android.externalstorage.documents".equals(authority)) { 0129 // ExternalStorageProvider 0130 Log.d("Kid3", "ExternalStorageProvider"); 0131 final String docId = DocumentsContract.getDocumentId(uri); 0132 final String[] split = docId.split(":"); 0133 final String type = split[0]; 0134 if ("primary".equalsIgnoreCase(type)) { 0135 return Environment.getExternalStorageDirectory() + "/" + split[1]; 0136 } 0137 } else if ("com.android.providers.downloads.documents".equals(authority)) { 0138 // DownloadsProvider 0139 Log.d("Kid3", "DownloadsProvider"); 0140 final String id = DocumentsContract.getDocumentId(uri); 0141 Log.d("Kid3", "getDocumentId " + id); 0142 long longId = 0; 0143 try { 0144 longId = Long.valueOf(id); 0145 } catch (NumberFormatException nfe) { 0146 return getDataColumn(context, uri, null, null); 0147 } 0148 final Uri contentUri = ContentUris.withAppendedId( 0149 Uri.parse("content://downloads/public_downloads"), longId); 0150 return getDataColumn(context, contentUri, null, null); 0151 } else if ("com.android.providers.media.documents".equals(authority)) { 0152 // MediaProvider 0153 Log.d("Kid3", "MediaProvider"); 0154 final String docId = DocumentsContract.getDocumentId(uri); 0155 final String[] split = docId.split(":"); 0156 final String type = split[0]; 0157 Uri contentUri = null; 0158 if ("image".equals(type)) { 0159 contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 0160 } else if ("video".equals(type)) { 0161 contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 0162 } else if ("audio".equals(type)) { 0163 contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 0164 } 0165 final String selection = "_id=?"; 0166 final String[] selectionArgs = new String[]{split[1]}; 0167 return getDataColumn(context, contentUri, selection, selectionArgs); 0168 } 0169 } 0170 if ("content".equalsIgnoreCase(uri.getScheme())) { 0171 if ("com.google.android.apps.photos.content".equals(authority)) 0172 return uri.getLastPathSegment(); 0173 String path = getDataColumn(context, uri, null, null); 0174 if (path == null) { 0175 int colonPos; 0176 path = uri.getPath(); 0177 if (path != null && path.startsWith("/external_storage_root/")) { 0178 path = Environment.getExternalStorageDirectory() + path.substring(22); 0179 } else if (path != null && path.startsWith("/document/") && 0180 (colonPos = path.indexOf(':')) != -1) { 0181 String storagePath = "/storage/" + path.substring(10, colonPos) + 0182 "/" + path.substring(colonPos + 1); 0183 if ((new File(storagePath)).exists()) { 0184 path = storagePath; 0185 } 0186 } 0187 } 0188 return path; 0189 } else if ("file".equalsIgnoreCase(uri.getScheme())) { 0190 return uri.getPath(); 0191 } 0192 return null; 0193 } 0194 0195 // Get the value of the data column for this URI. 0196 private static String getDataColumn(Context context, Uri uri, String selection, 0197 String[] selectionArgs) { 0198 String result = null; 0199 final String column = "_data"; 0200 final String[] projection = {column}; 0201 Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, 0202 null); 0203 if (cursor != null) { 0204 if (cursor.moveToFirst()) { 0205 final int index = cursor.getColumnIndex(column); 0206 if (index != -1) { 0207 result = cursor.getString(index); 0208 } 0209 } 0210 cursor.close(); 0211 } 0212 return result; 0213 } 0214 }