mirror of
https://github.com/TeamAmaze/AmazeFileManager.git
synced 2026-10-18 05:37:24 +08:00
Fixed USB OTG URI forgetting when app pauses
This commit is contained in:
@@ -48,6 +48,7 @@ import android.service.quicksettings.TileService;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -91,9 +92,10 @@ import com.amaze.filemanager.filesystem.HybridFile;
|
||||
import com.amaze.filemanager.filesystem.HybridFileParcelable;
|
||||
import com.amaze.filemanager.filesystem.PasteHelper;
|
||||
import com.amaze.filemanager.filesystem.RootHelper;
|
||||
import com.amaze.filemanager.filesystem.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.filesystem.usb.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.filesystem.ssh.CustomSshJConfig;
|
||||
import com.amaze.filemanager.filesystem.ssh.SshConnectionPool;
|
||||
import com.amaze.filemanager.filesystem.usb.UsbOtgRepresentation;
|
||||
import com.amaze.filemanager.fragments.AppsListFragment;
|
||||
import com.amaze.filemanager.fragments.CloudSheetFragment;
|
||||
import com.amaze.filemanager.fragments.CloudSheetFragment.CloudConnectionCallbacks;
|
||||
@@ -686,32 +688,13 @@ public class MainActivity extends PermissionsActivity implements SmbConnectionLi
|
||||
if (usb != null && !rv.contains(usb.getPath())) rv.add(usb.getPath());
|
||||
|
||||
if (SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (isUsbDeviceConnected()) rv.add(OTGUtil.PREFIX_OTG + "/");
|
||||
if (SingletonUsbOtg.getInstance().isDeviceConnected()) {
|
||||
rv.add(OTGUtil.PREFIX_OTG + "/");
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method finds whether a USB device is connected or not
|
||||
* @return true if device is connected
|
||||
*/
|
||||
private boolean isUsbDeviceConnected() {
|
||||
if (OTGUtil.isMassStorageDeviceConnected(this)) {
|
||||
if(!SingletonUsbOtg.getInstance().hasRootBeenRequested()) {
|
||||
SingletonUsbOtg.getInstance().setHasRootBeenRequested(false);
|
||||
// we need to set this every time as there is no way to know that whether USB device was
|
||||
// disconnected after closing the app and another one was connected in that case
|
||||
// the URI will obviously change otherwise we could persist the URI even after
|
||||
// reopening the app by not writing this preference when it's not null
|
||||
SingletonUsbOtg.getInstance().setUsbOtgRoot(null);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
SingletonUsbOtg.getInstance().setUsbOtgRoot(null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!drawer.isLocked() && drawer.isOpen()) {
|
||||
@@ -1135,28 +1118,65 @@ public class MainActivity extends PermissionsActivity implements SmbConnectionLi
|
||||
registerReceiver(receiver2, new IntentFilter(TAG_INTENT_FILTER_GENERAL));
|
||||
|
||||
if (SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
// Registering intent filter for OTG
|
||||
IntentFilter otgFilter = new IntentFilter();
|
||||
otgFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
otgFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
registerReceiver(mOtgReceiver, otgFilter);
|
||||
updateUsbInformation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates everything related to USB devices
|
||||
* MUST ALWAYS be called after onResume()
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
private void updateUsbInformation() {
|
||||
boolean isInformationUpdated = false;
|
||||
List<UsbOtgRepresentation> connectedDevices = OTGUtil.getMassStorageDevicesConnected(this);
|
||||
|
||||
if(!connectedDevices.isEmpty()) {
|
||||
if (SingletonUsbOtg.getInstance().getUsbOtgRoot() != null && OTGUtil.isUsbUriAccessible(this)) {
|
||||
for (UsbOtgRepresentation device : connectedDevices) {
|
||||
if (SingletonUsbOtg.getInstance().checkIfRootIsFromDevice(device)) {
|
||||
isInformationUpdated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isInformationUpdated) {
|
||||
SingletonUsbOtg.getInstance().resetUsbOtgRoot();
|
||||
}
|
||||
}
|
||||
|
||||
if(!isInformationUpdated) {
|
||||
SingletonUsbOtg.getInstance().setConnectedDevice(connectedDevices.get(0));
|
||||
isInformationUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isInformationUpdated) {
|
||||
SingletonUsbOtg.getInstance().resetUsbOtgRoot();
|
||||
drawer.refreshDrawer();
|
||||
goToMain(null);
|
||||
}
|
||||
|
||||
// Registering intent filter for OTG
|
||||
IntentFilter otgFilter = new IntentFilter();
|
||||
otgFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
otgFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
registerReceiver(mOtgReceiver, otgFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receiver to check if a USB device is connected at the runtime of application
|
||||
* If device is not connected at runtime (i.e. it was connected when the app was closed)
|
||||
* then {@link #isUsbDeviceConnected()} method handles the connection through
|
||||
* {@link #getStorageDirectories()}
|
||||
*/
|
||||
BroadcastReceiver mOtgReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
|
||||
SingletonUsbOtg.getInstance().setUsbOtgRoot(null);
|
||||
SingletonUsbOtg.getInstance().resetUsbOtgRoot();
|
||||
List<UsbOtgRepresentation> connectedDevices = OTGUtil.getMassStorageDevicesConnected(MainActivity.this);
|
||||
SingletonUsbOtg.getInstance().setConnectedDevice(connectedDevices.get(0));
|
||||
drawer.refreshDrawer();
|
||||
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
|
||||
SingletonUsbOtg.getInstance().setUsbOtgRoot(null);
|
||||
SingletonUsbOtg.getInstance().resetUsbOtgRoot();
|
||||
drawer.refreshDrawer();
|
||||
goToMain(null);
|
||||
}
|
||||
@@ -1594,7 +1614,7 @@ public class MainActivity extends PermissionsActivity implements SmbConnectionLi
|
||||
|
||||
if (SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
|
||||
SingletonUsbOtg.getInstance().setUsbOtgRoot(null);
|
||||
SingletonUsbOtg.getInstance().resetUsbOtgRoot();
|
||||
drawer.refreshDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.amaze.filemanager.filesystem;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
public class SingletonUsbOtg {
|
||||
private static SingletonUsbOtg instance = null;
|
||||
|
||||
public static SingletonUsbOtg getInstance() {
|
||||
if(instance == null) instance = new SingletonUsbOtg();
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Uri usbOtgRoot = null;
|
||||
/**
|
||||
* Indicates whether last app exit was for setting {@link #usbOtgRoot} or not
|
||||
*/
|
||||
private boolean hasRootBeenRequested = false;
|
||||
|
||||
private SingletonUsbOtg() { }
|
||||
|
||||
public void setUsbOtgRoot(@Nullable Uri root) {
|
||||
usbOtgRoot = root;
|
||||
}
|
||||
|
||||
public @Nullable Uri getUsbOtgRoot() {
|
||||
return usbOtgRoot;
|
||||
}
|
||||
|
||||
public void setHasRootBeenRequested(boolean hasRootBeenRequested) {
|
||||
this.hasRootBeenRequested = hasRootBeenRequested;
|
||||
}
|
||||
|
||||
public boolean hasRootBeenRequested() {
|
||||
return hasRootBeenRequested;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.amaze.filemanager.filesystem.usb;
|
||||
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
public class SingletonUsbOtg {
|
||||
private static SingletonUsbOtg instance = null;
|
||||
|
||||
public static SingletonUsbOtg getInstance() {
|
||||
if(instance == null) instance = new SingletonUsbOtg();
|
||||
return instance;
|
||||
}
|
||||
|
||||
private UsbOtgRepresentation connectedDevice = null;
|
||||
private @Nullable Uri usbOtgRoot;
|
||||
|
||||
private SingletonUsbOtg() { }
|
||||
|
||||
public void setConnectedDevice(UsbOtgRepresentation connectedDevice) {
|
||||
this.connectedDevice = connectedDevice;
|
||||
}
|
||||
|
||||
public boolean isDeviceConnected() {
|
||||
return connectedDevice != null;
|
||||
}
|
||||
|
||||
public void setUsbOtgRoot(@Nullable Uri root) {
|
||||
if(connectedDevice == null) throw new IllegalStateException("No device connected!");
|
||||
usbOtgRoot = root;
|
||||
}
|
||||
|
||||
public void resetUsbOtgRoot() {
|
||||
connectedDevice = null;
|
||||
usbOtgRoot = null;
|
||||
}
|
||||
|
||||
public @Nullable Uri getUsbOtgRoot() {
|
||||
return usbOtgRoot;
|
||||
}
|
||||
|
||||
public boolean checkIfRootIsFromDevice(@NonNull UsbOtgRepresentation device) {
|
||||
return usbOtgRoot != null && connectedDevice.hashCode() == device.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.amaze.filemanager.filesystem.usb;
|
||||
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.amaze.filemanager.utils.Utils;
|
||||
|
||||
/**
|
||||
* This class replesents a usb device.
|
||||
*
|
||||
* @see UsbOtgRepresentation#equals(Object)
|
||||
*/
|
||||
public class UsbOtgRepresentation {
|
||||
|
||||
public final int productID, vendorID;
|
||||
public final @Nullable String serialNumber;
|
||||
|
||||
public UsbOtgRepresentation(int productID, int vendorID, @Nullable String serialNumber) {
|
||||
this.productID = productID;
|
||||
this.vendorID = vendorID;
|
||||
this.serialNumber = serialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* This does not ensure a device is equal to another!
|
||||
* This tests parameters to know to a certain degree of certanty that a device is "similar enough"
|
||||
* to another one to be the same one.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof UsbOtgRepresentation)) return false;
|
||||
|
||||
UsbOtgRepresentation other = (UsbOtgRepresentation) obj;
|
||||
return productID == other.productID && vendorID == other.vendorID
|
||||
&& ((serialNumber == null && other.serialNumber == null) || serialNumber.equals(other.serialNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = productID;
|
||||
result = 37 * result + vendorID;
|
||||
result = 37 * result + (serialNumber != null? serialNumber.hashCode():0);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,7 +56,7 @@ import com.amaze.filemanager.activities.PreferencesActivity;
|
||||
import com.amaze.filemanager.database.CloudHandler;
|
||||
import com.amaze.filemanager.filesystem.HybridFile;
|
||||
import com.amaze.filemanager.filesystem.RootHelper;
|
||||
import com.amaze.filemanager.filesystem.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.filesystem.usb.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.fragments.AppsListFragment;
|
||||
import com.amaze.filemanager.fragments.CloudSheetFragment;
|
||||
import com.amaze.filemanager.fragments.FtpServerFragment;
|
||||
@@ -582,13 +582,10 @@ public class Drawer implements NavigationView.OnNavigationItemSelectedListener {
|
||||
&& SingletonUsbOtg.getInstance().getUsbOtgRoot() == null) {
|
||||
MaterialDialog dialog = GeneralDialogCreation.showOtgSafExplanationDialog(mainActivity);
|
||||
dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener((v) -> {
|
||||
SingletonUsbOtg.getInstance().setHasRootBeenRequested(true);
|
||||
Intent safIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
mainActivity.startActivityForResult(safIntent, MainActivity.REQUEST_CODE_SAF);
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
} else {
|
||||
pendingPath = meta.path;
|
||||
closeIfNotLocked();
|
||||
|
||||
@@ -3,18 +3,26 @@ package com.amaze.filemanager.utils;
|
||||
import android.content.Context;
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
import android.util.Log;
|
||||
|
||||
import com.amaze.filemanager.filesystem.HybridFileParcelable;
|
||||
import com.amaze.filemanager.filesystem.RootHelper;
|
||||
import com.amaze.filemanager.filesystem.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.filesystem.usb.SingletonUsbOtg;
|
||||
import com.amaze.filemanager.filesystem.usb.UsbOtgRepresentation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import static android.content.Context.USB_SERVICE;
|
||||
|
||||
@@ -108,26 +116,41 @@ public class OTGUtil {
|
||||
return rootUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the usb uri is still accessible
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public static boolean isUsbUriAccessible(Context context) {
|
||||
Uri rootUriString = SingletonUsbOtg.getInstance().getUsbOtgRoot();
|
||||
return DocumentsContract.isDocumentUri(context, rootUriString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is at least one USB device connected with class MASS STORAGE.
|
||||
*/
|
||||
public static boolean isMassStorageDeviceConnected(@NonNull final Context context) {
|
||||
@NonNull
|
||||
public static List<UsbOtgRepresentation> getMassStorageDevicesConnected(@NonNull final Context context) {
|
||||
UsbManager usbManager = (UsbManager) context.getSystemService(USB_SERVICE);
|
||||
if(usbManager == null) return false;
|
||||
if(usbManager == null) return Collections.emptyList();
|
||||
|
||||
HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
|
||||
ArrayList<UsbOtgRepresentation> usbOtgRepresentations = new ArrayList<>();
|
||||
|
||||
for (String deviceName : devices.keySet()) {
|
||||
UsbDevice device = devices.get(deviceName);
|
||||
|
||||
for (int i = 0; i < device.getInterfaceCount(); i++){
|
||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_MASS_STORAGE){
|
||||
return true;
|
||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_MASS_STORAGE) {
|
||||
final @Nullable String serial =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP? device.getSerialNumber():null;
|
||||
|
||||
UsbOtgRepresentation usb = new UsbOtgRepresentation(device.getProductId(), device.getVendorId(), serial);
|
||||
usbOtgRepresentations.add(usb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return usbOtgRepresentations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user