mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-07 09:01:38 -04:00
OS X/Linux: Show an informational popup message when an Android device is plugged in that needs the user to tap Allow for the connection to work.
This commit is contained in:
parent
c4931a2fcd
commit
6a82169373
@ -1,4 +1,4 @@
|
||||
__license__ = 'GPL v3'
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
"""
|
||||
Defines the errors that the device drivers generate.
|
||||
@ -18,8 +18,11 @@ class TimeoutError(ProtocolError):
|
||||
""" There was a timeout during communication """
|
||||
|
||||
def __init__(self, func_name):
|
||||
ProtocolError.__init__(self,
|
||||
"There was a timeout while communicating with the device in function: " +func_name)
|
||||
ProtocolError.__init__(
|
||||
self,
|
||||
"There was a timeout while communicating with the device in function: " +
|
||||
func_name
|
||||
)
|
||||
|
||||
|
||||
class DeviceError(ProtocolError):
|
||||
@ -54,7 +57,17 @@ class OpenFeedback(DeviceError):
|
||||
If you need to show the user a custom dialog, instead of just
|
||||
displaying the feedback_msg, create and return it here.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class OpenActionNeeded(DeviceError):
|
||||
|
||||
def __init__(self, device_name, msg, only_once_id):
|
||||
self.device_name, self.feedback_msg, self.only_once_id = device_name, msg, only_once_id
|
||||
DeviceError.__init__(self, msg)
|
||||
|
||||
def custom_dialog(self, parent):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class InitialConnectionError(OpenFeedback):
|
||||
@ -76,8 +89,10 @@ class DeviceBusy(ProtocolError):
|
||||
""" Raised when device is busy """
|
||||
|
||||
def __init__(self, uerr=""):
|
||||
ProtocolError.__init__(self, "Device is in use by another application:"
|
||||
"\nUnderlying error:" + str(uerr))
|
||||
ProtocolError.__init__(
|
||||
self, "Device is in use by another application:"
|
||||
"\nUnderlying error:" + str(uerr)
|
||||
)
|
||||
|
||||
|
||||
class DeviceLocked(ProtocolError):
|
||||
@ -138,4 +153,3 @@ class BlacklistedDevice(OpenFailed):
|
||||
blacklisted by the user. Only used in drivers that manage device presence,
|
||||
like the MTP driver. '''
|
||||
pass
|
||||
|
||||
|
@ -15,7 +15,7 @@ from functools import partial
|
||||
from calibre import prints, as_unicode
|
||||
from calibre.constants import plugins, islinux, isosx
|
||||
from calibre.ptempfile import SpooledTemporaryFile
|
||||
from calibre.devices.errors import OpenFailed, DeviceError, BlacklistedDevice
|
||||
from calibre.devices.errors import OpenFailed, DeviceError, BlacklistedDevice, OpenActionNeeded
|
||||
from calibre.devices.mtp.base import MTPDeviceBase, synchronous, debug
|
||||
|
||||
MTPDevice = namedtuple('MTPDevice', 'busnum devnum vendor_id product_id '
|
||||
@ -28,6 +28,7 @@ def fingerprint(d):
|
||||
return MTPDevice(d.busnum, d.devnum, d.vendor_id, d.product_id, d.bcd,
|
||||
d.serial, d.manufacturer, d.product)
|
||||
|
||||
|
||||
APPLE = 0x05ac
|
||||
|
||||
|
||||
@ -211,6 +212,7 @@ class MTP_DEVICE(MTPDeviceBase):
|
||||
@synchronous
|
||||
def open(self, connected_device, library_uuid):
|
||||
self.dev = self._filesystem_cache = None
|
||||
|
||||
try:
|
||||
self.dev = self.create_device(connected_device)
|
||||
except Exception as e:
|
||||
@ -218,7 +220,23 @@ class MTP_DEVICE(MTPDeviceBase):
|
||||
raise OpenFailed('Failed to open %s: Error: %s'%(
|
||||
connected_device, as_unicode(e)))
|
||||
|
||||
storage = sorted(self.dev.storage_info, key=operator.itemgetter('id'))
|
||||
try:
|
||||
storage = sorted(self.dev.storage_info, key=operator.itemgetter('id'))
|
||||
except self.libmtp.MTPError as e:
|
||||
if "The device has no storage information." in str(e):
|
||||
# This happens on newer Android devices while waiting for
|
||||
# the user to allow access. Apparently what happens is
|
||||
# that when the user clicks allow, the device disconnects
|
||||
# and re-connects as a new device.
|
||||
raise OpenActionNeeded(self.dev.friendly_name, _(
|
||||
'The device {0} is not allowing connections.'
|
||||
' Unlock the screen on the {0}, tap "Allow" on any connection popup message you see,'
|
||||
' then either wait a minute or restart calibre. You might'
|
||||
' also have to change the mode of the USB connection on the {0}'
|
||||
' to "Media Transfer mode (MTP)" or similar.'
|
||||
).format(self.dev.friendly_name), (self.dev.friendly_name, self.dev.serial_number))
|
||||
raise
|
||||
|
||||
storage = [x for x in storage if x.get('rw', False)]
|
||||
if not storage:
|
||||
self.blacklisted_devices.add(connected_device)
|
||||
@ -432,6 +450,7 @@ def develop():
|
||||
finally:
|
||||
dev.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dev = MTP_DEVICE(None)
|
||||
dev.startup()
|
||||
@ -442,4 +461,3 @@ if __name__ == '__main__':
|
||||
dev.debug_managed_device_detection(devs, sys.stdout)
|
||||
dev.set_debug_level(dev.LIBMTP_DEBUG_ALL)
|
||||
dev.shutdown()
|
||||
|
||||
|
@ -14,7 +14,7 @@ from PyQt5.Qt import (
|
||||
from calibre.customize.ui import (available_input_formats, available_output_formats,
|
||||
device_plugins, disabled_device_plugins)
|
||||
from calibre.devices.interface import DevicePlugin, currently_connected_device
|
||||
from calibre.devices.errors import (UserFeedback, OpenFeedback, OpenFailed,
|
||||
from calibre.devices.errors import (UserFeedback, OpenFeedback, OpenFailed, OpenActionNeeded,
|
||||
InitialConnectionError)
|
||||
from calibre.ebooks.covers import cprefs, override_prefs, scale_cover, generate_cover
|
||||
from calibre.gui2.dialogs.choose_format_device import ChooseFormatDeviceDialog
|
||||
@ -165,6 +165,7 @@ class DeviceManager(Thread): # {{{
|
||||
self.ejected_devices = set([])
|
||||
self.mount_connection_requests = Queue.Queue(0)
|
||||
self.open_feedback_slot = open_feedback_slot
|
||||
self.open_feedback_only_once_seen = set()
|
||||
self.after_callback_feedback_slot = after_callback_feedback_slot
|
||||
self.open_feedback_msg = open_feedback_msg
|
||||
self._device_information = None
|
||||
@ -296,6 +297,10 @@ class DeviceManager(Thread): # {{{
|
||||
except BlacklistedDevice as e:
|
||||
prints('Ignoring blacklisted device: %s'%
|
||||
as_unicode(e))
|
||||
except OpenActionNeeded as e:
|
||||
if e.only_once_id not in self.open_feedback_only_once_seen:
|
||||
self.open_feedback_only_once_seen.add(e.only_once_id)
|
||||
self.open_feedback_msg(e.device_name, e)
|
||||
except:
|
||||
prints('Error while trying to open %s (Driver: %s)'%
|
||||
(cd, dev))
|
||||
@ -875,6 +880,7 @@ class DeviceSignals(QObject): # {{{
|
||||
#: otherwise a disconnection.
|
||||
device_connection_changed = pyqtSignal(object)
|
||||
|
||||
|
||||
device_signals = DeviceSignals()
|
||||
# }}}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user