From 0906dc9e4a2fa4efd6225c61910bba58922e5262 Mon Sep 17 00:00:00 2001 From: livecodesam Date: Fri, 22 Jun 2018 12:54:32 +0100 Subject: [PATCH 01/46] [Dictionary] Changes from mobileGetLocationHistory to mobileStartTrackingSensor --- docs/dictionary/command/mobilePickMedia.lcdoc | 8 +- docs/dictionary/command/mobilePickPhoto.lcdoc | 14 ++-- .../command/mobilePlaySoundOnChannel.lcdoc | 2 - .../mobileSetLocationHistoryLimit.lcdoc | 20 +++-- .../command/mobileStartTrackingSensor.lcdoc | 4 +- .../function/mobileGetLocationHistory.lcdoc | 75 +++++++------------ .../function/mobileOrientation.lcdoc | 3 +- .../function/mobilePixelDensity.lcdoc | 4 +- .../function/mobilePreferredLanguages.lcdoc | 5 +- .../function/mobileSoundChannelStatus.lcdoc | 2 +- 10 files changed, 56 insertions(+), 81 deletions(-) diff --git a/docs/dictionary/command/mobilePickMedia.lcdoc b/docs/dictionary/command/mobilePickMedia.lcdoc index 0306ecb4163..9f0852ab55f 100644 --- a/docs/dictionary/command/mobilePickMedia.lcdoc +++ b/docs/dictionary/command/mobilePickMedia.lcdoc @@ -76,15 +76,17 @@ to select multiple items on iOS, the user has to select the Done button, once all of the selections have been made. The remaining arguments specify the type of media items the user should -> be allowed to select from the iPod library. On Android, it is not -> necessary to specify any arguments. The application that is launched -> is in control of the audio media types that are to be selected. +be allowed to select from the iPod library. On Android, it is not +necessary to specify any arguments. The application that is launched +is in control of the audio media types that are to be selected. >*Note:* does not return anything for m4p files or > iCloud files that are not physically on the device, even if they are > displayed in the picker itself. + >*Note:* On iOS, returns references to the iTunes data > store on the iOS device. These media references can only be played > with the command. + >*Note:* is not available on the iOS simulator. References: mobilePlaySoundOnChannel (command), mobilePick (command), diff --git a/docs/dictionary/command/mobilePickPhoto.lcdoc b/docs/dictionary/command/mobilePickPhoto.lcdoc index 5bfe65a855b..636c0e415ca 100644 --- a/docs/dictionary/command/mobilePickPhoto.lcdoc +++ b/docs/dictionary/command/mobilePickPhoto.lcdoc @@ -23,15 +23,13 @@ mobilePickPhoto "front camera", 250, 250 Parameters: source (enum): -The source for the image. One of: +The source for the image. -- "library" -- "album" -- "camera" - - -- "rear camera": iOS only -- "front camera": iOS only +- "library": +- "album": +- "camera": +- "rear camera": iOS only +- "front camera": iOS only maxwidth: diff --git a/docs/dictionary/command/mobilePlaySoundOnChannel.lcdoc b/docs/dictionary/command/mobilePlaySoundOnChannel.lcdoc index 5b108ba4c66..c27b7814e4c 100644 --- a/docs/dictionary/command/mobilePlaySoundOnChannel.lcdoc +++ b/docs/dictionary/command/mobilePlaySoundOnChannel.lcdoc @@ -33,8 +33,6 @@ channel: The name of the channel to play the sound on. type (enum): -One of: - - "now": The sound is played immediately, replacing any current sound (and queued sound) on the channel. - "next": The sound is queued to play immediately after the current diff --git a/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc b/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc index e438f18cf29..0649d21d193 100644 --- a/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc +++ b/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc @@ -57,21 +57,19 @@ sample provided with the event (which will always be the last sample in the history). e.g. on locationChanged - - local tHistory - put mobileGetLocationHistory() into tHistory - repeat for each element tSample in tHistory - - processLocationChanged tSample - - end repeat + local tHistory + put mobileGetLocationHistory() into tHistory + repeat for each element tSample in tHistory + processLocationChanged tSample + end repeat end locationChanged References: mobileStopTrackingSensor (command), -mobileStartTrackingSensor (command), mobileGetLocationHistory (function), +mobileStartTrackingSensor (command), function (control structure), +mobileGetLocationHistory (function), mobileGetLocationHistoryLimit (function), mobileSensorAvailable (function), mobileSensorReading (function), -mobileLocationAuthorizationStatus (function), locationChanged (message), -trackingError (message) +mobileLocationAuthorizationStatus (function), array (glossary), +locationChanged (message), trackingError (message) diff --git a/docs/dictionary/command/mobileStartTrackingSensor.lcdoc b/docs/dictionary/command/mobileStartTrackingSensor.lcdoc index dab95fc0c77..3137ccfea4d 100644 --- a/docs/dictionary/command/mobileStartTrackingSensor.lcdoc +++ b/docs/dictionary/command/mobileStartTrackingSensor.lcdoc @@ -33,9 +33,9 @@ loosely (enum): How accurate the readings from sensors should be. The default value is false -- "true": readings are determined without using accurate(but power +- "true": readings are determined without using accurate (but power consuming) sources such as GPS. -- "false": readings are determined using accurate(but power consuming) +- "false": readings are determined using accurate (but power consuming) sources such as GPS. diff --git a/docs/dictionary/function/mobileGetLocationHistory.lcdoc b/docs/dictionary/function/mobileGetLocationHistory.lcdoc index 16c27d2a1db..95af899270e 100644 --- a/docs/dictionary/function/mobileGetLocationHistory.lcdoc +++ b/docs/dictionary/function/mobileGetLocationHistory.lcdoc @@ -19,51 +19,31 @@ local tHistory put mobileGetLocationHistory() into tHistory Returns (array): -A numerically keyed of all accumulated samples +A numerically keyed, nested of all accumulated samples since the last time it was called with lower indices being older -samples. Calling the function clears the internal history. The default -history limit is 1 - meaning that only one sample is ever kept at a +samples. Each index of the has the following keys: + - "horizontal accuracy": the maximum error in meters of the +position indicated by longitude and latitude + - "latitude": the latitude of the current location, measured in degrees +relative to the equator. Positive values indicate positions in the +Northern Hemisphere, negative values in the Southern. + - "longitude": the longitude of the current location, measured in +degrees relative to the zero meridian. Positive values extend east +of the meridian, negative values extend west. + - "altitude": the distance in meters of the height of the device +relative to sea level. Positive values extend upward of sea level, +negative values downward. + - "timestamp": the time at which the measurement was taken, in +seconds since 1970. + +Calling the function clears the internal history. The default +history limit is 1, meaning that only one sample is ever kept at a time. If an application wants historical access to all samples, then it should set the location history limit using the - to the maximum number of + to the maximum number of samples it ever wants to record, or 0 to record the entire history (between calls to ). -{ - -- (integer) : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- : -- (real) : -- : -- : -- : - -} - Description: System events may occur more frequently than the @@ -82,14 +62,11 @@ sample provided with the event (which will always be the last sample in the history). e.g. on locationChanged - - local tHistory - put mobileGetLocationHistory() into tHistory - repeat for each element tSample in tHistory - - processLocationChanged tSample - - end repeat + local tHistory + put mobileGetLocationHistory() into tHistory + repeat for each element tSample in tHistory + processLocationChanged tSample + end repeat end locationChanged @@ -97,6 +74,6 @@ References: mobileSetLocationHistoryLimit (command), mobileStopTrackingSensor (command), mobileStartTrackingSensor (command), mobileGetLocationHistoryLimit (function), mobileSensorAvailable (function), mobileSensorReading (function), -mobileLocationAuthorizationStatus (function), locationChanged (message), -trackingError (message) +mobileLocationAuthorizationStatus (function), array (glossary), +locationChanged (message), trackingError (message) diff --git a/docs/dictionary/function/mobileOrientation.lcdoc b/docs/dictionary/function/mobileOrientation.lcdoc index 40a138ae97d..b66653f0287 100644 --- a/docs/dictionary/function/mobileOrientation.lcdoc +++ b/docs/dictionary/function/mobileOrientation.lcdoc @@ -19,8 +19,7 @@ Example: put mobileOrientation() into theInterfaceOrientation Returns (enum): -The function returns one of - +The function returns a string value. - portrait: the device is being held upward with the home button at the bottom - portrait upside down: the device is being held upward with the home diff --git a/docs/dictionary/function/mobilePixelDensity.lcdoc b/docs/dictionary/function/mobilePixelDensity.lcdoc index e7d06bdea33..002e78e1837 100644 --- a/docs/dictionary/function/mobilePixelDensity.lcdoc +++ b/docs/dictionary/function/mobilePixelDensity.lcdoc @@ -32,8 +32,8 @@ density on Android. The function returns the scale of the device screen (relative to a non-Retinal display on iOS), this is 2 on a retina -display and 1 otherwise. On Android this function return the Display -Metrics. +display and 1 otherwise. On Android this function returns the display +metrics. References: iphoneUseDeviceResolution (command), iphoneDeviceScale (function), iphoneDeviceResolution (function) diff --git a/docs/dictionary/function/mobilePreferredLanguages.lcdoc b/docs/dictionary/function/mobilePreferredLanguages.lcdoc index dbc864ce44d..e09b04f3254 100644 --- a/docs/dictionary/function/mobilePreferredLanguages.lcdoc +++ b/docs/dictionary/function/mobilePreferredLanguages.lcdoc @@ -23,9 +23,12 @@ answer "The user prefers" && line 1 of tLanguages Returns: The function returns a list of language tags in order of user preference, highest first, one per line. For example: + EN + FR -DE. + +DE Description: Use to get a list of preferred user diff --git a/docs/dictionary/function/mobileSoundChannelStatus.lcdoc b/docs/dictionary/function/mobileSoundChannelStatus.lcdoc index 8638ea77fa8..bab87b21f92 100644 --- a/docs/dictionary/function/mobileSoundChannelStatus.lcdoc +++ b/docs/dictionary/function/mobileSoundChannelStatus.lcdoc @@ -22,7 +22,7 @@ Example: put mobileSoundChannelStatus() into tChannelStatus Returns (enum): -The function returns one of: +The function returns a string value. - stopped: there is no sound currently playing, nor any sound scheduled to be playing From 0a2e4a674f3d2f70e5f485b26151b089e1f5f82a Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Fri, 20 Jul 2018 10:12:28 +1000 Subject: [PATCH 02/46] [[ Bug 21434 ]] Force bitmap view visible for visual effects This patch fixes a regresion from a previous patch that changed the behavior of the `showBitmapView` method to only set the visibility of `m_bitmap_view` to visible if the OpenGL view is not visible. This interfered with visual effects as they uset the bitmap view rather than OpenGL view. --- docs/notes/bugfix-21434.md | 1 + engine/src/java/com/runrev/android/Engine.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 docs/notes/bugfix-21434.md diff --git a/docs/notes/bugfix-21434.md b/docs/notes/bugfix-21434.md new file mode 100644 index 00000000000..e41919685a4 --- /dev/null +++ b/docs/notes/bugfix-21434.md @@ -0,0 +1 @@ +# Fix visual effects not working when acceleratedRendering is true on Android \ No newline at end of file diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index bc22d9fe676..af01d4297d1 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -2251,7 +2251,8 @@ public void run() { public void showBitmapView() { - ensureBitmapViewVisibility(); + // force visible for visual effects + m_bitmap_view.setVisibility(View.VISIBLE); } //////////////////////////////////////////////////////////////////////////////// From 5264d8696a397db869c2f368a02d90e8a65714e0 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Thu, 26 Jul 2018 12:15:57 +0100 Subject: [PATCH 03/46] [Android API 23+][mobilePickPhoto] Request for camera permissions on runtime --- .../src/java/com/runrev/android/Engine.java | 68 +++++++++++++++---- .../com/runrev/android/LiveCodeActivity.java | 10 +++ 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index af01d4297d1..49728804e9b 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -53,6 +53,8 @@ import android.provider.MediaStore.Images.Media; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.Manifest; +import java.lang.Object; import java.net.*; import java.io.*; @@ -1859,22 +1861,62 @@ else if (t_caminfo.facing == CameraCompat.CameraInfo.CAMERA_FACING_FRONT) return new String(t_directions); } + private String m_source; + public static final int CAMERA_PERMISSION_REQUEST_CODE = 1; public void showPhotoPicker(String p_source, int p_width, int p_height) { - m_photo_width = p_width; - m_photo_height = p_height; - - if (p_source.equals("camera")) - showCamera(); - else if (p_source.equals("album")) - showLibrary(); - else if (p_source.equals("library")) - showLibrary(); - else - { - doPhotoPickerError("source not available"); - } + m_photo_width = p_width; + m_photo_height = p_height; + m_source = p_source; + + // Camera permission not granted, so ask for it + if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) + { + Activity t_activity = (LiveCodeActivity)getContext(); + t_activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); + } + // Camera permission already granted, or we are in a device running Android API < 23 + else + { + onCameraPermissionGranted(m_source); + } } + + private void onCameraPermissionGranted(String p_source) + { + if (p_source.equals("camera")) + showCamera(); + else if (p_source.equals("album")) + showLibrary(); + else if (p_source.equals("library")) + showLibrary(); + else + { + doPhotoPickerError("source not available"); + } + } + + private void onCameraRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) + { + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) + { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) + { + onCameraPermissionGranted(m_source); + } + else + { + doPhotoPickerError("Permission denied. You can change this in the Settings app"); + } + } + } + + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) + { + onCameraRequestPermissionResult(requestCode, permissions, grantResults); + } + public void showCamera() { diff --git a/engine/src/java/com/runrev/android/LiveCodeActivity.java b/engine/src/java/com/runrev/android/LiveCodeActivity.java index f0ba460584a..49279915e72 100644 --- a/engine/src/java/com/runrev/android/LiveCodeActivity.java +++ b/engine/src/java/com/runrev/android/LiveCodeActivity.java @@ -23,6 +23,7 @@ import android.content.res.*; import android.widget.*; import android.util.*; +import android.content.pm.PackageManager; // This is the main activity exported by the application. This is // split into two parts, a customizable sub-class that gets dynamically @@ -198,4 +199,13 @@ protected void onActivityResult (int requestCode, int resultCode, Intent data) { s_main_view.onActivityResult(requestCode, resultCode, data); } + + // Callback sent when the app requests permissions on runtime (Android API 23+) + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) + { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + s_main_view.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } From 9a8c15bfe0d774b9bb6d79e53ef197ebe3d893f1 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Thu, 26 Jul 2018 22:23:11 +0100 Subject: [PATCH 04/46] [Android API 23+] Request for location permissions on runtime --- .../src/java/com/runrev/android/Engine.java | 20 +++++++++++++-- .../java/com/runrev/android/SensorModule.java | 25 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index 49728804e9b..3629eab7192 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -1863,6 +1863,7 @@ else if (t_caminfo.facing == CameraCompat.CameraInfo.CAMERA_FACING_FRONT) private String m_source; public static final int CAMERA_PERMISSION_REQUEST_CODE = 1; + public static final int LOCATION_PERMISSION_REQUEST_CODE = 3; public void showPhotoPicker(String p_source, int p_width, int p_height) { m_photo_width = p_width; @@ -1912,12 +1913,27 @@ private void onCameraRequestPermissionResult(int requestCode, String[] permissio } } + private void onLocationRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) + { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) + { + m_sensor_module.createLocationTracker(); + } + else + { + Log.e(TAG,"Permission denied. You can change this in the Settings app"); + } + } + + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - onCameraRequestPermissionResult(requestCode, permissions, grantResults); + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) + onCameraRequestPermissionResult(requestCode, permissions, grantResults); + else if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) + onLocationRequestPermissionResult(requestCode, permissions, grantResults); } - public void showCamera() { // 2012-01-18-IM temp file may be created in app cache folder, in which case diff --git a/engine/src/java/com/runrev/android/SensorModule.java b/engine/src/java/com/runrev/android/SensorModule.java index 29fabd62746..40ef8f493a5 100644 --- a/engine/src/java/com/runrev/android/SensorModule.java +++ b/engine/src/java/com/runrev/android/SensorModule.java @@ -19,6 +19,9 @@ import android.content.*; import android.os.*; import android.util.*; +import android.Manifest; +import java.lang.Object.*; +import android.app.Activity; import java.util.*; @@ -44,6 +47,8 @@ abstract class Tracker public static final int COARSE_TRACKING = 1; public static final int FINE_TRACKING = 2; + public static final int LOCATION_PERMISSION_REQUEST_CODE = 3; + protected boolean m_paused; protected int m_tracking_requested; protected int m_tracking_internal; @@ -230,6 +235,21 @@ class LocationTracker extends Tracker LocationListener m_gps_location_listener; public LocationTracker() + { + if (Build.VERSION.SDK_INT >= 23 && ((m_engine.getContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) + != m_engine.getContext().getPackageManager().PERMISSION_GRANTED || m_engine.getContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + != m_engine.getContext().getPackageManager().PERMISSION_GRANTED))) + { + Activity t_activity = (LiveCodeActivity)m_engine.getContext(); + t_activity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); + } + else + { + createLocationTracker(); + } + } + + private void createLocationTracker() { // Get the number of seconds since the device was booted double t_seconds_since_boot; @@ -689,4 +709,9 @@ public void finish() m_accel_tracker.stopTracking(); m_location_tracker.stopTracking(); } + + public void createLocationTracker() + { + m_location_tracker.createLocationTracker(); + } } From 0b857f1baa6ce695a2abf5f1cd5ce11966a4aa7a Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Thu, 26 Jul 2018 22:27:07 +0100 Subject: [PATCH 05/46] Removed unnecessary comparison --- engine/src/java/com/runrev/android/Engine.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index 3629eab7192..3c278ad3fb6 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -1900,16 +1900,13 @@ else if (p_source.equals("library")) private void onCameraRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) { - if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) - { - onCameraPermissionGranted(m_source); - } - else - { - doPhotoPickerError("Permission denied. You can change this in the Settings app"); - } + onCameraPermissionGranted(m_source); + } + else + { + doPhotoPickerError("Permission denied. You can change this in the Settings app"); } } @@ -1925,7 +1922,6 @@ private void onLocationRequestPermissionResult(int requestCode, String[] permiss } } - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) From 155a61ca8387f86faca03a3b0352f251ae16abf4 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Fri, 27 Jul 2018 16:12:58 +1000 Subject: [PATCH 06/46] [[ Bug ]] Move TISCopyCurrentKeyboardInputSource to main thread This patch moves `TISCopyCurrentKeyboardInputSource` as it is not allowed to be called in a non-main thread environment. --- engine/src/mac-abort.mm | 106 +++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 40 deletions(-) diff --git a/engine/src/mac-abort.mm b/engine/src/mac-abort.mm index 2eb33542a79..9f22719ec26 100644 --- a/engine/src/mac-abort.mm +++ b/engine/src/mac-abort.mm @@ -151,6 +151,58 @@ static CGEventRef abort_key_callback(CGEventTapProxy p_proxy, CGEventType p_type } #endif +static void update_keyboard_input_source() +{ + // Update our period key mapping if the input source has changed / hasn't + // been initialized. + TISInputSourceRef t_input_source; + t_input_source = TISCopyCurrentKeyboardInputSource(); + if (t_input_source != s_current_input_source || s_current_input_source == nil) + { + if (s_current_input_source != nil) + CFRelease(s_current_input_source); + + s_current_input_source = t_input_source; + s_current_period_keycode = 0xffff; + s_current_period_needs_shift = false; + + // If we have a valid keyboard input source then resolve '.'. + if (s_current_input_source != nil) + { + // Loop through all possible keycodes and map with no-shift and shift + // to see if we can find our '.' key. + for(uindex_t i = 0; i < 127; i++) + { + unichar t_char; + t_char = map_keycode_to_char(t_input_source, i, false); + if (t_char == '.') + { + s_current_period_keycode = i; + s_current_period_needs_shift = false; + break; + } + + t_char = map_keycode_to_char(t_input_source, i, true); + if (t_char == '.') + { + s_current_period_keycode = i; + s_current_period_needs_shift = true; + break; + } + } + } + } +} + +void update_keyboard_input_source_callback(CFNotificationCenterRef p_center, + void *p_observer, + CFStringRef p_name, + const void *p_object, + CFDictionaryRef p_userInfo) +{ + update_keyboard_input_source(); +} + static void abort_key_timer_callback(CFRunLoopTimerRef p_timer, void *p_info) { if (s_abort_key_disabled > 0) @@ -159,46 +211,6 @@ static void abort_key_timer_callback(CFRunLoopTimerRef p_timer, void *p_info) } s_abort_key_checked = false; - - // Update our period key mapping if the input source has changed / hasn't - // been initialized. - TISInputSourceRef t_input_source; - t_input_source = TISCopyCurrentKeyboardInputSource(); - if (t_input_source != s_current_input_source || s_current_input_source == nil) - { - if (s_current_input_source != nil) - CFRelease(s_current_input_source); - - s_current_input_source = t_input_source; - s_current_period_keycode = 0xffff; - s_current_period_needs_shift = false; - - // If we have a valid keyboard input source then resolve '.'. - if (s_current_input_source != nil) - { - // Loop through all possible keycodes and map with no-shift and shift - // to see if we can find our '.' key. - for(uindex_t i = 0; i < 127; i++) - { - unichar t_char; - t_char = map_keycode_to_char(t_input_source, i, false); - if (t_char == '.') - { - s_current_period_keycode = i; - s_current_period_needs_shift = false; - break; - } - - t_char = map_keycode_to_char(t_input_source, i, true); - if (t_char == '.') - { - s_current_period_keycode = i; - s_current_period_needs_shift = true; - break; - } - } - } - } // If we successfully found period - we must now check the state of the keys. if (s_current_period_keycode != 0xffff) @@ -343,6 +355,15 @@ bool MCPlatformInitializeAbortKey(void) if (!AXAPIEnabled()) return true; #endif + + update_keyboard_input_source(); + + CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), + nullptr, + update_keyboard_input_source_callback, + kTISNotifySelectedKeyboardInputSourceChanged, + nullptr, + CFNotificationSuspensionBehaviorDeliverImmediately); s_abort_key_thread = [[MCAbortKeyThread alloc] init]; [s_abort_key_thread start]; @@ -351,6 +372,11 @@ bool MCPlatformInitializeAbortKey(void) void MCPlatformFinalizeAbortKey(void) { + CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), + nullptr, + kTISNotifySelectedKeyboardInputSourceChanged, + nullptr); + [s_abort_key_thread terminate]; [s_abort_key_thread release]; s_abort_key_thread = nil; From 3224c7d09c47a1dd8c08951301e023a89e002d07 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Fri, 27 Jul 2018 18:21:56 +0100 Subject: [PATCH 07/46] [Runtime permissions] Created API that checks for permission --- .../src/java/com/runrev/android/Engine.java | 91 +++++++++++-------- .../java/com/runrev/android/SensorModule.java | 20 ---- engine/src/mblandroidcamera.cpp | 6 +- engine/src/mblandroidcontact.cpp | 20 ++++ engine/src/mblandroiddc.cpp | 29 ++++++ engine/src/mblandroidfs.cpp | 8 ++ engine/src/mblandroidsensor.cpp | 10 +- 7 files changed, 123 insertions(+), 61 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index 3c278ad3fb6..5b779ac7f75 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -1153,6 +1153,11 @@ public void onListPickerDone(int p_index, boolean p_done) if (m_wake_on_event) doProcess(false); } + + public void onAskPermissionDone(boolean p_granted) + { + doAskPermissionDone(p_granted); + } //////////////////////////////////////////////////////////////////////////////// @@ -1861,31 +1866,49 @@ else if (t_caminfo.facing == CameraCompat.CameraInfo.CAMERA_FACING_FRONT) return new String(t_directions); } - private String m_source; public static final int CAMERA_PERMISSION_REQUEST_CODE = 1; - public static final int LOCATION_PERMISSION_REQUEST_CODE = 3; - public void showPhotoPicker(String p_source, int p_width, int p_height) - { - m_photo_width = p_width; - m_photo_height = p_height; - m_source = p_source; - - // Camera permission not granted, so ask for it - if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.CAMERA) + public static final int COARSE_LOCATION_PERMISSION_REQUEST_CODE = 2; + public static final int FINE_LOCATION_PERMISSION_REQUEST_CODE = 3; + public static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 4; + public static final int WRITE_CONTACTS_PERMISSION_REQUEST_CODE = 5; + public static final int WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 6; + + public boolean askPermission(String p_permission) + { + if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(p_permission) != PackageManager.PERMISSION_GRANTED) { Activity t_activity = (LiveCodeActivity)getContext(); - t_activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); + t_activity.requestPermissions(new String[]{p_permission}, mapPermissionToRequestCode(p_permission)); } - // Camera permission already granted, or we are in a device running Android API < 23 else - { - onCameraPermissionGranted(m_source); - } - } + onAskPermissionDone(true); + return true; + } - private void onCameraPermissionGranted(String p_source) + private int mapPermissionToRequestCode(String p_permission) + { + if (p_permission.equals("android.permission.CAMERA")) + return CAMERA_PERMISSION_REQUEST_CODE; + else if (p_permission.equals("android.permission.ACCESS_COARSE_LOCATION")) + return COARSE_LOCATION_PERMISSION_REQUEST_CODE; + else if (p_permission.equals("android.permission.ACCESS_FINE_LOCATION")) + return FINE_LOCATION_PERMISSION_REQUEST_CODE; + else if (p_permission.equals("android.permission.READ_CONTACTS")) + return READ_CONTACTS_PERMISSION_REQUEST_CODE; + else if (p_permission.equals("android.permission.WRITE_CONTACTS")) + return WRITE_CONTACTS_PERMISSION_REQUEST_CODE; + else if (p_permission.equals("android.permission.WRITE_EXTERNAL_STORAGE")) + return WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE; + else + return -1; + } + + public void showPhotoPicker(String p_source, int p_width, int p_height) { + m_photo_width = p_width; + m_photo_height = p_height; + if (p_source.equals("camera")) showCamera(); else if (p_source.equals("album")) @@ -1896,38 +1919,27 @@ else if (p_source.equals("library")) { doPhotoPickerError("source not available"); } + } - private void onCameraRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) + private void onCameraPermissionGranted(String p_source) { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) - { - onCameraPermissionGranted(m_source); - } + if (p_source.equals("camera")) + showCamera(); + else if (p_source.equals("album")) + showLibrary(); + else if (p_source.equals("library")) + showLibrary(); else { - doPhotoPickerError("Permission denied. You can change this in the Settings app"); + doPhotoPickerError("source not available"); } } - private void onLocationRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) - { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) - { - m_sensor_module.createLocationTracker(); - } - else - { - Log.e(TAG,"Permission denied. You can change this in the Settings app"); - } - } - + // sent by the callback public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) - onCameraRequestPermissionResult(requestCode, permissions, grantResults); - else if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) - onLocationRequestPermissionResult(requestCode, permissions, grantResults); + onAskPermissionDone(grantResults[0] == PackageManager.PERMISSION_GRANTED); } public void showCamera() @@ -3791,6 +3803,7 @@ public static native void doHeadingChanged(double p_heading, double p_magnetic_h public static native void doDatePickerDone(int year, int month, int day, boolean done); public static native void doTimePickerDone(int hour, int minute, boolean done); public static native void doListPickerDone(int index, boolean done); + public static native void doAskPermissionDone(boolean granted); public static native void doMovieStopped(); public static native void doMovieTouched(); diff --git a/engine/src/java/com/runrev/android/SensorModule.java b/engine/src/java/com/runrev/android/SensorModule.java index 40ef8f493a5..fc6ffb82cbc 100644 --- a/engine/src/java/com/runrev/android/SensorModule.java +++ b/engine/src/java/com/runrev/android/SensorModule.java @@ -235,21 +235,6 @@ class LocationTracker extends Tracker LocationListener m_gps_location_listener; public LocationTracker() - { - if (Build.VERSION.SDK_INT >= 23 && ((m_engine.getContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) - != m_engine.getContext().getPackageManager().PERMISSION_GRANTED || m_engine.getContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) - != m_engine.getContext().getPackageManager().PERMISSION_GRANTED))) - { - Activity t_activity = (LiveCodeActivity)m_engine.getContext(); - t_activity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); - } - else - { - createLocationTracker(); - } - } - - private void createLocationTracker() { // Get the number of seconds since the device was booted double t_seconds_since_boot; @@ -709,9 +694,4 @@ public void finish() m_accel_tracker.stopTracking(); m_location_tracker.stopTracking(); } - - public void createLocationTracker() - { - m_location_tracker.createLocationTracker(); - } } diff --git a/engine/src/mblandroidcamera.cpp b/engine/src/mblandroidcamera.cpp index 8b1e8421b6e..74a36c0b76b 100644 --- a/engine/src/mblandroidcamera.cpp +++ b/engine/src/mblandroidcamera.cpp @@ -80,9 +80,13 @@ MCCamerasFeaturesType MCSystemGetAllCameraFeatures() return t_features; } +extern bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); bool MCAndroidPickPhoto(const char *p_source, int32_t p_max_width, int32_t p_max_height) { - MCAndroidEngineCall("showPhotoPicker", "vsii", nil, p_source, p_max_width, p_max_height); + if (!MCAndroidCheckRuntimePermission(MCSTR("android.permission.CAMERA"))) + return false; + + MCAndroidEngineCall("showPhotoPicker", "vsii", nil, p_source, p_max_width, p_max_height); // SN-2014-09-03: [[ Bug 13329 ]] MCAndroidPickPhoto's return value is ignored in 6.x, // but not in 7.0 - whence the failure in mobilePickPhoto return true; diff --git a/engine/src/mblandroidcontact.cpp b/engine/src/mblandroidcontact.cpp index cae48765ea6..70eb74cd9a9 100644 --- a/engine/src/mblandroidcontact.cpp +++ b/engine/src/mblandroidcontact.cpp @@ -58,9 +58,11 @@ static MCAndroidContactStatus s_contact_status = kMCAndroidContactWaiting; static int32_t s_contact_selected = 0; static MCString s_contacts_selected = ""; +extern bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); bool MCSystemPickContact(int32_t& r_result) { MCLog("MCSystemPickContact"); + MCAndroidEngineRemoteCall("pickContact", "i", &r_result); s_contact_status = kMCAndroidContactWaiting; while (s_contact_status == kMCAndroidContactWaiting) @@ -156,6 +158,9 @@ bool MCSystemUpdateContact(MCArrayRef p_contact, MCStringRef p_title, MCStringRef p_message, MCStringRef p_alternate_name, int32_t &r_result) { + if (!(MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_CONTACTS")))) + return false; + MCLog("MCSystemUpdateContact"); bool t_success = true; @@ -192,6 +197,10 @@ void MCAndroidUpdateContactCanceled(int32_t p_contact_id) bool MCSystemGetContactData(int32_t p_contact_id, MCArrayRef &r_contact_data) { MCLog("MCSystemGetContactData: %d", p_contact_id); + + if (!(MCAndroidCheckRuntimePermission(MCSTR("android.permission.READ_CONTACTS")))) + return false; + jobject t_jmap = nil; MCAndroidEngineRemoteCall("getContactData", "mi", &t_jmap, p_contact_id); MCLog("contact map: %p", t_jmap); @@ -209,6 +218,10 @@ bool MCSystemGetContactData(int32_t p_contact_id, MCArrayRef &r_contact_data) bool MCSystemRemoveContact(int32_t p_contact_id) { MCLog("MCSystemRemoveContact: %d", p_contact_id); + + if (!(MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_CONTACTS")))) + return false; + MCAndroidEngineRemoteCall("removeContact", "vi", nil, p_contact_id); return true; } @@ -216,6 +229,9 @@ bool MCSystemRemoveContact(int32_t p_contact_id) bool MCSystemAddContact(MCArrayRef p_contact, int32_t &r_result) { MCLog("MCSystemAddContact"); + + if (!(MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_CONTACTS")))) + return false; bool t_success = true; jobject t_map = nil; @@ -229,8 +245,12 @@ bool MCSystemAddContact(MCArrayRef p_contact, int32_t &r_result) return false; } + bool MCSystemFindContact(MCStringRef p_contact_name, MCStringRef& r_result) { + if (!(MCAndroidCheckRuntimePermission(MCSTR("android.permission.READ_CONTACTS")))) + return false; + MCAndroidEngineRemoteCall("findContact", "vx", nil, p_contact_name); return MCStringCreateWithCString(s_contacts_selected . getstring(), r_result); } diff --git a/engine/src/mblandroiddc.cpp b/engine/src/mblandroiddc.cpp index 4ef4f42b4d9..377ff388d83 100644 --- a/engine/src/mblandroiddc.cpp +++ b/engine/src/mblandroiddc.cpp @@ -2817,6 +2817,35 @@ void MCAndroidDisableOpenGLMode(void) //////////////////////////////////////////////////////////////////////////////// +static bool s_in_permission_dialog = false; +static bool s_permission_granted = false; +bool MCAndroidCheckRuntimePermission(MCStringRef p_permission) +{ + bool t_result; + s_in_permission_dialog = true; + MCAndroidEngineRemoteCall("askPermission", "bx", &t_result, p_permission); + + while (s_in_permission_dialog) + MCscreen -> wait(60.0, True, True); + + return s_permission_granted; +} + +extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAskPermissionDone(JNIEnv *env, jobject object, bool granted) __attribute__((visibility("default"))); +JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAskPermissionDone(JNIEnv *env, jobject object, bool granted) +{ + s_in_permission_dialog = false; + s_permission_granted = granted; + MCAndroidBreakWait(); +} + + + + + + +///////////////////////////////////////////////////////////////////////////////// + bool android_run_on_main_thread(void *p_callback, void *p_callback_state, int p_options); typedef void (*MCExternalThreadOptionalCallback)(void *state); diff --git a/engine/src/mblandroidfs.cpp b/engine/src/mblandroidfs.cpp index 57f3ca7e306..e451d356859 100644 --- a/engine/src/mblandroidfs.cpp +++ b/engine/src/mblandroidfs.cpp @@ -415,8 +415,16 @@ bool MCAndroidSystem::GetTemporaryFileName(MCStringRef &r_tmp_name) return MCStringCreateWithCString(tmpnam(NULL), r_tmp_name); } +extern bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); Boolean MCAndroidSystem::GetStandardFolder(MCNameRef p_folder, MCStringRef &r_folder) { + // accessing "external documents", "external cache" etc requires Write External Storage permission + if (MCStringBeginsWith(MCNameGetString(p_folder), MCSTR("external"), kMCStringOptionCompareCaseless) && !MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_EXTERNAL_STORAGE"))) + { + r_folder = MCValueRetain(kMCEmptyString); + return False; + } + // SN-2015-04-16: [[ Bug 14295 ]] The resources folder on Mobile is the same // as the engine folder. if (MCNameIsEqualToCaseless(p_folder, MCN_engine) diff --git a/engine/src/mblandroidsensor.cpp b/engine/src/mblandroidsensor.cpp index 4851f473e2d..be8f0acf323 100644 --- a/engine/src/mblandroidsensor.cpp +++ b/engine/src/mblandroidsensor.cpp @@ -58,9 +58,17 @@ void MCSystemSensorFinalize(void) } //////////////////////////////////////////////////////////////////////////////// +extern bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); bool MCSystemGetSensorAvailable(MCSensorType p_sensor, bool& r_available) -{ +{ + if (p_sensor == kMCSensorTypeLocation) + { + bool t_success = MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_COARSE_LOCATION")) && MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_FINE_LOCATION")); + if (!t_success) + return false; + } + MCAndroidEngineRemoteCall("isSensorAvailable", "bi", &r_available, (int32_t)p_sensor); return true; } From 912d98e5965412fffd28618d78b691242ae0b7bf Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Fri, 27 Jul 2018 18:30:19 +0100 Subject: [PATCH 08/46] Removed unused code --- engine/src/java/com/runrev/android/Engine.java | 16 ---------------- .../java/com/runrev/android/SensorModule.java | 6 ------ engine/src/mblandroiddc.cpp | 5 ----- 3 files changed, 27 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index 5b779ac7f75..ca6596d80c1 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -53,8 +53,6 @@ import android.provider.MediaStore.Images.Media; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.Manifest; -import java.lang.Object; import java.net.*; import java.io.*; @@ -1922,20 +1920,6 @@ else if (p_source.equals("library")) } - private void onCameraPermissionGranted(String p_source) - { - if (p_source.equals("camera")) - showCamera(); - else if (p_source.equals("album")) - showLibrary(); - else if (p_source.equals("library")) - showLibrary(); - else - { - doPhotoPickerError("source not available"); - } - } - // sent by the callback public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { diff --git a/engine/src/java/com/runrev/android/SensorModule.java b/engine/src/java/com/runrev/android/SensorModule.java index fc6ffb82cbc..58b0f77a68c 100644 --- a/engine/src/java/com/runrev/android/SensorModule.java +++ b/engine/src/java/com/runrev/android/SensorModule.java @@ -19,10 +19,6 @@ import android.content.*; import android.os.*; import android.util.*; -import android.Manifest; -import java.lang.Object.*; -import android.app.Activity; - import java.util.*; import android.hardware.*; @@ -47,8 +43,6 @@ abstract class Tracker public static final int COARSE_TRACKING = 1; public static final int FINE_TRACKING = 2; - public static final int LOCATION_PERMISSION_REQUEST_CODE = 3; - protected boolean m_paused; protected int m_tracking_requested; protected int m_tracking_internal; diff --git a/engine/src/mblandroiddc.cpp b/engine/src/mblandroiddc.cpp index 377ff388d83..f5ff3cd2181 100644 --- a/engine/src/mblandroiddc.cpp +++ b/engine/src/mblandroiddc.cpp @@ -2839,11 +2839,6 @@ JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAskPermissionDone(JNIEnv MCAndroidBreakWait(); } - - - - - ///////////////////////////////////////////////////////////////////////////////// bool android_run_on_main_thread(void *p_callback, void *p_callback_state, int p_options); From 0509d62f90b120bd1181619a10d554177a023480 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Sat, 28 Jul 2018 07:55:06 +0100 Subject: [PATCH 09/46] Used blocking wait --- .../src/java/com/runrev/android/Engine.java | 28 ++----------------- engine/src/mblandroiddc.cpp | 2 +- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index ca6596d80c1..280f3399568 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -1864,44 +1864,20 @@ else if (t_caminfo.facing == CameraCompat.CameraInfo.CAMERA_FACING_FRONT) return new String(t_directions); } - public static final int CAMERA_PERMISSION_REQUEST_CODE = 1; - public static final int COARSE_LOCATION_PERMISSION_REQUEST_CODE = 2; - public static final int FINE_LOCATION_PERMISSION_REQUEST_CODE = 3; - public static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 4; - public static final int WRITE_CONTACTS_PERMISSION_REQUEST_CODE = 5; - public static final int WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 6; - + public static final int PERMISSION_REQUEST_CODE = 1; public boolean askPermission(String p_permission) { if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(p_permission) != PackageManager.PERMISSION_GRANTED) { Activity t_activity = (LiveCodeActivity)getContext(); - t_activity.requestPermissions(new String[]{p_permission}, mapPermissionToRequestCode(p_permission)); + t_activity.requestPermissions(new String[]{p_permission}, PERMISSION_REQUEST_CODE); } else onAskPermissionDone(true); return true; } - private int mapPermissionToRequestCode(String p_permission) - { - if (p_permission.equals("android.permission.CAMERA")) - return CAMERA_PERMISSION_REQUEST_CODE; - else if (p_permission.equals("android.permission.ACCESS_COARSE_LOCATION")) - return COARSE_LOCATION_PERMISSION_REQUEST_CODE; - else if (p_permission.equals("android.permission.ACCESS_FINE_LOCATION")) - return FINE_LOCATION_PERMISSION_REQUEST_CODE; - else if (p_permission.equals("android.permission.READ_CONTACTS")) - return READ_CONTACTS_PERMISSION_REQUEST_CODE; - else if (p_permission.equals("android.permission.WRITE_CONTACTS")) - return WRITE_CONTACTS_PERMISSION_REQUEST_CODE; - else if (p_permission.equals("android.permission.WRITE_EXTERNAL_STORAGE")) - return WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE; - else - return -1; - } - public void showPhotoPicker(String p_source, int p_width, int p_height) { m_photo_width = p_width; diff --git a/engine/src/mblandroiddc.cpp b/engine/src/mblandroiddc.cpp index f5ff3cd2181..81a38421a7a 100644 --- a/engine/src/mblandroiddc.cpp +++ b/engine/src/mblandroiddc.cpp @@ -2826,7 +2826,7 @@ bool MCAndroidCheckRuntimePermission(MCStringRef p_permission) MCAndroidEngineRemoteCall("askPermission", "bx", &t_result, p_permission); while (s_in_permission_dialog) - MCscreen -> wait(60.0, True, True); + MCscreen -> wait(60.0, False, True); return s_permission_granted; } From 5c9490e443d5d446023c877d267f64c25ad62c57 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Sat, 28 Jul 2018 09:04:54 +0100 Subject: [PATCH 10/46] Implemented "androidRequestPermission()" function --- engine/src/exec-misc.cpp | 9 +++++++++ engine/src/exec.h | 1 + engine/src/mblandroidmisc.cpp | 8 ++++++++ engine/src/mblandroidutil.h | 1 + engine/src/mblhandlers.cpp | 27 +++++++++++++++++++++++++++ engine/src/mblsyntax.h | 1 + 6 files changed, 47 insertions(+) diff --git a/engine/src/exec-misc.cpp b/engine/src/exec-misc.cpp index f5bc5eebf22..e5a92186558 100644 --- a/engine/src/exec-misc.cpp +++ b/engine/src/exec-misc.cpp @@ -481,6 +481,15 @@ void MCMiscGetDoNotBackupFile(MCExecContext& ctxt, MCStringRef p_path, bool& r_n ctxt.Throw(); } +void MCMiscExecRequestPermission(MCExecContext& ctxt, MCStringRef p_permission, bool& r_granted) +{ + if (MCSystemRequestPermission(p_permission, r_granted)) + return; + + ctxt.Throw(); +} + + void MCMiscSetDoNotBackupFile(MCExecContext& ctxt, MCStringRef p_path, bool p_no_backup) { if (MCSystemFileSetDoNotBackup(p_path, p_no_backup)) diff --git a/engine/src/exec.h b/engine/src/exec.h index 81f22a8fe02..6df71a37ed0 100644 --- a/engine/src/exec.h +++ b/engine/src/exec.h @@ -4043,6 +4043,7 @@ void MCMiscExecLibUrlDownloadToFile(MCExecContext& ctxt, MCStringRef p_url, MCSt void MCMiscExecLibUrlSetSSLVerification(MCExecContext& ctxt, bool p_enabled); void MCMiscGetBuildInfo(MCExecContext& ctxt, MCStringRef p_key, MCStringRef& r_value); +void MCMiscExecRequestPermission(MCExecContext& ctxt, MCStringRef p_permission, bool& r_granted); void MCMiscExecEnableRemoteControl(MCExecContext& ctxt); void MCMiscExecDisableRemoteControl(MCExecContext& ctxt); diff --git a/engine/src/mblandroidmisc.cpp b/engine/src/mblandroidmisc.cpp index 5bc82aef127..49fd9a28b4e 100644 --- a/engine/src/mblandroidmisc.cpp +++ b/engine/src/mblandroidmisc.cpp @@ -802,6 +802,14 @@ bool MCSystemBuildInfo(MCStringRef p_key, MCStringRef& r_value) //////////////////////////////////////////////////////////////////////////////// +bool MCSystemRequestPermission(MCStringRef p_permission, bool& r_granted) +{ + r_granted = MCAndroidCheckRuntimePermission(p_permission); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// diff --git a/engine/src/mblandroidutil.h b/engine/src/mblandroidutil.h index 42fd778739e..874574ed256 100644 --- a/engine/src/mblandroidutil.h +++ b/engine/src/mblandroidutil.h @@ -63,6 +63,7 @@ void MCAndroidObjectCall(jobject p_object, const char *p_method, const char *p_s void MCAndroidObjectRemoteCall(jobject p_object, const char *p_method, const char *p_signature, void *p_return_value, ...); bool MCAndroidGetBuildInfo(MCStringRef t_key, MCStringRef &r_value); +bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); typedef struct _android_device_configuration { diff --git a/engine/src/mblhandlers.cpp b/engine/src/mblhandlers.cpp index ab260dc5817..33aea63342c 100644 --- a/engine/src/mblhandlers.cpp +++ b/engine/src/mblhandlers.cpp @@ -3377,6 +3377,32 @@ Exec_stat MCHandleBuildInfo(void *context, MCParameter *p_parameters) return ES_ERROR; } +Exec_stat MCHandleRequestPermission(void *context, MCParameter *p_parameters) +{ + MCExecContext ctxt(nil, nil, nil); + + MCAutoStringRef t_permission; + bool t_success, t_granted; + + t_success = MCParseParameters(p_parameters, "x", &(&t_permission)); + + if (t_success) + MCMiscExecRequestPermission(ctxt, *t_permission, t_granted); + + if (!ctxt . HasError()) + { + if (t_granted) + ctxt.SetTheResultToValue(kMCTrueString); + else + ctxt.SetTheResultToValue(kMCFalseString); + + return ES_NORMAL; + } + + ctxt.SetTheResultToEmpty(); + return ES_ERROR; +} + ////////////////////////////////////////////////////////////////////////////////////// static MCMediaType MCMediaTypeFromString(MCStringRef p_string) @@ -4529,6 +4555,7 @@ static const MCPlatformMessageSpec s_platform_messages[] = {false, "mobileLocationAuthorizationStatus", MCHandleLocationAuthorizationStatus, nil}, {false, "mobileBuildInfo", MCHandleBuildInfo, nil}, + {false, "androidRequestPermission", MCHandleRequestPermission, nil}, {false, "mobileCanMakePurchase", MCHandleCanMakePurchase, nil}, {false, "mobileEnablePurchaseUpdates", MCHandleEnablePurchaseUpdates, nil}, diff --git a/engine/src/mblsyntax.h b/engine/src/mblsyntax.h index 9ccfaa68249..d668a186cef 100644 --- a/engine/src/mblsyntax.h +++ b/engine/src/mblsyntax.h @@ -466,6 +466,7 @@ bool MCSystemFileSetDataProtection(MCStringRef p_path, MCStringRef p_protection_ bool MCSystemFileGetDataProtection(MCStringRef p_path, MCStringRef& r_protection_string); bool MCSystemBuildInfo(MCStringRef p_key, MCStringRef& r_value); +bool MCSystemRequestPermission(MCStringRef p_permission, bool& r_granted); bool MCSystemEnableRemoteControl(); bool MCSystemDisableRemoteControl(); From e5a704e29c5a248afa0ce290ad09288db9277590 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Sun, 29 Jul 2018 17:44:56 +0100 Subject: [PATCH 11/46] Added feature note --- .../feature-android_runtime_permissions.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 docs/notes/feature-android_runtime_permissions.md diff --git a/docs/notes/feature-android_runtime_permissions.md b/docs/notes/feature-android_runtime_permissions.md new file mode 100644 index 00000000000..85d603f5ca8 --- /dev/null +++ b/docs/notes/feature-android_runtime_permissions.md @@ -0,0 +1,26 @@ +# Android 6.0 runtime permissions + +Android 6.0 (API 23) Marshmallow introduced a new permissions model +that lets apps request permissions from the user at runtime, rather +than prior to installation. Apps built with LC 9.0.1 do support this +new permissions model, and request permissions automatically when the +app actually requires the services or data protected by the services. + +For example, if the app calls `mobilePickPhoto "camera"`, a dialog will +be shown to the user asking for permission to access the device camera. + +If the user does not grant permission, the call will fail. Moreover, the +app can use the function `androidRequestPermission(permissionName)` to +check if the permission for `permissionName` has been granted. + +Notes: + +- You have to make sure that you check the required permissions for your +app in the standalone settings. +- Apps that run on devices running Android 6+ will work with the new +permissions model. +- Apps that run on older devices (less than Android 6) will continue to +work with the old permissions model. +- If the user does not grant a permission when the dialog appears for the +first time, they can change this preference from the Settings app. + From 62f16516000d3b4a740d1a10f9601aabd6df3106 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Sun, 29 Jul 2018 19:15:13 +0100 Subject: [PATCH 12/46] [androidRequestPermission] Added dictionary entry --- .../function/androidRequestPermission.lcdoc | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/dictionary/function/androidRequestPermission.lcdoc diff --git a/docs/dictionary/function/androidRequestPermission.lcdoc b/docs/dictionary/function/androidRequestPermission.lcdoc new file mode 100644 index 00000000000..bef2e45423f --- /dev/null +++ b/docs/dictionary/function/androidRequestPermission.lcdoc @@ -0,0 +1,44 @@ +Name: androidRequestPermission + +Type: function + +Syntax: androidRequestPermission() + +Summary: +Returns if permission has been granted by the user. If the user has not been asked before, a dialog is displayed, +showing a permission request for . + +Introduced: 9.0.1 + +OS: mobile + +Platforms: android + +Example: +local tCameraPermissionGranted +put androidRequestPermission("android.permission.CAMERA") into tCameraPermissionGranted +if not tCameraPermissionGranted then + answer "This app is not permitted to access the device camera. You can change this \ + in the Settings app." +end if + + +Parameters: +permissionName (enum): +The name of the permission to request. + +- "android.permission.CAMERA": permission to access the device camera. +- "android.permission.ACCESS_COARSE_LOCATION": permission to access the device coarse location. +- "android.permission.ACCESS_FINE_LOCATION": permission to access the device fine location. +- "android.permission.WRITE_CONTACTS": permission to write date to the device contacts. +- "android.permission.READ_CONTACTS": permission to read data from the device contacts. +- "android.permission.WRITE_EXTERNAL_STORAGE": permission to write data to the device external storage. + +Returns(boolean): +True if permission has been granted, false otherwise. + + +Description: +Use the function to request permission for from the user, or to find out if permission has been granted. + +>*Note:* Permission names are case sensitive. From 4c34eaf1dca12792e5cc338fb1a634ffcc33317c Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Sun, 29 Jul 2018 23:38:55 +0100 Subject: [PATCH 13/46] Fixed a couple of issues on docs and with long lines --- .../function/androidRequestPermission.lcdoc | 8 ++++---- engine/src/mblandroidfs.cpp | 11 ++++++----- engine/src/mblandroidsensor.cpp | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/dictionary/function/androidRequestPermission.lcdoc b/docs/dictionary/function/androidRequestPermission.lcdoc index bef2e45423f..77d1ec486ae 100644 --- a/docs/dictionary/function/androidRequestPermission.lcdoc +++ b/docs/dictionary/function/androidRequestPermission.lcdoc @@ -10,16 +10,16 @@ showing a permission request for . Introduced: 9.0.1 -OS: mobile +OS: android -Platforms: android +Platforms: mobile Example: local tCameraPermissionGranted put androidRequestPermission("android.permission.CAMERA") into tCameraPermissionGranted if not tCameraPermissionGranted then - answer "This app is not permitted to access the device camera. You can change this \ - in the Settings app." + answer "This app is not permitted to access the device camera. You can change this" && \ + "in the Settings app." end if diff --git a/engine/src/mblandroidfs.cpp b/engine/src/mblandroidfs.cpp index e451d356859..1b18e3ffb90 100644 --- a/engine/src/mblandroidfs.cpp +++ b/engine/src/mblandroidfs.cpp @@ -419,7 +419,8 @@ extern bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); Boolean MCAndroidSystem::GetStandardFolder(MCNameRef p_folder, MCStringRef &r_folder) { // accessing "external documents", "external cache" etc requires Write External Storage permission - if (MCStringBeginsWith(MCNameGetString(p_folder), MCSTR("external"), kMCStringOptionCompareCaseless) && !MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_EXTERNAL_STORAGE"))) + if (MCStringBeginsWith(MCNameGetString(p_folder), MCSTR("external"), kMCStringOptionCompareCaseless) && \ + !MCAndroidCheckRuntimePermission(MCSTR("android.permission.WRITE_EXTERNAL_STORAGE"))) { r_folder = MCValueRetain(kMCEmptyString); return False; @@ -428,18 +429,18 @@ Boolean MCAndroidSystem::GetStandardFolder(MCNameRef p_folder, MCStringRef &r_fo // SN-2015-04-16: [[ Bug 14295 ]] The resources folder on Mobile is the same // as the engine folder. if (MCNameIsEqualToCaseless(p_folder, MCN_engine) - || MCNameIsEqualToCaseless(p_folder, MCN_resources)) + || MCNameIsEqualToCaseless(p_folder, MCN_resources)) { MCLog("GetStandardFolder(\"%@\") -> \"%@\"", MCNameGetString(p_folder), MCcmd); - return MCStringCopy(MCcmd, r_folder); + return MCStringCopy(MCcmd, r_folder); } - MCAutoStringRef t_stdfolder; + MCAutoStringRef t_stdfolder; MCAndroidEngineCall("getSpecialFolderPath", "xx", &(&t_stdfolder), MCNameGetString(p_folder)); MCLog("GetStandardFolder(\"%@\") -> \"%@\"", p_folder, *t_stdfolder == nil ? kMCEmptyString : *t_stdfolder); - r_folder = MCValueRetain(*t_stdfolder == nil ? kMCEmptyString : *t_stdfolder); + r_folder = MCValueRetain(*t_stdfolder == nil ? kMCEmptyString : *t_stdfolder); return True; } diff --git a/engine/src/mblandroidsensor.cpp b/engine/src/mblandroidsensor.cpp index be8f0acf323..3f1182c000b 100644 --- a/engine/src/mblandroidsensor.cpp +++ b/engine/src/mblandroidsensor.cpp @@ -64,7 +64,8 @@ bool MCSystemGetSensorAvailable(MCSensorType p_sensor, bool& r_available) { if (p_sensor == kMCSensorTypeLocation) { - bool t_success = MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_COARSE_LOCATION")) && MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_FINE_LOCATION")); + bool t_success = MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_COARSE_LOCATION")) && \ + MCAndroidCheckRuntimePermission(MCSTR("android.permission.ACCESS_FINE_LOCATION")); if (!t_success) return false; } From d2c5a3a021f347d2ed4230fe219cc0caaa9fa2b9 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Mon, 30 Jul 2018 15:06:26 +0100 Subject: [PATCH 14/46] Added "androidHasPermission" and "androidPermissionExists" commands --- .../androidRequestPermission.lcdoc | 15 ++-- .../function/androidHasPermission.lcdoc | 46 +++++++++++ .../function/androidPermissionExists.lcdoc | 33 ++++++++ engine/src/exec-misc.cpp | 16 ++++ engine/src/exec.h | 2 + engine/src/executionerrors.h | 3 + .../src/java/com/runrev/android/Engine.java | 77 +++++++++++++++++++ engine/src/mblandroiddc.cpp | 16 ++++ engine/src/mblandroidmisc.cpp | 12 +++ engine/src/mblandroidutil.h | 2 + engine/src/mblhandlers.cpp | 71 ++++++++++++++++- engine/src/mblsyntax.h | 2 + 12 files changed, 287 insertions(+), 8 deletions(-) rename docs/dictionary/{function => command}/androidRequestPermission.lcdoc (65%) create mode 100644 docs/dictionary/function/androidHasPermission.lcdoc create mode 100644 docs/dictionary/function/androidPermissionExists.lcdoc diff --git a/docs/dictionary/function/androidRequestPermission.lcdoc b/docs/dictionary/command/androidRequestPermission.lcdoc similarity index 65% rename from docs/dictionary/function/androidRequestPermission.lcdoc rename to docs/dictionary/command/androidRequestPermission.lcdoc index 77d1ec486ae..e098fea43ad 100644 --- a/docs/dictionary/function/androidRequestPermission.lcdoc +++ b/docs/dictionary/command/androidRequestPermission.lcdoc @@ -1,12 +1,11 @@ Name: androidRequestPermission -Type: function +Type: command Syntax: androidRequestPermission() Summary: -Returns if permission has been granted by the user. If the user has not been asked before, a dialog is displayed, -showing a permission request for . +Displays a dialog showing a permission request for . If a user has already granted permission for , this command does nothing. Introduced: 9.0.1 @@ -16,7 +15,11 @@ Platforms: mobile Example: local tCameraPermissionGranted -put androidRequestPermission("android.permission.CAMERA") into tCameraPermissionGranted +put androidHasPermission("android.permission.CAMERA") into tCameraPermissionGranted +if not tCameraPermissionGranted then + androidRequestPermission("android.permission.CAMERA") +end if +put androidHasPermission("android.permission.CAMERA") into tCameraPermissionGranted if not tCameraPermissionGranted then answer "This app is not permitted to access the device camera. You can change this" && \ "in the Settings app." @@ -34,11 +37,9 @@ The name of the permission to request. - "android.permission.READ_CONTACTS": permission to read data from the device contacts. - "android.permission.WRITE_EXTERNAL_STORAGE": permission to write data to the device external storage. -Returns(boolean): -True if permission has been granted, false otherwise. Description: -Use the function to request permission for from the user, or to find out if permission has been granted. +Use the command to request permission for from the user. >*Note:* Permission names are case sensitive. diff --git a/docs/dictionary/function/androidHasPermission.lcdoc b/docs/dictionary/function/androidHasPermission.lcdoc new file mode 100644 index 00000000000..856aedfe73c --- /dev/null +++ b/docs/dictionary/function/androidHasPermission.lcdoc @@ -0,0 +1,46 @@ +Name: androidHasPermission + +Type: function + +Syntax: androidHasPermission() + +Summary: +Returns if permission has been granted by the user. + +Introduced: 9.0.1 + +OS: android + +Platforms: mobile + +Example: +local tLocationPermissionGranted +put androidHasPermission("android.permission.ACCESS_FINE_LOCATION") into tLocationPermissionGranted +if not tLocationPermissionGranted then + androidRequestPermission("android.permission.ACCESS_FINE_LOCATION") +end if +if not tLocationPermissionGranted then + answer "This app is not permitted to access the device location. You can change this" && \ + "in the Settings app." +end if + + +Parameters: +permissionName (enum): +The name of the permission to request. + +- "android.permission.CAMERA": permission to access the device camera. +- "android.permission.ACCESS_COARSE_LOCATION": permission to access the device coarse location. +- "android.permission.ACCESS_FINE_LOCATION": permission to access the device fine location. +- "android.permission.WRITE_CONTACTS": permission to write date to the device contacts. +- "android.permission.READ_CONTACTS": permission to read data from the device contacts. +- "android.permission.WRITE_EXTERNAL_STORAGE": permission to write data to the device external storage. + +Returns(boolean): +True if permission has been granted, false otherwise. + + +Description: +Use the function to find out if permission has been granted by the user. + +>*Note:* Permission names are case sensitive. diff --git a/docs/dictionary/function/androidPermissionExists.lcdoc b/docs/dictionary/function/androidPermissionExists.lcdoc new file mode 100644 index 00000000000..46f1341b896 --- /dev/null +++ b/docs/dictionary/function/androidPermissionExists.lcdoc @@ -0,0 +1,33 @@ +Name: androidPermissionExists + +Type: function + +Syntax: androidPermissionExists() + +Summary: +Returns true if is a valid Android permission name + +Introduced: 9.0.1 + +OS: android + +Platforms: mobile + +Example: + +if not androidPermissionExists(pPermission) then + answer pPermission && "is not a valid permission name" +end if + + +Parameters: +permissionName (string): +The name of the permission to check. + +Returns(boolean): +True if is a valid Android permission name, false otherwise. + +Description: +Use the function to check if is a valid Android permission name. + +>*Note:* Permission names are case sensitive. diff --git a/engine/src/exec-misc.cpp b/engine/src/exec-misc.cpp index e5a92186558..432396ca6e0 100644 --- a/engine/src/exec-misc.cpp +++ b/engine/src/exec-misc.cpp @@ -489,6 +489,22 @@ void MCMiscExecRequestPermission(MCExecContext& ctxt, MCStringRef p_permission, ctxt.Throw(); } +void MCMiscExecPermissionExists(MCExecContext& ctxt, MCStringRef p_permission, bool& r_exists) +{ + if (MCSystemPermissionExists(p_permission, r_exists)) + return; + + ctxt.Throw(); +} + +void MCMiscExecHasPermission(MCExecContext& ctxt, MCStringRef p_permission, bool& r_permission_granted) +{ + if (MCSystemHasPermission(p_permission, r_permission_granted)) + return; + + ctxt.Throw(); +} + void MCMiscSetDoNotBackupFile(MCExecContext& ctxt, MCStringRef p_path, bool p_no_backup) { diff --git a/engine/src/exec.h b/engine/src/exec.h index 6df71a37ed0..2644f12c558 100644 --- a/engine/src/exec.h +++ b/engine/src/exec.h @@ -4044,6 +4044,8 @@ void MCMiscExecLibUrlSetSSLVerification(MCExecContext& ctxt, bool p_enabled); void MCMiscGetBuildInfo(MCExecContext& ctxt, MCStringRef p_key, MCStringRef& r_value); void MCMiscExecRequestPermission(MCExecContext& ctxt, MCStringRef p_permission, bool& r_granted); +void MCMiscExecPermissionExists(MCExecContext& ctxt, MCStringRef p_permission, bool& r_exists); +void MCMiscExecHasPermission(MCExecContext& ctxt, MCStringRef p_permission, bool& r_permission_granted); void MCMiscExecEnableRemoteControl(MCExecContext& ctxt); void MCMiscExecDisableRemoteControl(MCExecContext& ctxt); diff --git a/engine/src/executionerrors.h b/engine/src/executionerrors.h index 90b4e821948..7a4f1dd565c 100644 --- a/engine/src/executionerrors.h +++ b/engine/src/executionerrors.h @@ -2774,6 +2774,9 @@ enum Exec_errors // {EE-0908} fontLanguage: bad font name EE_FONTLANGUAGE_BADFONTNAME, + // {EE-0909} android permission: bad permission name + EE_BAD_PERMISSION_NAME, + }; extern const char *MCexecutionerrors; diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index 280f3399568..e88af53fd66 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -1878,6 +1878,83 @@ public boolean askPermission(String p_permission) return true; } + public boolean checkHasPermissionGranted(String p_permission) + { + if (Build.VERSION.SDK_INT >= 23) + { + return getContext().checkSelfPermission(p_permission) == PackageManager.PERMISSION_GRANTED; + } + return true; + } + + + public boolean checkPermissionExists(String p_permission) + { + if (Build.VERSION.SDK_INT >= 23) + { + List t_group_info_list = getAllPermissionGroups(); + if (t_group_info_list == null) + return false; + + ArrayList t_group_name_list = new ArrayList(); + for (PermissionGroupInfo t_group_info : t_group_info_list) + { + String t_group_name = t_group_info.name; + if (t_group_name != null) + t_group_name_list.add(t_group_name); + } + + for (String t_group_name : t_group_name_list) + { + ArrayList t_permission_name_list = getPermissionsForGroup(t_group_name); + + if (t_permission_name_list.contains(p_permission)) + return true; + } + return false; + } + return true; + } + + private List getAllPermissionGroups() + { + final PackageManager t_package_manager = getContext().getPackageManager(); + if (t_package_manager == null) + return null; + + return t_package_manager.getAllPermissionGroups(0); + } + + private ArrayList getPermissionsForGroup(String p_group_name) + { + final PackageManager t_package_manager = getContext().getPackageManager(); + final ArrayList t_permission_name_list = new ArrayList(); + + try + { + List t_permission_info_list = + t_package_manager.queryPermissionsByGroup(p_group_name, PackageManager.GET_META_DATA); + if (t_permission_info_list != null) + { + for (PermissionInfo t_permission_info : t_permission_info_list) + { + String t_permission_name = t_permission_info.name; + t_permission_name_list.add(t_permission_name); + } + } + } + catch (PackageManager.NameNotFoundException e) + { + // e.printStackTrace(); + Log.d(TAG, "permissions not found for group = " + p_group_name); + } + + Collections.sort(t_permission_name_list); + + return t_permission_name_list; + } + + public void showPhotoPicker(String p_source, int p_width, int p_height) { m_photo_width = p_width; diff --git a/engine/src/mblandroiddc.cpp b/engine/src/mblandroiddc.cpp index 81a38421a7a..7d8801ae5f9 100644 --- a/engine/src/mblandroiddc.cpp +++ b/engine/src/mblandroiddc.cpp @@ -2831,6 +2831,22 @@ bool MCAndroidCheckRuntimePermission(MCStringRef p_permission) return s_permission_granted; } +bool MCAndroidCheckPermissionExists(MCStringRef p_permission) +{ + bool t_result; + MCAndroidEngineRemoteCall("checkPermissionExists", "bx", &t_result, p_permission); + + return t_result; +} + +bool MCAndroidHasPermission(MCStringRef p_permission) +{ + bool t_result; + MCAndroidEngineRemoteCall("checkHasPermissionGranted", "bx", &t_result, p_permission); + + return t_result; +} + extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAskPermissionDone(JNIEnv *env, jobject object, bool granted) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAskPermissionDone(JNIEnv *env, jobject object, bool granted) { diff --git a/engine/src/mblandroidmisc.cpp b/engine/src/mblandroidmisc.cpp index 49fd9a28b4e..477ea6fa94b 100644 --- a/engine/src/mblandroidmisc.cpp +++ b/engine/src/mblandroidmisc.cpp @@ -808,6 +808,18 @@ bool MCSystemRequestPermission(MCStringRef p_permission, bool& r_granted) return true; } +bool MCSystemPermissionExists(MCStringRef p_permission, bool& r_exists) +{ + r_exists = MCAndroidCheckPermissionExists(p_permission); + return true; +} + +bool MCSystemHasPermission(MCStringRef p_permission, bool& r_permission_granted) +{ + r_permission_granted = MCAndroidHasPermission(p_permission); + return true; +} + //////////////////////////////////////////////////////////////////////////////// diff --git a/engine/src/mblandroidutil.h b/engine/src/mblandroidutil.h index 874574ed256..108877c0a7f 100644 --- a/engine/src/mblandroidutil.h +++ b/engine/src/mblandroidutil.h @@ -64,6 +64,8 @@ void MCAndroidObjectRemoteCall(jobject p_object, const char *p_method, const cha bool MCAndroidGetBuildInfo(MCStringRef t_key, MCStringRef &r_value); bool MCAndroidCheckRuntimePermission(MCStringRef p_permission); +bool MCAndroidCheckPermissionExists(MCStringRef p_permission); +bool MCAndroidHasPermission(MCStringRef p_permission); typedef struct _android_device_configuration { diff --git a/engine/src/mblhandlers.cpp b/engine/src/mblhandlers.cpp index 33aea63342c..2a5f0b48422 100644 --- a/engine/src/mblhandlers.cpp +++ b/engine/src/mblhandlers.cpp @@ -3377,6 +3377,7 @@ Exec_stat MCHandleBuildInfo(void *context, MCParameter *p_parameters) return ES_ERROR; } +/////////////////// Android 6.0 runtime permissions ///////////////////////// Exec_stat MCHandleRequestPermission(void *context, MCParameter *p_parameters) { MCExecContext ctxt(nil, nil, nil); @@ -3386,12 +3387,78 @@ Exec_stat MCHandleRequestPermission(void *context, MCParameter *p_parameters) t_success = MCParseParameters(p_parameters, "x", &(&t_permission)); + bool t_permission_exists; + MCMiscExecPermissionExists(ctxt, *t_permission, t_permission_exists); + + if (!t_permission_exists) + { + ctxt.LegacyThrow(EE_BAD_PERMISSION_NAME); + t_success = false; + } + if (t_success) MCMiscExecRequestPermission(ctxt, *t_permission, t_granted); + Exec_stat t_stat; + if (!ctxt . HasError()) + t_stat = ES_NORMAL; + else + t_stat = ES_ERROR; + + ctxt.SetTheResultToEmpty(); + return t_stat; +} + +Exec_stat MCHandlePermissionExists(void *context, MCParameter *p_parameters) +{ + MCExecContext ctxt(nil, nil, nil); + + MCAutoStringRef t_permission; + bool t_success, t_exists; + + t_success = MCParseParameters(p_parameters, "x", &(&t_permission)); + + if (t_success) + MCMiscExecPermissionExists(ctxt, *t_permission, t_exists); + + if (!ctxt . HasError()) + { + if (t_exists) + ctxt.SetTheResultToValue(kMCTrueString); + else + ctxt.SetTheResultToValue(kMCFalseString); + + return ES_NORMAL; + } + + ctxt.SetTheResultToEmpty(); + return ES_ERROR; +} + +Exec_stat MCHandleHasPermission(void *context, MCParameter *p_parameters) +{ + MCExecContext ctxt(nil, nil, nil); + + MCAutoStringRef t_permission; + bool t_success, t_permission_granted; + + t_success = MCParseParameters(p_parameters, "x", &(&t_permission)); + + bool t_permission_exists; + MCMiscExecPermissionExists(ctxt, *t_permission, t_permission_exists); + + if (!t_permission_exists) + { + ctxt.LegacyThrow(EE_BAD_PERMISSION_NAME); + t_success = false; + } + + if (t_success) + MCMiscExecHasPermission(ctxt, *t_permission, t_permission_granted); + if (!ctxt . HasError()) { - if (t_granted) + if (t_permission_granted) ctxt.SetTheResultToValue(kMCTrueString); else ctxt.SetTheResultToValue(kMCFalseString); @@ -4556,6 +4623,8 @@ static const MCPlatformMessageSpec s_platform_messages[] = {false, "mobileBuildInfo", MCHandleBuildInfo, nil}, {false, "androidRequestPermission", MCHandleRequestPermission, nil}, + {false, "androidPermissionExists", MCHandlePermissionExists, nil}, + {false, "androidHasPermission", MCHandleHasPermission, nil}, {false, "mobileCanMakePurchase", MCHandleCanMakePurchase, nil}, {false, "mobileEnablePurchaseUpdates", MCHandleEnablePurchaseUpdates, nil}, diff --git a/engine/src/mblsyntax.h b/engine/src/mblsyntax.h index d668a186cef..7f653d92584 100644 --- a/engine/src/mblsyntax.h +++ b/engine/src/mblsyntax.h @@ -467,6 +467,8 @@ bool MCSystemFileGetDataProtection(MCStringRef p_path, MCStringRef& r_protection bool MCSystemBuildInfo(MCStringRef p_key, MCStringRef& r_value); bool MCSystemRequestPermission(MCStringRef p_permission, bool& r_granted); +bool MCSystemPermissionExists(MCStringRef p_permission, bool& r_exists); +bool MCSystemHasPermission(MCStringRef p_permission, bool& r_permission_granted); bool MCSystemEnableRemoteControl(); bool MCSystemDisableRemoteControl(); From 120b71fde68f4c4cac94d4632778a888d5a3190d Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 31 Jul 2018 09:30:57 +0100 Subject: [PATCH 15/46] Added stubs for iphone and updated docs --- .../command/androidRequestPermission.lcdoc | 34 +++++++++++++++---- .../function/androidHasPermission.lcdoc | 34 +++++++++++++++---- engine/src/mbliphonemisc.mm | 22 ++++++++++++ 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/docs/dictionary/command/androidRequestPermission.lcdoc b/docs/dictionary/command/androidRequestPermission.lcdoc index e098fea43ad..63a2ed2b168 100644 --- a/docs/dictionary/command/androidRequestPermission.lcdoc +++ b/docs/dictionary/command/androidRequestPermission.lcdoc @@ -17,7 +17,7 @@ Example: local tCameraPermissionGranted put androidHasPermission("android.permission.CAMERA") into tCameraPermissionGranted if not tCameraPermissionGranted then - androidRequestPermission("android.permission.CAMERA") + androidRequestPermission "android.permission.CAMERA" end if put androidHasPermission("android.permission.CAMERA") into tCameraPermissionGranted if not tCameraPermissionGranted then @@ -30,12 +30,32 @@ Parameters: permissionName (enum): The name of the permission to request. -- "android.permission.CAMERA": permission to access the device camera. -- "android.permission.ACCESS_COARSE_LOCATION": permission to access the device coarse location. -- "android.permission.ACCESS_FINE_LOCATION": permission to access the device fine location. -- "android.permission.WRITE_CONTACTS": permission to write date to the device contacts. -- "android.permission.READ_CONTACTS": permission to read data from the device contacts. -- "android.permission.WRITE_EXTERNAL_STORAGE": permission to write data to the device external storage. +- "android.permission.READ_CALENDAR": permission to allow an application to read the device's calendar. +- "android.permission.WRITE_CALENDAR": permission to allow an application to write to the device's calendar. +- "android.permission.CAMERA": permission to allow an application to access the device's camera. +- "android.permission.ACCESS_COARSE_LOCATION": permission to allow an application to access the device's coarse location. +- "android.permission.ACCESS_FINE_LOCATION": permission to allow an application to access the device's fine location. +- "android.permission.READ_CONTACTS": permission to allow an application to read data from the device's contacts. +- "android.permission.WRITE_CONTACTS": permission to allow an application to write date to the device's contacts. +- "android.permission.GET_ACCOUNTS": permission to allow an application to access to the list of accounts in the Accounts Service. +- "android.permission.RECORD_AUDIO": permission to allow an application to allow an application to record audio. +- "android.permission.READ_EXTERNAL_STORAGE": permission to allow an application to read data from the device's external storage. +- "android.permission.WRITE_EXTERNAL_STORAGE": permission to allow an application to write data to the device's external storage. +- "android.permission.READ_PHONE_STATE": permission to allow an application to access phone state, including the phone number of the device, current cellular network information, the status of any ongoing calls, and a list of any PhoneAccounts registered on the device. +- "android.permission.READ_PHONE_NUMBERS": permission to allow an application to access the device's phone number(s). +- "android.permission.CALL_PHONE": permission to allow an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call. +- "android.permission.ANSWER_PHONE_CALLS": permission to allow an application to answer an incoming phone call. +- "android.permission.READ_CALL_LOG": permission to allow an application to read the user's call log. +- "android.permission.WRITE_CALL_LOG": permission to allow an application to write to the user's call log. +- "android.permission.ADD_VOICEMAIL": permission to allow an application to add voicemails into the system. +- "android.permission.USE_SIP": permission to allow an application to use SIP service. +- "android.permission.PROCESS_OUTGOING_CALLS": permission to allow an application to see the number being dialed during an outgoing call with the option to redirect the call to a different number or abort the call altogether. +- "android.permission.SEND_SMS": permission to allow an application to send SMS messages. +- "android.permission.RECEIVE_SMS": permission to allow an application to receive SMS messages +- "android.permission.READ_SMS": permission to allow an application to read SMS messages. +- "android.permission.RECEIVE_WAP_PUSH": permission to allow an application to receive WAP push messages. +- "android.permission.RECEIVE_MMS": permission to allow an application to receive MMS messages. +- "android.permission.BODY_SENSORS": permission to allow an application to access data from sensors that the user uses to measure what is happening inside his/her body, such as heart rate. diff --git a/docs/dictionary/function/androidHasPermission.lcdoc b/docs/dictionary/function/androidHasPermission.lcdoc index 856aedfe73c..48219cce0e2 100644 --- a/docs/dictionary/function/androidHasPermission.lcdoc +++ b/docs/dictionary/function/androidHasPermission.lcdoc @@ -17,7 +17,7 @@ Example: local tLocationPermissionGranted put androidHasPermission("android.permission.ACCESS_FINE_LOCATION") into tLocationPermissionGranted if not tLocationPermissionGranted then - androidRequestPermission("android.permission.ACCESS_FINE_LOCATION") + androidRequestPermission "android.permission.ACCESS_FINE_LOCATION" end if if not tLocationPermissionGranted then answer "This app is not permitted to access the device location. You can change this" && \ @@ -29,12 +29,32 @@ Parameters: permissionName (enum): The name of the permission to request. -- "android.permission.CAMERA": permission to access the device camera. -- "android.permission.ACCESS_COARSE_LOCATION": permission to access the device coarse location. -- "android.permission.ACCESS_FINE_LOCATION": permission to access the device fine location. -- "android.permission.WRITE_CONTACTS": permission to write date to the device contacts. -- "android.permission.READ_CONTACTS": permission to read data from the device contacts. -- "android.permission.WRITE_EXTERNAL_STORAGE": permission to write data to the device external storage. +- "android.permission.READ_CALENDAR": permission to allow an application to read the device's calendar. +- "android.permission.WRITE_CALENDAR": permission to allow an application to write to the device's calendar. +- "android.permission.CAMERA": permission to allow an application to access the device's camera. +- "android.permission.ACCESS_COARSE_LOCATION": permission to allow an application to access the device's coarse location. +- "android.permission.ACCESS_FINE_LOCATION": permission to allow an application to access the device's fine location. +- "android.permission.READ_CONTACTS": permission to allow an application to read data from the device's contacts. +- "android.permission.WRITE_CONTACTS": permission to allow an application to write date to the device's contacts. +- "android.permission.GET_ACCOUNTS": permission to allow an application to access to the list of accounts in the Accounts Service. +- "android.permission.RECORD_AUDIO": permission to allow an application to allow an application to record audio. +- "android.permission.READ_EXTERNAL_STORAGE": permission to allow an application to read data from the device's external storage. +- "android.permission.WRITE_EXTERNAL_STORAGE": permission to allow an application to write data to the device's external storage. +- "android.permission.READ_PHONE_STATE": permission to allow an application to access phone state, including the phone number of the device, current cellular network information, the status of any ongoing calls, and a list of any PhoneAccounts registered on the device. +- "android.permission.READ_PHONE_NUMBERS": permission to allow an application to access the device's phone number(s). +- "android.permission.CALL_PHONE": permission to allow an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call. +- "android.permission.ANSWER_PHONE_CALLS": permission to allow an application to answer an incoming phone call. +- "android.permission.READ_CALL_LOG": permission to allow an application to read the user's call log. +- "android.permission.WRITE_CALL_LOG": permission to allow an application to write to the user's call log. +- "android.permission.ADD_VOICEMAIL": permission to allow an application to add voicemails into the system. +- "android.permission.USE_SIP": permission to allow an application to use SIP service. +- "android.permission.PROCESS_OUTGOING_CALLS": permission to allow an application to see the number being dialed during an outgoing call with the option to redirect the call to a different number or abort the call altogether. +- "android.permission.SEND_SMS": permission to allow an application to send SMS messages. +- "android.permission.RECEIVE_SMS": permission to allow an application to receive SMS messages +- "android.permission.READ_SMS": permission to allow an application to read SMS messages. +- "android.permission.RECEIVE_WAP_PUSH": permission to allow an application to receive WAP push messages. +- "android.permission.RECEIVE_MMS": permission to allow an application to receive MMS messages. +- "android.permission.BODY_SENSORS": permission to allow an application to access data from sensors that the user uses to measure what is happening inside his/her body, such as heart rate. Returns(boolean): True if permission has been granted, false otherwise. diff --git a/engine/src/mbliphonemisc.mm b/engine/src/mbliphonemisc.mm index 3b497d95ac1..2fbcceb7fee 100644 --- a/engine/src/mbliphonemisc.mm +++ b/engine/src/mbliphonemisc.mm @@ -26,3 +26,25 @@ int32_t MCCustomPrinterComputeFontSize(void *font) { return CTFontGetSize((CTFontRef)font); } + +//////////////////////////////////////////////////////////////////////////////// + +bool MCSystemRequestPermission(MCStringRef p_permission, bool& r_granted) +{ + // Not implemented + return false; +} + +bool MCSystemPermissionExists(MCStringRef p_permission, bool& r_exists) +{ + // Not implemented + return false; +} + +bool MCSystemHasPermission(MCStringRef p_permission, bool& r_permission_granted) +{ + // Not implemented + return false; +} + +//////////////////////////////////////////////////////////////////////////////// From 39b59eeee08b75e6968c872bc865258757f11c73 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 31 Jul 2018 09:32:48 +0100 Subject: [PATCH 16/46] [androidRequestPermission] Docs: removed parentheses from syntax --- docs/dictionary/command/androidRequestPermission.lcdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dictionary/command/androidRequestPermission.lcdoc b/docs/dictionary/command/androidRequestPermission.lcdoc index 63a2ed2b168..07e5f1ec831 100644 --- a/docs/dictionary/command/androidRequestPermission.lcdoc +++ b/docs/dictionary/command/androidRequestPermission.lcdoc @@ -2,7 +2,7 @@ Name: androidRequestPermission Type: command -Syntax: androidRequestPermission() +Syntax: androidRequestPermission Summary: Displays a dialog showing a permission request for . If a user has already granted permission for , this command does nothing. From b1be19ca9592f82b137fd8e3564fff76381606ae Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 31 Jul 2018 11:32:02 +0100 Subject: [PATCH 17/46] [9.0.1-rc-2] Updated version --- version | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version b/version index 12491871bcd..493f72c3dca 100644 --- a/version +++ b/version @@ -1,6 +1,6 @@ -BUILD_REVISION = 15100 +BUILD_REVISION = 15101 BUILD_MAJOR_VERSION = 9 BUILD_MINOR_VERSION = 0 BUILD_POINT_VERSION = 1 -BUILD_SHORT_VERSION = 9.0.1-rc-1 -BUILD_LONG_VERSION = 9.0.1.15100 (RC 1) +BUILD_SHORT_VERSION = 9.0.1-rc-2 +BUILD_LONG_VERSION = 9.0.1.15101 (RC 2) From 9c388a56a4a049d27d99c2d9271a9895e19e3d52 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Tue, 31 Jul 2018 19:48:30 +1000 Subject: [PATCH 18/46] [[ Bug 18395 ]] Handle return correctly in fileds on Android This patch ensures that all key events are routed through `handleKey` in order to ensure that special key events like return are translated correctly and we only have one code path to send a key event to the engine. --- docs/notes/bugfix-18395.md | 1 + engine/src/java/com/runrev/android/Engine.java | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 docs/notes/bugfix-18395.md diff --git a/docs/notes/bugfix-18395.md b/docs/notes/bugfix-18395.md new file mode 100644 index 00000000000..6956ec53449 --- /dev/null +++ b/docs/notes/bugfix-18395.md @@ -0,0 +1 @@ +# Fix return key event handling in fields on Android \ No newline at end of file diff --git a/engine/src/java/com/runrev/android/Engine.java b/engine/src/java/com/runrev/android/Engine.java index bc22d9fe676..f40288da8ce 100644 --- a/engine/src/java/com/runrev/android/Engine.java +++ b/engine/src/java/com/runrev/android/Engine.java @@ -502,12 +502,12 @@ else if (key.getAction() == KeyEvent.ACTION_MULTIPLE) // IM-2013-02-21: [[ BZ 10684 ]] // allow BaseInputConnection to do the handling of commitText(), etc // and instead catch the raw key events that are generated. - if (key.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) + if (t_key_code == KeyEvent.KEYCODE_UNKNOWN) { // handle string of chars CharSequence t_chars = key.getCharacters(); for (int i = 0; i < t_chars.length(); i++) - doKeyPress(0, t_chars.charAt(i), 0); + handleKey(t_key_code, t_chars.charAt(i)); } else { @@ -548,10 +548,10 @@ void updateComposingText(CharSequence p_new) // send backspaces for (int i = 0; i < t_current_length - t_match_length; i++) - doKeyPress(0, 0, 0xff08); + handleKey(KeyEvent.KEYCODE_DEL, 0); // send new text for (int i = t_match_length; i < t_new_length; i++) - doKeyPress(0, p_new.charAt(i), 0); + handleKey(KeyEvent.KEYCODE_UNKNOWN, p_new.charAt(i)); m_composing_text = p_new; From 3ba44983945dd33540668376409f71d9ec985c40 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Thu, 2 Aug 2018 12:52:29 +1000 Subject: [PATCH 19/46] [[ Bug 21443 ]] Dirty rect even if layer id is 0 This patch ensures that groups with `m_layer_id` of 0 still have their effective rect dirtied. Previously a `return` was causing the dirtying of the rect to be skipped. --- docs/notes/bugfix-21443.md | 1 + engine/src/redraw.cpp | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) create mode 100644 docs/notes/bugfix-21443.md diff --git a/docs/notes/bugfix-21443.md b/docs/notes/bugfix-21443.md new file mode 100644 index 00000000000..152fe0a6576 --- /dev/null +++ b/docs/notes/bugfix-21443.md @@ -0,0 +1 @@ +# Fix groups sometimes not redrawing when scrolled \ No newline at end of file diff --git a/engine/src/redraw.cpp b/engine/src/redraw.cpp index 9e09d160851..0fe196e8d79 100644 --- a/engine/src/redraw.cpp +++ b/engine/src/redraw.cpp @@ -599,14 +599,10 @@ void MCControl::layer_dirtyeffectiverect(const MCRectangle& p_effective_rect, bo MCRectangle32 t_device_rect; t_device_rect = MCRectangle32GetTransformedBounds(t_dirty_rect, t_transform); - // Notify any tilecache of the changes. - if (t_tilecache != nil) + // Notify any tilecache of the changes + // If the layer id is zero, there is nothing to do. + if (t_tilecache != nil && t_control -> m_layer_id != 0) { - // We must be in tile-cache mode with a top-level control, but if the layer - // id is zero, there is nothing to do. - if (t_control -> m_layer_id == 0) - return; - // How we handle the layer depends on whether it is a sprite or not. if (!t_control -> layer_issprite()) { From 8d18e392517ce44163627f618998f6ff0f1105d0 Mon Sep 17 00:00:00 2001 From: Brian Milby Date: Fri, 3 Aug 2018 21:55:08 -0500 Subject: [PATCH 20/46] Update .gitignore to exclude more build files Added/modified lines to remove additional files from being recognized as candidates for committing to the repository. tests/lcs/extensions/... - By adding `**` the the front of the extensions exclusions, it will catch these files as well engine/src/.lci and libscript/src/.lci --- .gitignore | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 7a301693c7e..7ad1add4d8e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,11 +20,12 @@ encryptedstack.cpp encryptedstack.h stacksecurity_encrypted.cpp util/perfect/perfect.linux-* -extensions/*/*/*.xml -extensions/*/*/*.lci -extensions/*/*/*.lcm -extensions/*/*/*.lce -extensions/*/*/api.lcdoc +**/extensions/*/*/*.xml +**/extensions/*/*/*.lci +**/extensions/*/*/*.lcm +**/extensions/*/*/*.lce +**/extensions/*/*/api.lcdoc +*/src/.lci/* # Compiled source and intermediates # ################### From 7c6d8d41f7e0257fb80ddb88eeca48faf8f14a7e Mon Sep 17 00:00:00 2001 From: Trevor DeVore Date: Mon, 6 Aug 2018 07:34:14 -0500 Subject: [PATCH 21/46] Include folders in iOS extension code folders --- docs/notes/bugfix-21468.md | 1 + ide-support/revsblibrary.livecodescript | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 docs/notes/bugfix-21468.md diff --git a/docs/notes/bugfix-21468.md b/docs/notes/bugfix-21468.md new file mode 100644 index 00000000000..7e4c788931f --- /dev/null +++ b/docs/notes/bugfix-21468.md @@ -0,0 +1 @@ +# Include .framework folders in iOS extension code folders diff --git a/ide-support/revsblibrary.livecodescript b/ide-support/revsblibrary.livecodescript index c4056792ae5..a0df9d9f847 100644 --- a/ide-support/revsblibrary.livecodescript +++ b/ide-support/revsblibrary.livecodescript @@ -2573,7 +2573,7 @@ private command __UpdateSettingsFromCodeFolder pPath, pCodeFolderName, pPlatform appendToStringList tFolderPath & slash & tLine, xSettings["extension_code_resources"] end repeat - if pPlatform is "mac" then + if pPlatform is among the items of "mac-ios" then local tFolders put folders(tFolderPath) into tFolders filter tFolders without ".*" From bc8ad306cb9c21cc3326d3076e0a38fb659b46de Mon Sep 17 00:00:00 2001 From: Trevor DeVore Date: Mon, 6 Aug 2018 18:14:51 -0500 Subject: [PATCH 22/46] use `among the words` --- ide-support/revsblibrary.livecodescript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide-support/revsblibrary.livecodescript b/ide-support/revsblibrary.livecodescript index a0df9d9f847..ebbd7e485c6 100644 --- a/ide-support/revsblibrary.livecodescript +++ b/ide-support/revsblibrary.livecodescript @@ -2573,7 +2573,7 @@ private command __UpdateSettingsFromCodeFolder pPath, pCodeFolderName, pPlatform appendToStringList tFolderPath & slash & tLine, xSettings["extension_code_resources"] end repeat - if pPlatform is among the items of "mac-ios" then + if pPlatform is among the words of "mac ios" then local tFolders put folders(tFolderPath) into tFolders filter tFolders without ".*" From 43ebc69efe668adf01aea76c83a72e9f650609b5 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Tue, 7 Aug 2018 11:05:38 +1000 Subject: [PATCH 23/46] [[ Bug 21469 ]] Recursively sign frameworks in iOS apps This patch ensures embedded frameworks are correctly signed by recursively signing any framework bundles in the app bundle before signing the app itself. --- docs/notes/bugfix-21469.md | 1 + .../revsaveasiosstandalone.livecodescript | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 docs/notes/bugfix-21469.md diff --git a/docs/notes/bugfix-21469.md b/docs/notes/bugfix-21469.md new file mode 100644 index 00000000000..c99048ca1b4 --- /dev/null +++ b/docs/notes/bugfix-21469.md @@ -0,0 +1 @@ +# Ensure iOS apps with embedded frameworks are correctly signed \ No newline at end of file diff --git a/ide-support/revsaveasiosstandalone.livecodescript b/ide-support/revsaveasiosstandalone.livecodescript index 34178634262..70878a40350 100644 --- a/ide-support/revsaveasiosstandalone.livecodescript +++ b/ide-support/revsaveasiosstandalone.livecodescript @@ -801,7 +801,8 @@ private command revSaveAsMobileStandaloneMain pStack, pAppBundle, pTarget, pSett --try -- Perform the codesigning of the main bundle local tResult - put shell("/usr/bin/codesign --verbose -f -s" && quote & tCertificate & quote && \ + __CodesignFrameworks pAppBundle, tCertificate, tEntitlementsFile + put shell("/usr/bin/codesign --deep --verbose -f -s" && quote & tCertificate & quote && \ "--entitlements" && quote & tEntitlementsFile & quote && \ quote & pAppBundle & quote) into tResult -- MM-2012-10-25: [[ Bug ]] try catch finally oddness meant that any errors here were being ignored. @@ -817,6 +818,23 @@ private command revSaveAsMobileStandaloneMain pStack, pAppBundle, pTarget, pSett end if end revSaveAsMobileStandaloneMain +private command __CodesignFrameworks pPath, pCertificate, pEntitlements + local tFrameworks + put folders(pPath) into tFrameworks + filter tFrameworks with "*.framework" + repeat for each line tFramework in tFrameworks + __CodesignFrameworks pPath & "/" & tFramework & "/Frameworks", pCertificate, pEntitlements + + local tResult + put shell("/usr/bin/codesign --deep --verbose -f -s" && quote & pCertificate & quote && \ + "--entitlements" && quote & pEntitlements & quote && \ + quote & pPath & "/" & tFramework & quote) into tResult + if not (tResult contains "signed bundle" or tResult contains "signed app bundle") then + throw "codesigning failed with" && tResult + end if + end repeat +end __CodesignFrameworks + command revSaveAsMobileDeployer pDeployAppBundle, pAppBundle, pAppName, pAppId, pAppExecutables create folder pDeployAppBundle create folder pDeployAppBundle & slash & "Contents" From a11b4d4817cbc2870f5ff7d331c0ee8fd6ec9f19 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Tue, 7 Aug 2018 20:35:14 +1000 Subject: [PATCH 24/46] [[ Bug ]] Fix definition of natural float on 64 bit systems Natural float on 64 bit systems should be double rather than float. --- libfoundation/src/foundation-foreign.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfoundation/src/foundation-foreign.cpp b/libfoundation/src/foundation-foreign.cpp index 4900cea38a1..a42cc8c62c2 100644 --- a/libfoundation/src/foundation-foreign.cpp +++ b/libfoundation/src/foundation-foreign.cpp @@ -148,7 +148,7 @@ typedef float natural_float_t; #elif defined(__64_BIT__) typedef uint64_t natural_uint_t; typedef int64_t natural_sint_t; -typedef float natural_float_t; +typedef double natural_float_t; #else #error Bitness of target not defined #endif From 7f4f1857f683cd1d4a132802ef3edaf109ad48f4 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 7 Aug 2018 13:25:50 +0100 Subject: [PATCH 25/46] [9.0.2-rc-1] Updated version --- version | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/version b/version index 12491871bcd..2a6d041c6b3 100644 --- a/version +++ b/version @@ -1,6 +1,6 @@ -BUILD_REVISION = 15100 +BUILD_REVISION = 15150 BUILD_MAJOR_VERSION = 9 BUILD_MINOR_VERSION = 0 -BUILD_POINT_VERSION = 1 -BUILD_SHORT_VERSION = 9.0.1-rc-1 -BUILD_LONG_VERSION = 9.0.1.15100 (RC 1) +BUILD_POINT_VERSION = 2 +BUILD_SHORT_VERSION = 9.0.2-rc-1 +BUILD_LONG_VERSION = 9.0.2.15150 (RC 1) From 7f5d41066705bcccbfa0235c2f66ed4983e07c7d Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Mon, 13 Aug 2018 13:36:06 +0100 Subject: [PATCH 26/46] [[Bug 21488]] Check 'uname -m' if on Linux and 'uname -p' is unknown Fixed bug 21488, where on some Linux systems the Makefile is unable to automatically determine the architecture to build for. This is due to the Makefile using 'uname -p', which can return 'unknown' in some cases. Fixed by adding an additional case statement into the Makefile that checks 'uname -m' if 'unknown' is returned from 'uname -p'. --- Makefile.common | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.common b/Makefile.common index 81939644dfa..864c64bb688 100644 --- a/Makefile.common +++ b/Makefile.common @@ -43,6 +43,10 @@ guess_linux_arch_script := \ case `uname -p` in \ x86_64) echo x86_64 ;; \ x86|i*86) echo x86 ;; \ + unknown) case `uname -m` in \ + x86_64) echo x86_64 ;; \ + x86|i*86) echo x86 ;; \ + esac ;; \ esac guess_linux_arch := $(shell $(guess_linux_arch_script)) From 21c132b5a1169e49d10b5762ba5f05c09cb635b7 Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Mon, 13 Aug 2018 14:08:12 +0100 Subject: [PATCH 27/46] [[Bug 21488]] Added documentation note --- docs/notes/bugfix-21488.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/notes/bugfix-21488.md diff --git a/docs/notes/bugfix-21488.md b/docs/notes/bugfix-21488.md new file mode 100644 index 00000000000..7a43ae2df67 --- /dev/null +++ b/docs/notes/bugfix-21488.md @@ -0,0 +1 @@ +# Fix automatic architecture detection on some Linux systems From 8f04abe8416235660ad05caf2340574006dab5cf Mon Sep 17 00:00:00 2001 From: Gregory Miller Date: Mon, 13 Aug 2018 09:28:07 -0400 Subject: [PATCH 28/46] Update ParseStringAsNumber dictionary (#6627) Examples provided in ParseStringAsNumber were incorrect --- libscript/src/arithmetic.lcb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libscript/src/arithmetic.lcb b/libscript/src/arithmetic.lcb index a83fb3f863a..d3ebe541625 100644 --- a/libscript/src/arithmetic.lcb +++ b/libscript/src/arithmetic.lcb @@ -590,12 +590,13 @@ The result: parsed as a number, or nothing. Example: variable tString as String put "5.6" into tString - parse tString as Number -- the result is 5.6 + parse tString as number -- the result is 5.6 Example: variable tResult as optional String variable tNum as optional Number - parse "aaaa" as Number into tNum + + parse "aaaa" as number into tNum if tNum is nothing then put "unable to parse string" into tResult From 7e3c2bbb1338cc42a6448cac86873e368805fefc Mon Sep 17 00:00:00 2001 From: livecodeali Date: Wed, 15 Aug 2018 16:05:55 +0100 Subject: [PATCH 29/46] [[ Bug 21496 ]] Ensure emscripten startup_script is suitable for capsule section Previously the emscripten startup script was a startup handler for a boot stack. Now that emscripten deploy uses the deploy command and capsule format, it needs to be a script snippet (that will ultimately be placed in a generated `on message` handler which is called on startup). --- docs/notes/bugfix-21496.md | 1 + ...emscripten-startup-template.livecodescript | 68 +++++++++---------- ...vsaveasemscriptenstandalone.livecodescript | 6 +- 3 files changed, 34 insertions(+), 41 deletions(-) create mode 100644 docs/notes/bugfix-21496.md diff --git a/docs/notes/bugfix-21496.md b/docs/notes/bugfix-21496.md new file mode 100644 index 00000000000..89812e0345b --- /dev/null +++ b/docs/notes/bugfix-21496.md @@ -0,0 +1 @@ +# Ensure emscripten aux stacks are loaded on startup diff --git a/engine/rsrc/emscripten-startup-template.livecodescript b/engine/rsrc/emscripten-startup-template.livecodescript index 3638d194e57..337612d6959 100644 --- a/engine/rsrc/emscripten-startup-template.livecodescript +++ b/engine/rsrc/emscripten-startup-template.livecodescript @@ -1,4 +1,3 @@ -script "__startup" constant kEngineVersion = "@ENGINE_VERSION@" -- Directories that engine expects to normally be present @@ -7,41 +6,38 @@ constant kStandardFolders = "/tmp:/livecode:/boot:/boot/standalone:/boot/fonts" -- Directory containing the initial stack files constant kStartupFolder = "/boot/standalone" -on startup - local tError, tFolder - try - ---------------------------------------------------------------- - -- Create standard filesystem layout - set the itemdelimiter to ":" - repeat for each item tFolder in kStandardFolders - if there is not a folder tFolder then - create folder tFolder - if the result is not empty then - throw the result - end if +local tError, tFolder +try + ---------------------------------------------------------------- + -- Create standard filesystem layout + set the itemdelimiter to ":" + repeat for each item tFolder in kStandardFolders + if there is not a folder tFolder then + create folder tFolder + if the result is not empty then + throw the result end if - end repeat - - ------------------------------------------------------------- - -- Validate engine version - if the version is not kEngineVersion then - throw "Engine mismatch: found" && the version & ", expected" && kEngineVersion end if - - - @STARTUP_SCRIPT@ - - catch tError - end try - - -- Set the initial working directory to the directory that contains - -- the initial stack. - set the defaultfolder to kStartupFolder - - -- Try to print something vaguely helpful to the the log - if tError is not empty then - write "startup failed:" && tError & return to stderr + end repeat + + ------------------------------------------------------------- + -- Validate engine version + if the version is not kEngineVersion then + throw "Engine mismatch: found" && the version & ", expected" && kEngineVersion end if - - return tError -end startup + + + @STARTUP_SCRIPT@ + +catch tError +end try + +-- Try to print something vaguely helpful to the the log +if tError is not empty then + write "startup failed:" && tError & return to stderr + throw tError +end if + +-- Set the initial working directory to the directory that contains +-- the initial stack. +set the defaultfolder to kStartupFolder diff --git a/ide-support/revsaveasemscriptenstandalone.livecodescript b/ide-support/revsaveasemscriptenstandalone.livecodescript index 6cb19c822a6..deeafe06bcf 100644 --- a/ide-support/revsaveasemscriptenstandalone.livecodescript +++ b/ide-support/revsaveasemscriptenstandalone.livecodescript @@ -253,13 +253,9 @@ private function getStartupScript pGeneratedStartupScript throw tTemplateFile & ":" && the result end if close file tTemplateFile - - -- Trim to the actual script - delete line 1 of tScript - + -- Make substitutions in the startup script replace "@ENGINE_VERSION@" with the version in tScript - replace "@MODULE_VERSION@" with extensionLCCompileVersion() in tScript replace "@STARTUP_SCRIPT@" with pGeneratedStartupScript in tScript return tScript end getStartupScript From 016f200bce13f16fc24a095bee61409b75d05a52 Mon Sep 17 00:00:00 2001 From: livecodeali Date: Wed, 15 Aug 2018 16:10:33 +0100 Subject: [PATCH 30/46] [[ Bug 21417 ]] Remove externals list from emscripten deploy params Now that the deploy command is used on emscripten, we need to empty the externals deploy param as they are not supported for emscripten builds. --- docs/notes/bugfix-21417.md | 1 + ide-support/revsaveasemscriptenstandalone.livecodescript | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 docs/notes/bugfix-21417.md diff --git a/docs/notes/bugfix-21417.md b/docs/notes/bugfix-21417.md new file mode 100644 index 00000000000..e0c98c759f6 --- /dev/null +++ b/docs/notes/bugfix-21417.md @@ -0,0 +1 @@ +# Don't include any externals in emscripten standalones diff --git a/ide-support/revsaveasemscriptenstandalone.livecodescript b/ide-support/revsaveasemscriptenstandalone.livecodescript index 6cb19c822a6..fb288076a14 100644 --- a/ide-support/revsaveasemscriptenstandalone.livecodescript +++ b/ide-support/revsaveasemscriptenstandalone.livecodescript @@ -202,7 +202,10 @@ private command storeDeployedStack pZip, pDeployPath, pBuildFolder, pMainStack, put tTempStackPath into pDeployParams["stackfile"] put tTempDeployPath into pDeployParams["output"] put empty into pDeployParams["engine"] - + + // Externals are not yet supported in emscripten builds + put empty into pDeployParams["externals"] + ---------- Perform standalone deployment logDebug "deploy", "Deploying standalone" From 964d263d729b746dae105d777af2a492909f1505 Mon Sep 17 00:00:00 2001 From: Monte Goulding Date: Thu, 16 Aug 2018 08:47:01 +1000 Subject: [PATCH 31/46] [[ Bug 21396 ]] Fix crash on startup in iOS 12 beta This patch fixes an issue where the view layer appears to be retaining the `CGDataProvider` from an image when it is drawn via `CGContextDrawImage`. As we were freeing the raster directly after the draw the `CALayer` could not access it from the `CGDataProvider` when rendering causing a crash. This patch therefore changes the behavior of `MCGRasterCreateCGDataProvider` where previously when calling it with the copy parameter `false` it would be left to the caller to free the buffer the data provider now takes ownership of it and it is freed via the data provider free callback. As a consequence of the change custom cursor creation on mac now copies the buffer for simplicity. --- docs/notes/bugfix-21396.md | 1 + engine/src/cgimageutil.cpp | 6 ++++-- engine/src/mac-cursor.mm | 2 +- engine/src/mac-surface.mm | 1 - engine/src/mbliphonegfx.mm | 20 ++++++++++++++------ 5 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 docs/notes/bugfix-21396.md diff --git a/docs/notes/bugfix-21396.md b/docs/notes/bugfix-21396.md new file mode 100644 index 00000000000..c3b4faed0b7 --- /dev/null +++ b/docs/notes/bugfix-21396.md @@ -0,0 +1 @@ +# Fix crash on startup in iOS 12 beta \ No newline at end of file diff --git a/engine/src/cgimageutil.cpp b/engine/src/cgimageutil.cpp index fc09c878f08..573343b62d0 100644 --- a/engine/src/cgimageutil.cpp +++ b/engine/src/cgimageutil.cpp @@ -114,7 +114,7 @@ bool MCGRasterCreateCGDataProvider(const MCGRaster &p_raster, const MCGIntegerRe t_width = p_src_rect.size.width; t_height = p_src_rect.size.height; - const uint8_t *t_src_ptr = (uint8_t*)MCGRasterGetPixelPtr(p_raster, t_x, t_y); + uint8_t *t_src_ptr = (uint8_t*)MCGRasterGetPixelPtr(p_raster, t_x, t_y); uint32_t t_dst_stride; @@ -125,8 +125,10 @@ bool MCGRasterCreateCGDataProvider(const MCGRaster &p_raster, const MCGIntegerRe if (!p_copy) { t_dst_stride = p_raster.stride; - t_data_provider = CGDataProviderCreateWithData(nil, t_src_ptr, t_height * p_raster.stride, nil); + t_data_provider = CGDataProviderCreateWithData(nil, t_src_ptr, t_height * p_raster.stride, __CGDataProviderDeallocate); t_success = t_data_provider != nil; + if (!t_success) + MCMemoryDeallocate(t_src_ptr); } else { diff --git a/engine/src/mac-cursor.mm b/engine/src/mac-cursor.mm index 31d2aeae782..135c6d5007f 100644 --- a/engine/src/mac-cursor.mm +++ b/engine/src/mac-cursor.mm @@ -137,7 +137,7 @@ void MCPlatformCreateCustomCursor(MCImageBitmap *p_image, MCPoint p_hotspot, MCP t_cursor -> is_standard = false; CGImageRef t_cg_image; - /* UNCHECKED */ MCImageBitmapToCGImage(p_image, false, false, t_cg_image); + /* UNCHECKED */ MCImageBitmapToCGImage(p_image, true, false, t_cg_image); // Convert the CGImage into an NSIMage NSImage *t_cursor_image; diff --git a/engine/src/mac-surface.mm b/engine/src/mac-surface.mm index cccbaa9149c..559c0b58ddb 100644 --- a/engine/src/mac-surface.mm +++ b/engine/src/mac-surface.mm @@ -317,7 +317,6 @@ CGRect MCMacFlipCGRect(const CGRect &p_rect, uint32_t p_surface_height) // IM-2014-10-03: [[ Bug 13432 ]] Render with copy blend mode to replace destination alpha with the source alpha. MCMacRenderRasterToCG(m_cg_context, t_dst_rect, m_raster, MCGRectangleMake(0, 0, m_raster.width, m_raster.height), 1.0, kMCGBlendModeCopy); - free(m_raster . pixels); m_raster . pixels = nil; } diff --git a/engine/src/mbliphonegfx.mm b/engine/src/mbliphonegfx.mm index 22ac7370a2a..a75861d9f02 100644 --- a/engine/src/mbliphonegfx.mm +++ b/engine/src/mbliphonegfx.mm @@ -102,7 +102,7 @@ static void do_update(void *p_dirty) MCGRegionRef m_region; bool m_own_region; - virtual void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride) = 0; + virtual void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride, bool &x_taken) = 0; public: MCIPhoneStackSurface(MCGRegionRef p_region) @@ -197,10 +197,16 @@ void UnlockPixels(MCGIntegerRectangle p_area, MCGRaster& p_raster, bool p_update if (p_raster . pixels == nil) return; + bool t_taken = false; + if (p_update) - FlushBits(p_area, p_raster . pixels, p_raster . stride); + FlushBits(p_area, p_raster . pixels, p_raster . stride, t_taken); + + if (!t_taken) + { + free(p_raster.pixels); + } - free(p_raster . pixels); } bool Composite(MCGRectangle p_dst_rect, MCGImageRef p_src, MCGRectangle p_src_rect, MCGFloat p_alpha, MCGBlendMode p_blend) @@ -337,7 +343,7 @@ void UnlockTarget(void) protected: // MM-2014-07-31: [[ ThreadedRendering ]] Updated to pass in the area we wish to draw. - void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride) + void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride, bool &x_taken) { void *t_target; if (!LockTarget(kMCStackSurfaceTargetCoreGraphics, t_target)) @@ -368,6 +374,8 @@ void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride) if (MCGRasterToCGImage(t_raster, MCGIntegerRectangleMake(0, 0, p_area.size.width, p_area.size.height), t_colorspace, false, false, t_image)) { + x_taken = true; + CGContextDrawImage(t_context, CGRectMake((float)p_area.origin.x, (float)(m_height - (p_area.origin.y + p_area.size.height)), (float)p_area.size.width, (float)p_area.size.height), t_image); CGImageRelease(t_image); } @@ -521,7 +529,7 @@ void UnlockTarget(void) protected: // MM-2014-07-31: [[ ThreadedRendering ]] Updated to pass in the area we wish to draw. - void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride) + void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride, bool& x_taken) { GLuint t_texture; glGenTextures(1, &t_texture); @@ -582,7 +590,7 @@ void FlushBits(MCGIntegerRectangle p_area, void *p_bits, uint32_t p_stride) } glDeleteTextures(1, &t_texture); - } + } }; @implementation MCIPhoneOpenGLDisplayView From 90ae2ab778d2997064856302b95bd1350644b92c Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Thu, 16 Aug 2018 14:30:09 +0100 Subject: [PATCH 32/46] [[Docfix]] Added undocumented TestSkipIf requirements The testing.md file which explains the process for writing tests for the various aspects of LiveCode contains a section on the TestSkipIf command, which skips a test if a certain requirment is met. However not all the available requirement options that TestSkipIf provides were documented. Information for these requirement options has now been added. --- docs/development/testing.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/development/testing.md b/docs/development/testing.md index 2be01270b59..9cf06a10d8b 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -61,11 +61,13 @@ Before running each test command, the test framework inserts a test library stac * `TestAssert pDescription, pExpectTrue`: Make a test assertion. The test is recorded as a failure if *pExpectTrue* is false. *pDescription* should be a short string that describes the test (e.g. "clipboard is clear"). * `TestSkip pDescription, pReasonSkipped`: Record a test as having been skipped. *pReasonSkipped* should be a short explanation of why the test was skipped (e.g. "not supported on Windows"). * `TestSkipIf pRequirement, pOptions`: Skip a test if the requirements -are met. `pOptions` varies depending on the `pRequirement` enum. The -following requirements are implemented: - - `ide` - the IDE repo is available. No options. +are met. `pOptions` varies depending on the `pRequirement` enum (if no +options are explicitly specified then no options are available for that +particular `pRequirement`. The following requirements are implemented: + - `ide` - the IDE repo is available - `lcb` - LCB compilation supported - - `docs` - the docs are available. No options. + - `docs` - the docs are available + - `standalone` - the test is running in the standalone test runner - `securityPermissions` - Option `set` to skip if a test should not set the `securityPermissions` - `platform` - options are comma delimited platform strings @@ -73,6 +75,19 @@ following requirements are implemented: - `stack` - options are comma delimited stack names to test if they are available - `environment` - options are comma delimited environment strings + - `clipboard` - access to the clipboard is available + - `wait` - the `wait` command is available and works as expected + - `security` - the security module is available + - `write` - write access to the filesystem is available + - `ui` - the test is running in a graphical environment (as opposed + to the command line) + - `desktop` - the test is running on a desktop computer + - `mobile` - the test is running on a mobile device + - `external` - an external module can be loaded/used. Options are a + comma delimited list of external module names + - `database` - an database module can be loaded/used. Options are a + comma delimited list of external module names + - `jvm` - the Java Virtual Machine is available * `TestSkipIfNot pRequirement, pOptions`: Skip a test if the requirements are not met. Requirements and options are the same as for `TestSkipIf`. From 82c69ce984dbda106fa4ed41fbb8ff862e53ba77 Mon Sep 17 00:00:00 2001 From: Brian Milby Date: Sat, 18 Aug 2018 00:47:56 -0500 Subject: [PATCH 33/46] [[ Bug 21503 ]] Tree widget - prevent value removal on key addition Current operation of the tree widget will delete the value stored in a key if the "+" is clicked to add a new sub-key and it is not already an array. This change alters the behavior such that when the "+" is clicked, if the current key is not already an array, then the existing value is moved to the new sub-key that is created. --- extensions/widgets/treeview/notes/21503.md | 1 + extensions/widgets/treeview/treeview.lcb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 extensions/widgets/treeview/notes/21503.md diff --git a/extensions/widgets/treeview/notes/21503.md b/extensions/widgets/treeview/notes/21503.md new file mode 100644 index 00000000000..efbb95cbcf2 --- /dev/null +++ b/extensions/widgets/treeview/notes/21503.md @@ -0,0 +1 @@ +# [21503] Prevent value removal on key addition \ No newline at end of file diff --git a/extensions/widgets/treeview/treeview.lcb b/extensions/widgets/treeview/treeview.lcb index e7641189506..588941000ee 100644 --- a/extensions/widgets/treeview/treeview.lcb +++ b/extensions/widgets/treeview/treeview.lcb @@ -759,7 +759,7 @@ public handler OnMouseDown() returns nothing end if end handler -public handler OnMouseMove() returns nothing +public handler OnMouseMove() returns nothing if scrollDragging() then variable tScrollPositionRatio as Real scrollbarDrag(mViewHeight) @@ -1511,7 +1511,7 @@ private handler addKey(in pListElt as Integer, in pPath as List, in pLevel as In else variable tArray as Array put the empty array into tArray - put "" into tArray[1 formatted as string] + put tElement into tArray[1 formatted as string] put tArray into xArray[pPath[pLevel + 1]] put false into xList[pListElt]["leaf"] end if From 27d509605ba27030f87c6bb6537df341b6203f6b Mon Sep 17 00:00:00 2001 From: Ian Macphail Date: Mon, 20 Aug 2018 15:37:56 +0100 Subject: [PATCH 34/46] [[ Bug 21507 ]] Fix incorrect parameter order calling MCMathEvalAtan2Number from atan2 --- libscript/src/math.lcb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscript/src/math.lcb b/libscript/src/math.lcb index deb3c787a7a..0774cffc2bd 100644 --- a/libscript/src/math.lcb +++ b/libscript/src/math.lcb @@ -322,7 +322,7 @@ end syntax public handler atan2(in pY as Number, in pX as Number) returns Number variable tVar as Number unsafe - MCMathEvalAtan2Number(pX, pY, tVar) + MCMathEvalAtan2Number(pY, pX, tVar) end unsafe return tVar end handler From a426d7afbf26c6888209453321c3ce4600a73627 Mon Sep 17 00:00:00 2001 From: Ian Macphail Date: Mon, 20 Aug 2018 15:53:17 +0100 Subject: [PATCH 35/46] [[ Bug 21507 ]] Add release note --- docs/lcb/notes/21507.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/lcb/notes/21507.md diff --git a/docs/lcb/notes/21507.md b/docs/lcb/notes/21507.md new file mode 100644 index 00000000000..5e6dc61164d --- /dev/null +++ b/docs/lcb/notes/21507.md @@ -0,0 +1 @@ +# [21507] Fix incorrect parameter order in com.livecode.math atan2 function From f3b6258eb2d65d83603461697b1febd713ba45eb Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 21 Aug 2018 10:24:34 +0300 Subject: [PATCH 36/46] [21500] Fix crash when moving a group before calling quit --- engine/src/globals.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/globals.cpp b/engine/src/globals.cpp index d2bad3c3286..809ed0a7672 100644 --- a/engine/src/globals.cpp +++ b/engine/src/globals.cpp @@ -1342,6 +1342,7 @@ int X_close(void) while (MCsavegroupptr != NULL) { MCControl *gptr = MCsavegroupptr->remove(MCsavegroupptr); + gptr -> removereferences(); delete gptr; } From d4fcb19f8a105d8834eda3619b5bd2471995bf36 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 21 Aug 2018 10:26:05 +0300 Subject: [PATCH 37/46] [21500] Added bugfix note --- docs/notes/bugfix-21500.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/notes/bugfix-21500.md diff --git a/docs/notes/bugfix-21500.md b/docs/notes/bugfix-21500.md new file mode 100644 index 00000000000..5472fb7de42 --- /dev/null +++ b/docs/notes/bugfix-21500.md @@ -0,0 +1 @@ +# Fix crash when moving a group before calling quit From c0f3485134cfb2053e2492a532e2a050c801f47a Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 21 Aug 2018 12:07:51 +0300 Subject: [PATCH 38/46] [21500] Added tests --- .../core/engine/_ungroupandquit.livecodescript | 8 ++++++++ tests/lcs/core/engine/engine.livecodescript | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/lcs/core/engine/_ungroupandquit.livecodescript diff --git a/tests/lcs/core/engine/_ungroupandquit.livecodescript b/tests/lcs/core/engine/_ungroupandquit.livecodescript new file mode 100644 index 00000000000..2365b16fcfe --- /dev/null +++ b/tests/lcs/core/engine/_ungroupandquit.livecodescript @@ -0,0 +1,8 @@ +script "_ungroupandquit" +on startup + create button "one" + create button "two" + group button "one" and button "two" + ungroup the last group + quit 0 +end startup \ No newline at end of file diff --git a/tests/lcs/core/engine/engine.livecodescript b/tests/lcs/core/engine/engine.livecodescript index c4a1494063a..5ec52b2d272 100644 --- a/tests/lcs/core/engine/engine.livecodescript +++ b/tests/lcs/core/engine/engine.livecodescript @@ -501,3 +501,19 @@ wait 2 ticks TestAssert "the ticks change with time", the ticks - tTime >= 2 end TestTicks +on TestUngroupAndQuit + -- Bug 21500: run a subprocess in which we ungroup a group and + -- then quit, to test that it no longer crashes + local tStackToRun, tOptions + put the effective filename of me into tStackToRun + set the itemdelimiter to slash + if the environment is not "server" then + put "_ungroupandquit.livecodescript" into item -1 of tStackToRun + if the environment contains "command line" then + put "-ui" into tOptions + end if + end if + TestRunStack tOptions, tStackToRun + TestAssert "ungroup does not crash on quit", the result is empty +end TestUngroupAndQuit + From 9a163766dcca4527380dc44376f23d3fdd0cdbf5 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 21 Aug 2018 13:10:51 +0300 Subject: [PATCH 39/46] Updated bugfix note --- docs/notes/bugfix-21500.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/notes/bugfix-21500.md b/docs/notes/bugfix-21500.md index 5472fb7de42..ba3551da1f9 100644 --- a/docs/notes/bugfix-21500.md +++ b/docs/notes/bugfix-21500.md @@ -1 +1 @@ -# Fix crash when moving a group before calling quit +# Fix crash when ungrouping a group before calling quit From b70a409911ffaeaa69c941f5da3e56c2fbde7cfc Mon Sep 17 00:00:00 2001 From: Brian Milby Date: Tue, 21 Aug 2018 19:27:25 -0500 Subject: [PATCH 40/46] [[ Bug 21503 ]] Tree widget - prevent value removal on key addition Adjust code to display a dialog box to allow the user to choose how to handle the situation where a new array could remove an existing value. --- extensions/widgets/treeview/notes/21503.md | 2 +- extensions/widgets/treeview/treeview.lcb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/extensions/widgets/treeview/notes/21503.md b/extensions/widgets/treeview/notes/21503.md index efbb95cbcf2..e333f747434 100644 --- a/extensions/widgets/treeview/notes/21503.md +++ b/extensions/widgets/treeview/notes/21503.md @@ -1 +1 @@ -# [21503] Prevent value removal on key addition \ No newline at end of file +# [21503] Prevent accidental value removal on key addition \ No newline at end of file diff --git a/extensions/widgets/treeview/treeview.lcb b/extensions/widgets/treeview/treeview.lcb index 588941000ee..7cb16855381 100644 --- a/extensions/widgets/treeview/treeview.lcb +++ b/extensions/widgets/treeview/treeview.lcb @@ -1509,6 +1509,20 @@ private handler addKey(in pListElt as Integer, in pPath as List, in pLevel as In if tElement is an array then createNewKey(xArray[pPath[pLevel + 1]]) else + if tElement is not "" then + variable tPrompt as String + combine pPath with "][" + put "The array element at path [" & the result & "] is not empty. " & \ + "Would you like to replace it with an empty array or " & \ + "move it to the first element?" into tPrompt + execute script "answer \q" & tPrompt & \ + "\q with Cancel or Replace or Move; return it" + if the result is "Replace" then + put "" into tElement + else if the result is "Cancel" then + return + end if + end if variable tArray as Array put the empty array into tArray put tElement into tArray[1 formatted as string] From 0b6e6cb37fee156cd344764de143a9a3144b6fb9 Mon Sep 17 00:00:00 2001 From: livecodesam Date: Thu, 23 Aug 2018 11:48:20 +0100 Subject: [PATCH 41/46] Update mobileGetLocationHistory.lcdoc --- docs/dictionary/function/mobileGetLocationHistory.lcdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dictionary/function/mobileGetLocationHistory.lcdoc b/docs/dictionary/function/mobileGetLocationHistory.lcdoc index 95af899270e..5cd347a1335 100644 --- a/docs/dictionary/function/mobileGetLocationHistory.lcdoc +++ b/docs/dictionary/function/mobileGetLocationHistory.lcdoc @@ -74,6 +74,6 @@ References: mobileSetLocationHistoryLimit (command), mobileStopTrackingSensor (command), mobileStartTrackingSensor (command), mobileGetLocationHistoryLimit (function), mobileSensorAvailable (function), mobileSensorReading (function), -mobileLocationAuthorizationStatus (function), array (glossary), +mobileLocationAuthorizationStatus (function), locationChanged (message), trackingError (message) From f9bdb2b913300e672332ae7bed1b5d9898fd8f42 Mon Sep 17 00:00:00 2001 From: livecodesam Date: Thu, 23 Aug 2018 11:48:28 +0100 Subject: [PATCH 42/46] Update mobileSetLocationHistoryLimit.lcdoc --- docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc b/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc index 0649d21d193..25aaa4b2e5e 100644 --- a/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc +++ b/docs/dictionary/command/mobileSetLocationHistoryLimit.lcdoc @@ -66,10 +66,10 @@ the last sample in the history). e.g. References: mobileStopTrackingSensor (command), -mobileStartTrackingSensor (command), function (control structure), +mobileStartTrackingSensor (command), mobileGetLocationHistory (function), mobileGetLocationHistoryLimit (function), mobileSensorAvailable (function), mobileSensorReading (function), -mobileLocationAuthorizationStatus (function), array (glossary), +mobileLocationAuthorizationStatus (function), locationChanged (message), trackingError (message) From aee1042b31fa6fdbb92c7c0af2306be5a0e8eaa2 Mon Sep 17 00:00:00 2001 From: livecodesam Date: Fri, 24 Aug 2018 12:57:10 +0100 Subject: [PATCH 43/46] [Bugfix-21494] Correct Round entry --- docs/dictionary/function/round.lcdoc | 12 ++++++------ docs/notes/bugfix-21494.md | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 docs/notes/bugfix-21494.md diff --git a/docs/dictionary/function/round.lcdoc b/docs/dictionary/function/round.lcdoc index b1e5cb98588..89fd57ab389 100644 --- a/docs/dictionary/function/round.lcdoc +++ b/docs/dictionary/function/round.lcdoc @@ -47,12 +47,12 @@ the up if positive, down if . (To round off numbers without introducing any statistical upward bias, use the instead.) -A positive indicates a place to the right of the , and a indicates a place to the left. For -example, 1 rounds off to the nearest tenth, 2 rounds off to the nearest -hundredth, -1 rounds off by ten, and so on. If you don't specify a -, zero is used, meaning that the is rounded off to a -whole number. +A positive indicates a place to the right of the +, and a indicates a place to the +left. For example, 1 rounds off to the nearest tenth, 2 rounds off to +the nearest hundredth, -1 rounds off by ten, and so on. If you don't +specify a , zero is used, meaning that the is +rounded off to a whole number. >*Note:* The is equivalent to > "round" . diff --git a/docs/notes/bugfix-21494.md b/docs/notes/bugfix-21494.md new file mode 100644 index 00000000000..2a60c14d9a6 --- /dev/null +++ b/docs/notes/bugfix-21494.md @@ -0,0 +1 @@ +# Correct missing text issue in the ROund function dictionary entry. From c9d0b41086cb1deae483bd55ab672a09f02a7903 Mon Sep 17 00:00:00 2001 From: livecodesam Date: Fri, 24 Aug 2018 12:59:44 +0100 Subject: [PATCH 44/46] Update bugfix-21494.md --- docs/notes/bugfix-21494.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/notes/bugfix-21494.md b/docs/notes/bugfix-21494.md index 2a60c14d9a6..d013ef1f4c1 100644 --- a/docs/notes/bugfix-21494.md +++ b/docs/notes/bugfix-21494.md @@ -1 +1 @@ -# Correct missing text issue in the ROund function dictionary entry. +# Correct missing text issue in the Round function dictionary entry. From befc4599dfef0cfa2da61f24a27d85dbdd1a822c Mon Sep 17 00:00:00 2001 From: Brian Milby Date: Sat, 25 Aug 2018 11:59:27 -0500 Subject: [PATCH 45/46] [[ Bug 21527 ]] Include iPadPro splash image in plist file Adjusted `revCreateMobilePlist` handler to include the iPadPro splash images in the plist file so that they are recognized by the device. --- docs/notes/bugfix-21527.md | 1 + ide-support/revsaveasiosstandalone.livecodescript | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 docs/notes/bugfix-21527.md diff --git a/docs/notes/bugfix-21527.md b/docs/notes/bugfix-21527.md new file mode 100644 index 00000000000..f11ed912568 --- /dev/null +++ b/docs/notes/bugfix-21527.md @@ -0,0 +1 @@ +# Include iPadPro splash image in plist file diff --git a/ide-support/revsaveasiosstandalone.livecodescript b/ide-support/revsaveasiosstandalone.livecodescript index 70878a40350..b04d6517178 100644 --- a/ide-support/revsaveasiosstandalone.livecodescript +++ b/ide-support/revsaveasiosstandalone.livecodescript @@ -1707,9 +1707,11 @@ private command revCreateMobilePlist pSettings, pAppBundle, pTarget, pFonts, pPl if 2 is among the items of tDeviceFamily then if tIPadOrientations contains "Portrait" then put "Default-Portrait|Default-Portrait|{768, 1024}|Portrait" & return after tSplashScreens + put "Default-iPadProPortrait|Default-iPadProPortrait|{1024, 1366}|Portrait" & return after tSplashScreens end if if tIPadOrientations contains "Landscape" then put "Default-Landscape|Default-Landscape|{768, 1024}|Landscape" & return after tSplashScreens + put "Default-iPadProLandscape|Default-iPadProLandscape|{1024, 1366}|Landscape" & return after tSplashScreens end if end if From 4eba7960891705510f9798ca3453d6b1c409ab6d Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Mon, 27 Aug 2018 22:11:35 +0300 Subject: [PATCH 46/46] Updated ide submodule ptr --- ide | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide b/ide index 46297e0978a..17feb6e6c03 160000 --- a/ide +++ b/ide @@ -1 +1 @@ -Subproject commit 46297e0978ab3cd8f10c6be3861c72c699590680 +Subproject commit 17feb6e6c034c0364ce93d1e652a25223c45e234