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 }