Merge branch 'usb-otg-nearby-repos' into 'master'

fix repo handling on SDCard/USB-OTG

See merge request fdroid/fdroidclient!950
This commit is contained in:
Hans-Christoph Steiner 2020-11-18 21:57:39 +00:00
commit f4ae1aacc7
9 changed files with 98 additions and 47 deletions

View File

@ -100,7 +100,6 @@
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter"/> android:resource="@xml/device_filter"/>
</receiver> </receiver>
<receiver <receiver
android:name=".nearby.UsbDeviceDetachedReceiver"> android:name=".nearby.UsbDeviceDetachedReceiver">
<intent-filter> <intent-filter>
@ -110,6 +109,17 @@
android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
android:resource="@xml/device_filter"/> android:resource="@xml/device_filter"/>
</receiver> </receiver>
<receiver android:name=".nearby.UsbDeviceMediaMountedReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_EJECT" />
<action android:name="android.intent.action.MEDIA_REMOVED" />
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
<data android:scheme="content" />
<data android:scheme="file" />
</intent-filter>
</receiver>
<activity <activity
android:name=".panic.PanicPreferencesActivity" android:name=".panic.PanicPreferencesActivity"

View File

@ -28,11 +28,10 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.Process; import android.os.Process;
import androidx.core.content.ContextCompat;
import android.util.Log; import android.util.Log;
import androidx.core.content.ContextCompat;
import org.fdroid.fdroid.IndexUpdater; import org.fdroid.fdroid.IndexUpdater;
import org.fdroid.fdroid.IndexV1Updater; import org.fdroid.fdroid.IndexV1Updater;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import java.io.File; import java.io.File;
@ -55,7 +54,7 @@ import java.util.List;
* "External Storage" * "External Storage"
* <p> * <p>
* Scanning the removable storage requires that the user allowed it. This * Scanning the removable storage requires that the user allowed it. This
* requires both the {@link Preferences#isScanRemovableStorageEnabled()} * requires both the {@link org.fdroid.fdroid.Preferences#isScanRemovableStorageEnabled()}
* and the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} * and the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
* permission to be enabled. * permission to be enabled.
* *
@ -75,12 +74,10 @@ public class SDCardScannerService extends IntentService {
} }
public static void scan(Context context) { public static void scan(Context context) {
if (Preferences.get().isScanRemovableStorageEnabled()) {
Intent intent = new Intent(context, SDCardScannerService.class); Intent intent = new Intent(context, SDCardScannerService.class);
intent.setAction(ACTION_SCAN); intent.setAction(ACTION_SCAN);
context.startService(intent); context.startService(intent);
} }
}
@Override @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {

View File

@ -20,7 +20,6 @@
package org.fdroid.fdroid.nearby; package org.fdroid.fdroid.nearby;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.app.IntentService; import android.app.IntentService;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
@ -28,15 +27,14 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Process; import android.os.Process;
import androidx.documentfile.provider.DocumentFile;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import androidx.documentfile.provider.DocumentFile;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.fdroid.fdroid.AddRepoIntentService; import org.fdroid.fdroid.AddRepoIntentService;
import org.fdroid.fdroid.IndexUpdater; import org.fdroid.fdroid.IndexUpdater;
import org.fdroid.fdroid.IndexV1Updater; import org.fdroid.fdroid.IndexV1Updater;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Repo;
@ -76,19 +74,22 @@ public class TreeUriScannerIntentService extends IntentService {
public static final String TAG = "TreeUriScannerIntentSer"; public static final String TAG = "TreeUriScannerIntentSer";
private static final String ACTION_SCAN_TREE_URI = "org.fdroid.fdroid.nearby.action.SCAN_TREE_URI"; private static final String ACTION_SCAN_TREE_URI = "org.fdroid.fdroid.nearby.action.SCAN_TREE_URI";
/**
* @see <a href="https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r38/core/java/android/provider/DocumentsContract.java#238">DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY</a>
* @see <a href="https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r38/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java#70">ExternalStorageProvider.AUTHORITY</a>
*/
public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents";
public TreeUriScannerIntentService() { public TreeUriScannerIntentService() {
super("TreeUriScannerIntentService"); super("TreeUriScannerIntentService");
} }
public static void scan(Context context, Uri data) { public static void scan(Context context, Uri data) {
if (Preferences.get().isScanRemovableStorageEnabled()) {
Intent intent = new Intent(context, TreeUriScannerIntentService.class); Intent intent = new Intent(context, TreeUriScannerIntentService.class);
intent.setAction(ACTION_SCAN_TREE_URI); intent.setAction(ACTION_SCAN_TREE_URI);
intent.setData(data); intent.setData(data);
context.startService(intent); context.startService(intent);
} }
}
/** /**
* Now determine if it is External Storage that must be handled by the * Now determine if it is External Storage that must be handled by the

View File

@ -19,28 +19,21 @@
package org.fdroid.fdroid.nearby; package org.fdroid.fdroid.nearby;
import android.app.Activity;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.UriPermission; import android.content.UriPermission;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.views.main.MainActivity; import androidx.annotation.RequiresApi;
import org.fdroid.fdroid.views.main.NearbyViewBinder; import org.fdroid.fdroid.views.main.NearbyViewBinder;
import java.util.HashMap;
/** /**
* This is just a shim to receive {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} * This is just a shim to receive {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED}
@ -49,7 +42,6 @@ import java.util.HashMap;
public class UsbDeviceAttachedReceiver extends BroadcastReceiver { public class UsbDeviceAttachedReceiver extends BroadcastReceiver {
public static final String TAG = "UsbDeviceAttachedReceiv"; public static final String TAG = "UsbDeviceAttachedReceiv";
private static final HashMap<Uri, ContentObserver> contentObservers = new HashMap<>();
@RequiresApi(api = 19) @RequiresApi(api = 19)
@Override @Override
@ -77,6 +69,7 @@ public class UsbDeviceAttachedReceiver extends BroadcastReceiver {
} }
}; };
contentResolver.registerContentObserver(uri, true, contentObserver); contentResolver.registerContentObserver(uri, true, contentObserver);
UsbDeviceDetachedReceiver.contentObservers.put(uri, contentObserver);
} }
} }
} }

View File

@ -19,25 +19,17 @@
package org.fdroid.fdroid.nearby; package org.fdroid.fdroid.nearby;
import android.app.Activity;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.UriPermission;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.views.main.MainActivity; import androidx.annotation.RequiresApi;
import org.fdroid.fdroid.views.main.NearbyViewBinder; import org.fdroid.fdroid.views.main.NearbyViewBinder;
import java.util.HashMap; import java.util.HashMap;
@ -49,7 +41,7 @@ import java.util.HashMap;
public class UsbDeviceDetachedReceiver extends BroadcastReceiver { public class UsbDeviceDetachedReceiver extends BroadcastReceiver {
public static final String TAG = "UsbDeviceDetachedReceiv"; public static final String TAG = "UsbDeviceDetachedReceiv";
private static final HashMap<Uri, ContentObserver> contentObservers = new HashMap<>(); static final HashMap<Uri, ContentObserver> contentObservers = new HashMap<>();
@RequiresApi(api = 19) @RequiresApi(api = 19)
@Override @Override

View File

@ -0,0 +1,23 @@
package org.fdroid.fdroid.nearby;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import org.fdroid.fdroid.views.main.NearbyViewBinder;
public class UsbDeviceMediaMountedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || intent.getAction() == null) {
return;
}
String action = intent.getAction();
if (Environment.MEDIA_BAD_REMOVAL.equals(action)
|| Environment.MEDIA_MOUNTED.equals(action)
|| Environment.MEDIA_REMOVED.equals(action)
|| Environment.MEDIA_EJECTING.equals(action)) {
NearbyViewBinder.updateUsbOtg(context);
}
}
}

View File

@ -13,6 +13,7 @@ import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import android.provider.DocumentsContract;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@ -21,11 +22,9 @@ import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.nearby.SDCardScannerService; import org.fdroid.fdroid.nearby.SDCardScannerService;
@ -61,6 +60,8 @@ import java.util.List;
* *
* @see TreeUriScannerIntentService * @see TreeUriScannerIntentService
* @see org.fdroid.fdroid.nearby.SDCardScannerService * @see org.fdroid.fdroid.nearby.SDCardScannerService
* <p>
* TODO use {@link StorageManager#registerStorageVolumeCallback(Executor, StorageManager.StorageVolumeCallback)}
*/ */
public class NearbyViewBinder { public class NearbyViewBinder {
public static final String TAG = "NearbyViewBinder"; public static final String TAG = "NearbyViewBinder";
@ -165,11 +166,26 @@ public class NearbyViewBinder {
for (final StorageVolume storageVolume : storageManager.getStorageVolumes()) { for (final StorageVolume storageVolume : storageManager.getStorageVolumes()) {
if (storageVolume.isRemovable() && !storageVolume.isPrimary()) { if (storageVolume.isRemovable() && !storageVolume.isPrimary()) {
Log.i(TAG, "StorageVolume: " + storageVolume); Log.i(TAG, "StorageVolume: " + storageVolume);
final Intent intent = storageVolume.createAccessIntent(null); Intent tmpIntent = null;
if (intent == null) { if (Build.VERSION.SDK_INT < 29) {
tmpIntent = storageVolume.createAccessIntent(null);
} else {
tmpIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
tmpIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI,
Uri.parse("content://"
+ TreeUriScannerIntentService.EXTERNAL_STORAGE_PROVIDER_AUTHORITY
+ "/tree/"
+ storageVolume.getUuid()
+ "%3A/document/"
+ storageVolume.getUuid()
+ "%3A"));
}
if (tmpIntent == null) {
Utils.debugLog(TAG, "Got null Storage Volume access Intent"); Utils.debugLog(TAG, "Got null Storage Volume access Intent");
return; return;
} }
final Intent intent = tmpIntent;
storageVolumeText.setVisibility(View.VISIBLE); storageVolumeText.setVisibility(View.VISIBLE);
String text = storageVolume.getDescription(context); String text = storageVolume.getDescription(context);
@ -196,8 +212,23 @@ public class NearbyViewBinder {
return; return;
} }
} }
((Activity) context).startActivityForResult(intent,
MainActivity.REQUEST_STORAGE_ACCESS); Activity activity = null;
if (context instanceof Activity) {
activity = (Activity) context;
} else if (swapView != null && swapView.getContext() instanceof Activity) {
activity = (Activity) swapView.getContext();
}
if (activity != null) {
activity.startActivityForResult(intent, MainActivity.REQUEST_STORAGE_ACCESS);
} else {
// scan in the background without requesting permissions
Toast.makeText(context.getApplicationContext(),
context.getString(R.string.scan_removable_storage_toast, externalStorage),
Toast.LENGTH_SHORT).show();
SDCardScannerService.scan(context);
}
} }
}); });
} }

View File

@ -539,8 +539,10 @@ public class FDroidApp extends Application {
atStartTime.edit().remove(queryStringKey).apply(); atStartTime.edit().remove(queryStringKey).apply();
} }
if (Preferences.get().isScanRemovableStorageEnabled()) {
SDCardScannerService.scan(this); SDCardScannerService.scan(this);
} }
}
/** /**
* Asks if the current process is "org.fdroid.fdroid:acra". * Asks if the current process is "org.fdroid.fdroid:acra".

View File

@ -21,14 +21,14 @@
package org.fdroid.fdroid.views.main; package org.fdroid.fdroid.views.main;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.view.Menu; import android.view.Menu;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
/** /**
@ -76,6 +76,8 @@ class MainViewAdapter extends RecyclerView.Adapter<MainViewController> {
long viewType = getItemId(holder.getAdapterPosition()); long viewType = getItemId(holder.getAdapterPosition());
if (viewType == R.id.updates) { if (viewType == R.id.updates) {
holder.bindUpdates(); holder.bindUpdates();
} else if (viewType == R.id.nearby) {
NearbyViewBinder.updateUsbOtg(activity);
} }
} }