summaryrefslogtreecommitdiff
path: root/external/plyer/platforms/android
diff options
context:
space:
mode:
Diffstat (limited to 'external/plyer/platforms/android')
-rw-r--r--external/plyer/platforms/android/__init__.py12
-rw-r--r--external/plyer/platforms/android/accelerometer.py74
-rw-r--r--external/plyer/platforms/android/audio.py58
-rw-r--r--external/plyer/platforms/android/battery.py34
-rw-r--r--external/plyer/platforms/android/camera.py59
-rw-r--r--external/plyer/platforms/android/compass.py74
-rw-r--r--external/plyer/platforms/android/email.py40
-rw-r--r--external/plyer/platforms/android/gps.py79
-rw-r--r--external/plyer/platforms/android/gyroscope.py74
-rw-r--r--external/plyer/platforms/android/irblaster.py54
-rw-r--r--external/plyer/platforms/android/notification.py37
-rw-r--r--external/plyer/platforms/android/orientation.py43
-rw-r--r--external/plyer/platforms/android/sms.py25
-rw-r--r--external/plyer/platforms/android/tts.py24
-rw-r--r--external/plyer/platforms/android/uniqueid.py16
-rw-r--r--external/plyer/platforms/android/vibrator.py48
16 files changed, 751 insertions, 0 deletions
diff --git a/external/plyer/platforms/android/__init__.py b/external/plyer/platforms/android/__init__.py
new file mode 100644
index 0000000..6b565a3
--- /dev/null
+++ b/external/plyer/platforms/android/__init__.py
@@ -0,0 +1,12 @@
+from os import environ
+from jnius import autoclass
+
+ANDROID_VERSION = autoclass('android.os.Build$VERSION')
+SDK_INT = ANDROID_VERSION.SDK_INT
+
+if 'PYTHON_SERVICE_ARGUMENT' in environ:
+ PythonService = autoclass('org.renpy.android.PythonService')
+ activity = PythonService.mService
+else:
+ PythonActivity = autoclass('org.renpy.android.PythonActivity')
+ activity = PythonActivity.mActivity
diff --git a/external/plyer/platforms/android/accelerometer.py b/external/plyer/platforms/android/accelerometer.py
new file mode 100644
index 0000000..af07c52
--- /dev/null
+++ b/external/plyer/platforms/android/accelerometer.py
@@ -0,0 +1,74 @@
+'''
+Android accelerometer
+---------------------
+'''
+
+from plyer.facades import Accelerometer
+from jnius import PythonJavaClass, java_method, autoclass, cast
+from plyer.platforms.android import activity
+
+Context = autoclass('android.content.Context')
+Sensor = autoclass('android.hardware.Sensor')
+SensorManager = autoclass('android.hardware.SensorManager')
+
+
+class AccelerometerSensorListener(PythonJavaClass):
+ __javainterfaces__ = ['android/hardware/SensorEventListener']
+
+ def __init__(self):
+ super(AccelerometerSensorListener, self).__init__()
+ self.SensorManager = cast('android.hardware.SensorManager',
+ activity.getSystemService(Context.SENSOR_SERVICE))
+ self.sensor = self.SensorManager.getDefaultSensor(
+ Sensor.TYPE_ACCELEROMETER)
+
+ self.values = [None, None, None]
+
+ def enable(self):
+ self.SensorManager.registerListener(self, self.sensor,
+ SensorManager.SENSOR_DELAY_NORMAL)
+
+ def disable(self):
+ self.SensorManager.unregisterListener(self, self.sensor)
+
+ @java_method('(Landroid/hardware/SensorEvent;)V')
+ def onSensorChanged(self, event):
+ self.values = event.values[:3]
+
+ @java_method('(Landroid/hardware/Sensor;I)V')
+ def onAccuracyChanged(self, sensor, accuracy):
+ # Maybe, do something in future?
+ pass
+
+
+class AndroidAccelerometer(Accelerometer):
+ def __init__(self):
+ super(AndroidAccelerometer, self).__init__()
+ self.bState = False
+
+ def _enable(self):
+ if (not self.bState):
+ self.listener = AccelerometerSensorListener()
+ self.listener.enable()
+ self.bState = True
+
+ def _disable(self):
+ if (self.bState):
+ self.bState = False
+ self.listener.disable()
+ del self.listener
+
+ def _get_acceleration(self):
+ if (self.bState):
+ return tuple(self.listener.values)
+ else:
+ return (None, None, None)
+
+ def __del__(self):
+ if(self.bState):
+ self._disable()
+ super(self.__class__, self).__del__()
+
+
+def instance():
+ return AndroidAccelerometer()
diff --git a/external/plyer/platforms/android/audio.py b/external/plyer/platforms/android/audio.py
new file mode 100644
index 0000000..2115f19
--- /dev/null
+++ b/external/plyer/platforms/android/audio.py
@@ -0,0 +1,58 @@
+from jnius import autoclass
+
+from plyer.facades.audio import Audio
+
+# Recorder Classes
+MediaRecorder = autoclass('android.media.MediaRecorder')
+AudioSource = autoclass('android.media.MediaRecorder$AudioSource')
+OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')
+AudioEncoder = autoclass('android.media.MediaRecorder$AudioEncoder')
+
+# Player Classes
+MediaPlayer = autoclass('android.media.MediaPlayer')
+
+
+class AndroidAudio(Audio):
+ '''Audio for android.
+
+ For recording audio we use MediaRecorder Android class.
+ For playing audio we use MediaPlayer Android class.
+ '''
+
+ def __init__(self, file_path=None):
+ default_path = '/sdcard/testrecorder.3gp'
+ super(AndroidAudio, self).__init__(file_path or default_path)
+
+ self._recorder = None
+ self._player = None
+
+ def _start(self):
+ self._recorder = MediaRecorder()
+ self._recorder.setAudioSource(AudioSource.DEFAULT)
+ self._recorder.setOutputFormat(OutputFormat.DEFAULT)
+ self._recorder.setAudioEncoder(AudioEncoder.DEFAULT)
+ self._recorder.setOutputFile(self.file_path)
+
+ self._recorder.prepare()
+ self._recorder.start()
+
+ def _stop(self):
+ if self._recorder:
+ self._recorder.stop()
+ self._recorder.release()
+ self._recorder = None
+
+ if self._player:
+ self._player.stop()
+ self._player.release()
+ self._player = None
+
+ def _play(self):
+ self._player = MediaPlayer()
+ self._player.setDataSource(self.file_path)
+ self._player.prepare()
+ self._player.start()
+
+
+def instance():
+ return AndroidAudio()
diff --git a/external/plyer/platforms/android/battery.py b/external/plyer/platforms/android/battery.py
new file mode 100644
index 0000000..2ade1d2
--- /dev/null
+++ b/external/plyer/platforms/android/battery.py
@@ -0,0 +1,34 @@
+from jnius import autoclass, cast
+from plyer.platforms.android import activity
+from plyer.facades import Battery
+
+Intent = autoclass('android.content.Intent')
+BatteryManager = autoclass('android.os.BatteryManager')
+IntentFilter = autoclass('android.content.IntentFilter')
+
+
+class AndroidBattery(Battery):
+ def _get_state(self):
+ status = {"isCharging": None, "percentage": None}
+
+ ifilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
+
+ batteryStatus = cast('android.content.Intent',
+ activity.registerReceiver(None, ifilter))
+
+ query = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
+ isCharging = (query == BatteryManager.BATTERY_STATUS_CHARGING or
+ query == BatteryManager.BATTERY_STATUS_FULL)
+
+ level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
+ scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
+ percentage = level / float(scale)
+
+ status['isCharging'] = isCharging
+ status['percentage'] = percentage
+
+ return status
+
+
+def instance():
+ return AndroidBattery()
diff --git a/external/plyer/platforms/android/camera.py b/external/plyer/platforms/android/camera.py
new file mode 100644
index 0000000..344296d
--- /dev/null
+++ b/external/plyer/platforms/android/camera.py
@@ -0,0 +1,59 @@
+import android
+import android.activity
+from os import unlink
+from jnius import autoclass, cast
+from plyer.facades import Camera
+from plyer.platforms.android import activity
+
+Intent = autoclass('android.content.Intent')
+PythonActivity = autoclass('org.renpy.android.PythonActivity')
+MediaStore = autoclass('android.provider.MediaStore')
+Uri = autoclass('android.net.Uri')
+
+
+class AndroidCamera(Camera):
+
+ def _take_picture(self, on_complete, filename=None):
+ assert(on_complete is not None)
+ self.on_complete = on_complete
+ self.filename = filename
+ android.activity.unbind(on_activity_result=self._on_activity_result)
+ android.activity.bind(on_activity_result=self._on_activity_result)
+ intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+ uri = Uri.parse('file://' + filename)
+ parcelable = cast('android.os.Parcelable', uri)
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, parcelable)
+ activity.startActivityForResult(intent, 0x123)
+
+ def _take_video(self, on_complete, filename=None):
+ assert(on_complete is not None)
+ self.on_complete = on_complete
+ self.filename = filename
+ android.activity.unbind(on_activity_result=self._on_activity_result)
+ android.activity.bind(on_activity_result=self._on_activity_result)
+ intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
+ uri = Uri.parse('file://' + filename)
+ parcelable = cast('android.os.Parcelable', uri)
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, parcelable)
+
+ # 0 = low quality, suitable for MMS messages,
+ # 1 = high quality
+ intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
+ activity.startActivityForResult(intent, 0x123)
+
+ def _on_activity_result(self, requestCode, resultCode, intent):
+ if requestCode != 0x123:
+ return
+ android.activity.unbind(on_activity_result=self._on_activity_result)
+ if self.on_complete(self.filename):
+ self._unlink(self.filename)
+
+ def _unlink(self, fn):
+ try:
+ unlink(fn)
+ except:
+ pass
+
+
+def instance():
+ return AndroidCamera()
diff --git a/external/plyer/platforms/android/compass.py b/external/plyer/platforms/android/compass.py
new file mode 100644
index 0000000..7fb19d6
--- /dev/null
+++ b/external/plyer/platforms/android/compass.py
@@ -0,0 +1,74 @@
+'''
+Android Compass
+---------------------
+'''
+
+from plyer.facades import Compass
+from jnius import PythonJavaClass, java_method, autoclass, cast
+from plyer.platforms.android import activity
+
+Context = autoclass('android.content.Context')
+Sensor = autoclass('android.hardware.Sensor')
+SensorManager = autoclass('android.hardware.SensorManager')
+
+
+class MagneticFieldSensorListener(PythonJavaClass):
+ __javainterfaces__ = ['android/hardware/SensorEventListener']
+
+ def __init__(self):
+ super(MagneticFieldSensorListener, self).__init__()
+ self.SensorManager = cast('android.hardware.SensorManager',
+ activity.getSystemService(Context.SENSOR_SERVICE))
+ self.sensor = self.SensorManager.getDefaultSensor(
+ Sensor.TYPE_MAGNETIC_FIELD)
+
+ self.values = [None, None, None]
+
+ def enable(self):
+ self.SensorManager.registerListener(self, self.sensor,
+ SensorManager.SENSOR_DELAY_NORMAL)
+
+ def disable(self):
+ self.SensorManager.unregisterListener(self, self.sensor)
+
+ @java_method('(Landroid/hardware/SensorEvent;)V')
+ def onSensorChanged(self, event):
+ self.values = event.values[:3]
+
+ @java_method('(Landroid/hardware/Sensor;I)V')
+ def onAccuracyChanged(self, sensor, accuracy):
+ # Maybe, do something in future?
+ pass
+
+
+class AndroidCompass(Compass):
+ def __init__(self):
+ super(AndroidCompass, self).__init__()
+ self.bState = False
+
+ def _enable(self):
+ if (not self.bState):
+ self.listener = MagneticFieldSensorListener()
+ self.listener.enable()
+ self.bState = True
+
+ def _disable(self):
+ if (self.bState):
+ self.bState = False
+ self.listener.disable()
+ del self.listener
+
+ def _get_orientation(self):
+ if (self.bState):
+ return tuple(self.listener.values)
+ else:
+ return (None, None, None)
+
+ def __del__(self):
+ if(self.bState):
+ self._disable()
+ super(self.__class__, self).__del__()
+
+
+def instance():
+ return AndroidCompass()
diff --git a/external/plyer/platforms/android/email.py b/external/plyer/platforms/android/email.py
new file mode 100644
index 0000000..79923e4
--- /dev/null
+++ b/external/plyer/platforms/android/email.py
@@ -0,0 +1,40 @@
+from jnius import autoclass, cast
+from plyer.facades import Email
+from plyer.platforms.android import activity
+
+Intent = autoclass('android.content.Intent')
+AndroidString = autoclass('java.lang.String')
+
+
+class AndroidEmail(Email):
+ def _send(self, **kwargs):
+ intent = Intent(Intent.ACTION_SEND)
+ intent.setType('text/plain')
+
+ recipient = kwargs.get('recipient')
+ subject = kwargs.get('subject')
+ text = kwargs.get('text')
+ create_chooser = kwargs.get('create_chooser')
+
+ if recipient:
+ intent.putExtra(Intent.EXTRA_EMAIL, [recipient])
+ if subject:
+ android_subject = cast('java.lang.CharSequence',
+ AndroidString(subject))
+ intent.putExtra(Intent.EXTRA_SUBJECT, android_subject)
+ if text:
+ android_text = cast('java.lang.CharSequence',
+ AndroidString(text))
+ intent.putExtra(Intent.EXTRA_TEXT, android_text)
+
+ if create_chooser:
+ chooser_title = cast('java.lang.CharSequence',
+ AndroidString('Send message with:'))
+ activity.startActivity(Intent.createChooser(intent,
+ chooser_title))
+ else:
+ activity.startActivity(intent)
+
+
+def instance():
+ return AndroidEmail()
diff --git a/external/plyer/platforms/android/gps.py b/external/plyer/platforms/android/gps.py
new file mode 100644
index 0000000..fbe580f
--- /dev/null
+++ b/external/plyer/platforms/android/gps.py
@@ -0,0 +1,79 @@
+'''
+Android GPS
+-----------
+'''
+
+from plyer.facades import GPS
+from plyer.platforms.android import activity
+from jnius import autoclass, java_method, PythonJavaClass
+
+Looper = autoclass('android.os.Looper')
+LocationManager = autoclass('android.location.LocationManager')
+Context = autoclass('android.content.Context')
+
+
+class _LocationListener(PythonJavaClass):
+ __javainterfaces__ = ['android/location/LocationListener']
+
+ def __init__(self, root):
+ self.root = root
+ super(_LocationListener, self).__init__()
+
+ @java_method('(Landroid/location/Location;)V')
+ def onLocationChanged(self, location):
+ self.root.on_location(
+ lat=location.getLatitude(),
+ lon=location.getLongitude(),
+ speed=location.getSpeed(),
+ bearing=location.getBearing(),
+ altitude=location.getAltitude())
+
+ @java_method('(Ljava/lang/String;)V')
+ def onProviderEnabled(self, status):
+ if self.root.on_status:
+ self.root.on_status('provider-enabled', status)
+
+ @java_method('(Ljava/lang/String;)V')
+ def onProviderDisabled(self, status):
+ if self.root.on_status:
+ self.root.on_status('provider-disabled', status)
+
+ @java_method('(Ljava/lang/String;ILandroid/os/Bundle;)V')
+ def onStatusChanged(self, provider, status, extras):
+ if self.root.on_status:
+ s_status = 'unknown'
+ if status == 0x00:
+ s_status = 'out-of-service'
+ elif status == 0x01:
+ s_status = 'temporarily-unavailable'
+ elif status == 0x02:
+ s_status = 'available'
+ self.root.on_status('provider-status', '{}: {}'.format(
+ provider, s_status))
+
+
+class AndroidGPS(GPS):
+
+ def _configure(self):
+ if not hasattr(self, '_location_manager'):
+ self._location_manager = activity.getSystemService(
+ Context.LOCATION_SERVICE)
+ self._location_listener = _LocationListener(self)
+
+ def _start(self):
+ # XXX defaults should be configurable by the user, later
+ providers = self._location_manager.getProviders(False).toArray()
+ for provider in providers:
+ self._location_manager.requestLocationUpdates(
+ provider,
+ 1000, # minTime, in milliseconds
+ 1, # minDistance, in meters
+ self._location_listener,
+ Looper.getMainLooper())
+
+ def _stop(self):
+ self._location_manager.removeUpdates(self._location_listener)
+
+
+def instance():
+ return AndroidGPS()
diff --git a/external/plyer/platforms/android/gyroscope.py b/external/plyer/platforms/android/gyroscope.py
new file mode 100644
index 0000000..58747d7
--- /dev/null
+++ b/external/plyer/platforms/android/gyroscope.py
@@ -0,0 +1,74 @@
+'''
+Android Gyroscope
+---------------------
+'''
+
+from plyer.facades import Gyroscope
+from jnius import PythonJavaClass, java_method, autoclass, cast
+from plyer.platforms.android import activity
+
+Context = autoclass('android.content.Context')
+Sensor = autoclass('android.hardware.Sensor')
+SensorManager = autoclass('android.hardware.SensorManager')
+
+
+class GyroscopeSensorListener(PythonJavaClass):
+ __javainterfaces__ = ['android/hardware/SensorEventListener']
+
+ def __init__(self):
+ super(GyroscopeSensorListener, self).__init__()
+ self.SensorManager = cast('android.hardware.SensorManager',
+ activity.getSystemService(Context.SENSOR_SERVICE))
+ self.sensor = self.SensorManager.getDefaultSensor(
+ Sensor.TYPE_GYROSCOPE)
+
+ self.values = [None, None, None]
+
+ def enable(self):
+ self.SensorManager.registerListener(self, self.sensor,
+ SensorManager.SENSOR_DELAY_NORMAL)
+
+ def disable(self):
+ self.SensorManager.unregisterListener(self, self.sensor)
+
+ @java_method('(Landroid/hardware/SensorEvent;)V')
+ def onSensorChanged(self, event):
+ self.values = event.values[:3]
+
+ @java_method('(Landroid/hardware/Sensor;I)V')
+ def onAccuracyChanged(self, sensor, accuracy):
+ # Maybe, do something in future?
+ pass
+
+
+class AndroidGyroscope(Gyroscope):
+ def __init__(self):
+ super(AndroidGyroscope, self).__init__()
+ self.bState = False
+
+ def _enable(self):
+ if (not self.bState):
+ self.listener = GyroscopeSensorListener()
+ self.listener.enable()
+ self.bState = True
+
+ def _disable(self):
+ if (self.bState):
+ self.bState = False
+ self.listener.disable()
+ del self.listener
+
+ def _get_orientation(self):
+ if (self.bState):
+ return tuple(self.listener.values)
+ else:
+ return (None, None, None)
+
+ def __del__(self):
+ if(self.bState):
+ self._disable()
+ super(self.__class__, self).__del__()
+
+
+def instance():
+ return AndroidGyroscope()
diff --git a/external/plyer/platforms/android/irblaster.py b/external/plyer/platforms/android/irblaster.py
new file mode 100644
index 0000000..6c44717
--- /dev/null
+++ b/external/plyer/platforms/android/irblaster.py
@@ -0,0 +1,54 @@
+from jnius import autoclass
+
+from plyer.facades import IrBlaster
+from plyer.platforms.android import activity, SDK_INT, ANDROID_VERSION
+
+if SDK_INT >= 19:
+ Context = autoclass('android.content.Context')
+ ir_manager = activity.getSystemService(Context.CONSUMER_IR_SERVICE)
+else:
+ ir_manager = None
+
+
+class AndroidIrBlaster(IrBlaster):
+ def _exists(self):
+ if ir_manager and ir_manager.hasIrEmitter():
+ return True
+ return False
+
+ @property
+ def multiply_pulse(self):
+ '''Android 4.4.3+ uses microseconds instead of period counts
+ '''
+ return not (SDK_INT == 19 and
+ int(str(ANDROID_VERSION.RELEASE).rsplit('.', 1)[-1]) < 3)
+
+ def _get_frequencies(self):
+ if not ir_manager:
+ return None
+
+ if hasattr(self, '_frequencies'):
+ return self._frequencies
+
+ ir_frequencies = ir_manager.getCarrierFrequencies()
+ if not ir_frequencies:
+ return []
+
+ frequencies = []
+ for freqrange in ir_frequencies:
+ freq = (freqrange.getMinFrequency(), freqrange.getMaxFrequency())
+ frequencies.append(freq)
+
+ self._frequencies = frequencies
+ return frequencies
+
+ def _transmit(self, frequency, pattern, mode):
+ if self.multiply_pulse and mode == 'period':
+ pattern = self.periods_to_microseconds(frequency, pattern)
+ elif not self.multiply_pulse and mode == 'microseconds':
+ pattern = self.microseconds_to_periods(frequency, pattern)
+ ir_manager.transmit(frequency, pattern)
+
+
+def instance():
+ return AndroidIrBlaster()
diff --git a/external/plyer/platforms/android/notification.py b/external/plyer/platforms/android/notification.py
new file mode 100644
index 0000000..bfc3a25
--- /dev/null
+++ b/external/plyer/platforms/android/notification.py
@@ -0,0 +1,37 @@
+from jnius import autoclass
+from plyer.facades import Notification
+from plyer.platforms.android import activity, SDK_INT
+
+AndroidString = autoclass('java.lang.String')
+Context = autoclass('android.content.Context')
+NotificationBuilder = autoclass('android.app.Notification$Builder')
+Drawable = autoclass("{}.R$drawable".format(activity.getPackageName()))
+
+
+class AndroidNotification(Notification):
+ def _get_notification_service(self):
+ if not hasattr(self, '_ns'):
+ self._ns = activity.getSystemService(Context.NOTIFICATION_SERVICE)
+ return self._ns
+
+ def _notify(self, **kwargs):
+ icon = getattr(Drawable, kwargs.get('icon_android', 'icon'))
+ noti = NotificationBuilder(activity)
+ noti.setContentTitle(AndroidString(
+ kwargs.get('title').encode('utf-8')))
+ noti.setContentText(AndroidString(
+ kwargs.get('message').encode('utf-8')))
+ noti.setSmallIcon(icon)
+ noti.setAutoCancel(True)
+
+ if SDK_INT >= 16:
+ noti = noti.build()
+ else:
+ noti = noti.getNotification()
+
+ self._get_notification_service().notify(0, noti)
+
+
+def instance():
+ return AndroidNotification()
+
diff --git a/external/plyer/platforms/android/orientation.py b/external/plyer/platforms/android/orientation.py
new file mode 100644
index 0000000..e98e34d
--- /dev/null
+++ b/external/plyer/platforms/android/orientation.py
@@ -0,0 +1,43 @@
+from jnius import autoclass, cast
+from plyer.platforms.android import activity
+from plyer.facades import Orientation
+
+ActivityInfo = autoclass('android.content.pm.ActivityInfo')
+
+
+class AndroidOrientation(Orientation):
+
+ def _set_landscape(self, **kwargs):
+ reverse = kwargs.get('reverse')
+ if reverse:
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE)
+ else:
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+
+ def _set_portrait(self, **kwargs):
+ reverse = kwargs.get('reverse')
+ if reverse:
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT)
+ else:
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+
+ def _set_sensor(self, **kwargs):
+ mode = kwargs.get('mode')
+
+ if mode == 'any':
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_SENSOR)
+ elif mode == 'landscape':
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE)
+ elif mode == 'portrait':
+ activity.setRequestedOrientation(
+ ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
+
+
+def instance():
+ return AndroidOrientation()
diff --git a/external/plyer/platforms/android/sms.py b/external/plyer/platforms/android/sms.py
new file mode 100644
index 0000000..8650968
--- /dev/null
+++ b/external/plyer/platforms/android/sms.py
@@ -0,0 +1,25 @@
+'''
+Android SMS
+-----------
+'''
+
+from jnius import autoclass
+from plyer.facades import Sms
+
+SmsManager = autoclass('android.telephony.SmsManager')
+
+
+class AndroidSms(Sms):
+
+ def _send(self, **kwargs):
+ sms = SmsManager.getDefault()
+
+ recipient = kwargs.get('recipient')
+ message = kwargs.get('message')
+
+ if sms:
+ sms.sendTextMessage(recipient, None, message, None, None)
+
+
+def instance():
+ return AndroidSms()
diff --git a/external/plyer/platforms/android/tts.py b/external/plyer/platforms/android/tts.py
new file mode 100644
index 0000000..eae2974
--- /dev/null
+++ b/external/plyer/platforms/android/tts.py
@@ -0,0 +1,24 @@
+from time import sleep
+from jnius import autoclass
+from plyer.facades import TTS
+from plyer.platforms.android import activity
+
+Locale = autoclass('java.util.Locale')
+TextToSpeech = autoclass('android.speech.tts.TextToSpeech')
+
+
+class AndroidTextToSpeech(TTS):
+ def _speak(self, **kwargs):
+ tts = TextToSpeech(activity, None)
+ tts.setLanguage(Locale.US) # TODO: locale specification as option
+ retries = 0 # First try rarely succeeds due to some timing issue
+ while retries < 100 and \
+ tts.speak(kwargs.get('message').encode('utf-8'),
+ TextToSpeech.QUEUE_FLUSH, None) == -1:
+ # -1 indicates error. Let's wait and then try again
+ sleep(0.1)
+ retries += 1
+
+
+def instance():
+ return AndroidTextToSpeech()
diff --git a/external/plyer/platforms/android/uniqueid.py b/external/plyer/platforms/android/uniqueid.py
new file mode 100644
index 0000000..b8561de
--- /dev/null
+++ b/external/plyer/platforms/android/uniqueid.py
@@ -0,0 +1,16 @@
+from jnius import autoclass
+from plyer.platforms.android import activity
+from plyer.facades import UniqueID
+
+Secure = autoclass('android.provider.Settings$Secure')
+
+
+class AndroidUniqueID(UniqueID):
+
+ def _get_uid(self):
+ return Secure.getString(activity.getContentResolver(),
+ Secure.ANDROID_ID)
+
+
+def instance():
+ return AndroidUniqueID()
diff --git a/external/plyer/platforms/android/vibrator.py b/external/plyer/platforms/android/vibrator.py
new file mode 100644
index 0000000..c28fe8e
--- /dev/null
+++ b/external/plyer/platforms/android/vibrator.py
@@ -0,0 +1,48 @@
+'''Implementation Vibrator for Android.'''
+
+from jnius import autoclass
+from plyer.facades import Vibrator
+from plyer.platforms.android import activity
+from plyer.platforms.android import SDK_INT
+
+Context = autoclass('android.content.Context')
+vibrator = activity.getSystemService(Context.VIBRATOR_SERVICE)
+
+
+class AndroidVibrator(Vibrator):
+ '''Android Vibrator class.
+
+ Supported features:
+ * vibrate for some period of time.
+ * vibrate from given pattern.
+ * cancel vibration.
+ * check whether Vibrator exists.
+ '''
+
+ def _vibrate(self, time=None, **kwargs):
+ if vibrator:
+ vibrator.vibrate(int(1000 * time))
+
+ def _pattern(self, pattern=None, repeat=None, **kwargs):
+ pattern = [int(1000 * time) for time in pattern]
+
+ if vibrator:
+ vibrator.vibrate(pattern, repeat)
+
+ def _exists(self, **kwargs):
+ if SDK_INT >= 11:
+ return vibrator.hasVibrator()
+ elif activity.getSystemService(Context.VIBRATOR_SERVICE) is None:
+ raise NotImplementedError()
+ return True
+
+ def _cancel(self, **kwargs):
+ vibrator.cancel()
+
+
+def instance():
+ '''Returns Vibrator with android features.
+
+ :return: instance of class AndroidVibrator
+ '''
+ return AndroidVibrator()