Differences

This shows you the differences between the selected revisions of the page.

2022-09-12 2022-09-12
no summary (188.43.235.177) (hidden) (untrusted) Restored revision 1662982066. Undoing revisions 1662989532, 1662994511, 1662994524, 1662994533, 1662994543, 1662994553, 1662994582, 1662994597, 1662994624. (martin) (hidden)
Line 1: Line 1:
-/* +====== Recent Version History ======
- * Headwind Remote: Open Source Remote Access Software for Android +
- * https://headwind-remote.com +
- +
- * Copyright (C) 2022 headwind-remote.com +
-+
- * Licensed under the Apache License, Version 2.0 (the "License"); +
- * you may not use this file except in compliance with the License. +
- * You may obtain a copy of the License at +
-+
- *      http://www.apache.org/licenses/LICENSE-2.0 +
-+
- * Unless required by applicable law or agreed to in writing, software +
- * distributed under the License is distributed on an "AS IS" BASIS, +
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +
- * See the License for the specific language governing permissions and +
- * limitations under the License. +
- */+
-package com.hmdm.control;+This is a full list of changes for each release of WinSCP. See also [[project_history|Project history]] and [[incompatible_changes|Incompatible changes between versions]].
-import android.app.AlertDialog; +===== [[6.0]] 6.0 (not released yet) ((2022-09-07)) ===== 
-import android.app.Dialog+··* Local file manager mode (two local panels). [[bug>;1893]] 
-import android.content.BroadcastReceiver+··* Ongoing delete operation can be moved to background queue. [[bug>;194]] 
-import android.content.ClipData+··* Showing directory size in file panel. [[bug>;41]] 
-import android.content.ClipboardManager; +··* File checksum calculation support for SCP protocol and SFTP protocol via secondary shell session using shell commands like ''sha256sum''. 
-import android.content.Context+··* Tab titles are shortened to fit window width as needed. [[bug>1423]] 
-import android.content.DialogInterface; +··* Tabs show tooltips with full session name and paths. 
-import android.content.Intent+  * Displaying thanks and transitioning help toolbar message after Store installation over classic installation
-import android.content.IntentFilter+··* Remembering remote directory tree nodes state when switching sessions. [[bug>;1057]] 
-import android.graphics.PixelFormat+··* Support for S3 servers without TLS encryption. [[bug>;1995]] 
-import android.media.projection.MediaProjectionManager; +··* Support for redirected WebDAV downloads (even to other hosts). [[bug>;1667]] 
-import android.os.Build+··* ''Shift''-clicking //New Session// command opens the Login dialog in new WinSCP instance, instead of possibly opening new instance of workspace. 
-import android.os.Bundle+  * Allowed opening all sites in a folder in PuTTY. [[bug>2079]] 
-import android.os.Handler; +··* Allowing environment variables in custom INI file path. [[bug>;2105]] 
-import android.util.DisplayMetrics+··* Private key pattern ''!K'' in PuTTY command-line and custom commands. [[bug>;2107]] 
-import android.util.Log+··* Automatically reconnect when FTP server fails to open data connection with ''426'' code, if it previously worked. [[bug>2110]] 
-import android.view.Gravity+··* Cleaning up temporary WinSCP PuTTY sessions. 
-import android.view.Menu+  * Added import from KiTTY directly to the Import dialog. [[bug>1551]] 
-import android.view.MenuItem; +··* Blocking Windows Rich Edit formatting keyboard shortcuts in Internal editor. [[bug>2108]] 
-import android.view.View; +··* PNG code upgraded to PngComponents 1.9.0. 
-import android.view.WindowManager+··* When switching tabs, prevent visibly scrolling the panels when focusing the last selected file. 
-import android.widget.EditText; +··* Removed the "compression" indicator from the status bar. 
-import android.widget.ImageView+  * Allowed normal behavior of double-click on a file even when resolving of symlinks is disabled. [[bug>;2037]] 
-import android.widget.TextView; +··* Change: ''SessionOptions.WebdavSecure'' renamed to ''SessionOptions.Secure'' (and applies to S3 protocol too). 
-import android.widget.Toast;+··* ''Session.ExecutablePath'' returns detected or actual executable path when not set. [[bug>2055]] 
 +··* Change: Keyboard shortcut for //Command Line// command changed to ''Shift+Ctrl+M'' (''Shift+Ctrl+N'' previously). 
 +··* Preventing construction of .NET assembly internal collection classes, what avoids them being unnecessarily registered for COM. 
 +··* Bug fix: Failure when trying to switch session tabs while previous switch did not complete yet. 
 +  * Bug fix: When importing from FileZilla with KiTTY selected as SSH terminal, host keys were imported from KiTTY instead of FileZilla/PuTTY. 
 +··* Bug fix: Incorrect escaping of values in single-quoted patterns in custom commands.
-import androidx.appcompat.app.AppCompatActivity; +===== [[5.21.4]] 5.21.4 ((2022-09-12)) =====
-import androidx.appcompat.widget.Toolbar; +
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;+
-import com.hmdm.control.janus.SharingEngineJanus;+  * This is Microsoft Store-only release with the following fix: 
 +····* The //Donate// command removed from the //Help// menu to comply with Store App policies.
-public class MainActivity extends AppCompatActivity implements SharingEngineJanus.EventListener, SharingEngineJanus.StateListener {+===== [[5.21.3]] 5.21.3 ((2022-09-06)) =====
-····private ImageView imageViewConnStatus; +··* Translation updated: Ukrainian. 
- ···private TextView textViewConnStatus; + ·* Added new ''me-central-1'' AWS region. 
-····private EditText editTextSessionId; + ·* Bug fix: Site with a stored password protected by master password cannot be opened from command-line. [[bug>;2101]] 
- ···private EditText editTextPassword+ ·* Bug fix: Opening session in new window fails. [[bug>;2104]]
-   private TextView textViewComment; +
-····private TextView textViewConnect+
- ···private TextView textViewSendLink; +
-   private TextView textViewExit;+
-····private ImageView overlayDot; +===== [[5.21.2]] 5.21.2 ((2022-08-08)) =====
-····private Handler handler = new Handler(); +
-····private int overlayDotAlpha; +
-····private int overlayDotDirection = 1;+
-····private Dialog exitOnIdleDialog+··* Translation completed: Farsi. 
- ···private int exitCounter+  * TLS/SSL core upgraded to OpenSSL 1.1.1q. 
- ···private static final int EXIT_PROMPT_SEC = 10;+  * Initial implementation of application logging. 
 +  * Bug fix: ";Hidden files showing toggled" message displays opposite status. 
 + ·* Bug fix: Cannot authenticate to WebDAV server with username containing some special characters. [[bug>;2095]] 
 + ·* Bug fix: Checkbox to set permissions recursively on Properties dialog is missing, when changing owner and group is not supported. [[bug>;2097]] 
 +  * Bug fix: .NET assembly type library cannot be used in WSH. [[bug>2098]]
-····private static final int OVERLAY_DOT_ANIMATION_INCREMENT = 20+===== [[5.21.1]] 5.21.1 ((2022-06-24)) ===== 
- ···private static final int OVERLAY_DOT_ANIMATION_DELAY = 200;+· * Translation completed: Polish. 
 +  * TLS/SSL core upgraded to OpenSSL 1.1.1p. 
 +  * Not offering to create a link to parent directory, when it happens to be selected, when starting to create a link. [[bug>;2091]] 
 + ·* Bug fix: Extension options dialog layout broken on systems with multiple monitors with different text scaling. [[bug>;2090]] 
 +  * Bug fix: Failure when starting parallel FTP background transfers. [[bug>2093]] 
 +  * Bug fix: Directory coloring rules on remote panel do not work. [[bug>2094]]
-····private SharingEngine sharingEngine;+===== [[5.21]] 5.21 ((2022-06-15)) =====
-····private SettingsHelper settingsHelper;+··* Bug fix: Hang when entering small directories with FTP protocol. [[bug>;2087]] 
 +  * Bug fix: Lag when moving files from remote panel using drag&drop. [[bug>2088]] 
 +  * Bug fix: After certain operations, drive that was ever opened in local file panel cannot be safely removed temporarily.
-····private String sessionId+===== [[5.20.4]] 5.20.4 RC ((2022-06-08)) ===== 
-    private String password+   
-    private String adminName;+  * SSH core and SSH private key tools (PuTTYgen and Pageant) upgraded to [[&;url(puttychanges)|PuTTY 0.77]]. It brings the following changes: 
 +    * Pageant: Option ''%%--openssh-config%%'' to allow easy interoperation with Windows's ''ssh.exe''. [[pbug>;win-pageant-openssh-interop]] 
 +    * Bug fix: PuTTYgen's mouse-based entropy collection now handles high-frequency mice without getting confused. [[pbug>;win-puttygen-entropy-rate-limit]] 
 +    * Bug fix: Pageant can now handle large numbers of concurrent connections without hanging or crashing. [[pbug>win-pageant-max-connections-2]] 
 +    * Bug fix: If Pageant is started multiple times simultaneously, the instances should reliably agree on one of them to be the persistent server. [[pbug>win-pageant-concurrent-startup]] 
 +  * Improved error message when FTP server returns malformed response. [[bug>2077]] 
 +  * Translations updated: German and Slovak. 
 +  * Not listing remote directory when downloading file using FTP protocol with overwrite confirmations off. [[bug>2084]] 
 +  * Workaround for calls to system API failing when used first time against some network shares (Samba) with paths over the legacy Windows limit. [[bug>2082]] 
 +  * Workaround for an apparent bug in Windows 11 that prevents WinSCP from stopping Windows going to the sleep mode during transfers. [[bug>2083]] 
 +  * Workaround for specific encoding of commas in filenames (and particularly directory names) by OneDrive WebDAV interface. [[bug>2085]] 
 +  * Bug fix: When transferring a growing file, after its original size is reached, the ''Session.FileTransferProgress'' event starts being triggered continuously. [[bug>2078]] 
 +  * Bug fix: Restored pre-5.20.3 behaviour with MVS systems. [[bug>2086]]
-····private final static String ATTR_SESSION_ID = "sessionId"; +===== [[5.20.3]] 5.20.3 RC ((2022-05-17)) =====
- ···private final static String ATTR_PASSWORD = "password"; +
- ···private final static String ATTR_ADMIN_NAME = "adminName";+
-····private boolean needReconnect = false;+··* Translations completed: Catalan, Czech, Dutch, Finnish, French, German, Hungarian, Italian, Japanese, Korean, Portuguese, Romanian, Russian, Simplified Chinese, Slovak, Spanish, Swedish, Traditional Chinese, Turkish and Ukrainian; and updated: Vietnamese 
 +  * Streaming support in .NET assembly and scripting for FTP protocol. [[bug>1945]] 
 +  * Improved compatibility with MVS systems. [[bug>2069]] 
 +  * New .NET assembly method ''Session.TryGetFileInfo''. Thanks to @RachamimYaakobov. [[bug>2068]] 
 +  * Expanding environment variables in Open Directory/Location Profiles dialogs in local paths. [[bug>909]] 
 +  * Optimized loading of large directories. [[bug>1631]] 
 +  * TLS/SSL core upgraded to OpenSSL 1.1.1o. 
 +  * Installer upgraded to Inno Setup 6.2.1. 
 +  * When group (//Site/Shared//) to which new location profile is added is changed, switching the page to the target group. 
 +  * Preventing occasional exhaustion of resources while testing WinSCP executable version on repeated use of .NET assembly. [[bug>2075]] 
 +  * Bug fix: Capabilities of S3 sessions were not shown. 
 +  * Bug fix: Misplaced warning about unused scripting parameters when ''/rawsettings'' command-line switch is used. [[bug>2070]] 
 +  * Bug fix: File panels malfunction when files are dropped from other application to it. [[bug>2071]] 
 +  * Bug fix: When logging transfer statistics, recent transfer speed was logged instead of average speed of whole transfer. [[bug>2073]] 
 +  * Bug fix: z/OS PDS members without ISPF statistics are omitted in directory listing. [[bug>2076]]
-····private MediaProjectionManager projectionManager;+===== [[5.20.2]] 5.20.2 beta ((2022-04-06)) =====
-····private BroadcastReceiver mSharingServiceReceiver = new BroadcastReceiver() { +··* Translations updated: German and Vietnamese
- ·······@Override +  * SSH core upgraded to pre-release build of [[https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/|PuTTY 0.77]]. (*TODO replace with &url(puttychanges) once 0.77 is released*) \\ It brings the following changes: 
- ·······public void onReceive(Context context, Intent intent) { + ···* Support for HTTP Digest authentication for proxies. [[pbug>http-digestauth]] 
- ···········if (intent == null || intent.getAction() == null) { + ···* Interactive username/password prompts for proxy authentication. [[bug>468]] [[pbug>proxy-password-prompt]] 
- ···············return+· * TLS/SSL core upgraded to OpenSSL 1.1.1n. 
- ···········} + ·* WebDAV core upgraded to neon 0.32.2. 
- ···········if (intent.getAction().equals(Const.ACTION_SCREEN_SHARING_START)) { +· * XML parser upgraded to Expat 2.4.8. 
- ···············notifySharingStart();+· * Allowed uploading edited files over encrypted session. [[bug>1989]] 
 +· * Building .NET assembly in Visual Studio 2019. 
 + ·* Optionally not flashing taskbar button when WinSCP needs attention while in the background. [[bug>;2067]] 
 + ·* In .NET assembly or scripting with "nul" configuration, when WinSCP registry key does not exist, do not write statistics to INI file. [[bug>2066]] 
 + ·* New less prominent icon for //Quit// command. 
 +··* Bug fix: Failure when attempting to switch to an unconnected sessions using keyboard shortcuts while another session is being connected. 
 +··* Bug fix: Removing all custom commands resets the default ones when INI file is used. [[bug>2059]] 
 +· * Bug fix: Failure when changing remote folder using directory tree while previous directory is still loading. [[bug>2060]] 
 + ·* Bug fix: Drive that was ever opened in local file panel cannot be safely removed until WinSCP is closed. [[bug>2061]] 
 +  * Bug fix: //"Optimize connection buffer size"// checkbox was disabled for S3 although it has effect for the protocol. [[bug>2058]] 
 +  * Bug fix: Custom commands menu fail to open. [[bug>2062]] 
 +  * Bug fix: Local drive menu does not reflect some changes. [[bug>2063]] 
 +  * Bug fix: Using drive menu to change to an invalid drive fails silently. 
 +  * Bug fix: Scripting command ''ls'' in FTP session displays timestamps without year even if the server (notably IIS) provided the year, if it did not provide seconds. [[bug>;2065]]
-············} else if (intent.getAction().equals(Const.ACTION_SCREEN_SHARING_STOP)) { +===== [[5.20.1]] 5.20.1 beta ((2022-01-11)) ===== 
- ···············notifySharingStop()+ ·* File masks relative to the root of an operation. [[bug>;2052]] 
- ···············adminName = null+ ·* Private key can be provided as string in .NET assembly and scripting. [[bug>;2044]] 
- ···············updateUI()+ ·* Support for importing key files that are specified using home ''~'' prefix from OpenSSH ''config'' file. [[bug>;2053]] 
- ···············cancelSharingTimeout()+ ·* Translation updated: German
- ···············scheduleExitOnIdle();+  * TLS/SSL core upgraded to OpenSSL 1.1.1m. 
 +  * Commands that do not fit on //Custom Commands// toolbar are presented in drop down menu, instead of a horizontal bar. [[bug>;554]] 
 + ·* First hiding right-most //Custom Commands// toolbar commands that do not fit. 
 +  * Prevent hang when dragging files without drag&;drop shell extensions when some mapped network drive is not available. [[bug>2054]] 
 +  * Added new ''ap-southeast-3'' AWS region. 
 +  * XML parser upgraded to Expat 2.4.2. 
 +  * Bug fix: When initial remote directory specified in the ''open'' command does not exist, the error was silently ignored. 
 +  * Bug fix: File color rules with path mask do not work for local files.
-············} else if (intent.getAction().equals(Const.ACTION_SCREEN_SHARING_FAILED)) +===== [[5.20]] 5.20 beta ((2021-12-02)) =====
-                String message = intent.getStringExtra(Const.EXTRA_MESSAGE); +
-               if (message != null) { +
-                    Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show()+
- ···············} +
-················adminName = null+
-                updateUI(); +
-                cancelSharingTimeout(); +
-                scheduleExitOnIdle();+
-············} else if (intent.getAction().equals(Const.ACTION_CONNECTION_FAILURE)) { +··* Support for ACL for S3 protocol. [[bug>1641]] 
- ···············sharingEngine.setState(Const.STATE_DISCONNECTED)+  * SSH core upgraded to [[&url(puttychanges)|PuTTY 0.76]]. [[bug>1984]] \\ It brings the following changes: 
- ···············Toast.makeText(MainActivity.this, R.string.connection_failure_hint, Toast.LENGTH_LONG).show(); + ···* Support Curve448 key exchange method. [[pbug>curve448]] 
- ···············updateUI();+    * Support Ed448 user and host keys. [[pbug>;ed448]] 
 + ···* Support rsa-sha2-256 and rsa-sha2-512 SSH public key algorithms. [[bug>1952]] [[pbug>rsa-sha2]] 
 +    * Change: SHA-256 fingerprints are not padded anymore. 
 +  * It is possible to import sessions from OpenSSH ''config'' file. [[bug>1896]] 
 +  * Change: Removed support for SSH-1. 
 +  * Optionally keeping symbolic link name in path instead of resolving it with SFTP protocol. [[bug>81]] 
 +  * Improved shortening long paths, when single level name is too long on its own. [[bug>2043]] 
 +  * WebDAV core upgraded to neon 0.32.1. 
 +  * Allow displaying all VMS file revisions with FTP protocol. [[bug>1944]] 
 +  * Support reading S3 credentials from AWS CLI configuration. [[bug>1941]] 
 +  * Bytes transferred are recorded in XML log and available in .NET assembly API. [[bug>597]] 
 +  * Generating PPK3 keys. 
 +  * It is possible to copy information to the clipboard from the Properties dialog. 
 +  * Made ''WinSCP.exe'' be deployed even when WinSCP NuGet package is included as transitive dependency. [[bug>2017]] 
 +  * When performing a single-item atomic operation, displaying indeterminate progress status. 
 +  * S3 //Security token// session option renamed to a more appropriate //Session Token//. 
 +  * Not resetting protocol to WebDAV when S3 protocol is selected and HTTP URL is pasted on the Login dialog. [[bug>2045]] 
 +  * Automatically reconnect when FTP server fails to open data connection, if it previously worked. [[bug>2046]] 
 +  * Confirm closing when multiple tabs are opened and auto workspace saving is not enabled, even when none of the tabs contain an active remote session. 
 +  * Including host key of tunnel session in generated code. [[bug>2006]] 
 +  * Support for custom certificate store files with configurable path. [[bug>2034]] 
 +  * Allowed providing tunnel private key passphrase in scripting. [[bug>2029]] 
 +  * Improved handling of long shell command error messages. [[bug>1949]] 
 +  * Considering global passive/active mode settings when importing sessions from FileZilla 
 +  * Automatically retry when S3 transfer fails with ''503'' code (//Slow down// or //Service unavailable//). [[bug>2047]] 
 +  * Improving formatting of errors displayed after an operation completed in //Continue on error// mode. 
 +  * ''Shift+Ctrl+R'' keyboard shortcut for //Reconnect Session// command. 
 +  * Change: Keyboard shortcut for //Restore Selection// command changed to ''Shift+Ctrl+S'' (''Shift+Ctrl+R'' previously)
 +  * Change: Monitoring ''A:'' and ''B:'' drives. [[bug>;2014]] 
 + ·* Preventing beep when using ''Alt+Enter'' to open the Properties dialog. 
 +  * When collecting list of files for background transfer, say //"Listing"// instead of //"Calculating"// not to give an impression that it is a superfluous operation. [[bug>2026]] 
 +  * Checking for too many parameters with ''/keygen'' switch. 
 +  * PNG code upgraded to PngComponents 1.7.0. 
 +  * Warning when selecting too new key file. 
 +  * Warning when opening more than 100 tabs. [[bug>1997]] 
 +  * Including HTTP message into S3 error message. 
 +  * Bug fix: Do not say //"Terminated by user"// when the session has actually timed out. 
 +  * Bug fix: Cannot use passwords and passphrases longer than 255 characters in automation and various other purposes. [[bug>1988]] 
 +  * Bug fix: When size of a file downloaded with FTP protocol changes (or when ASCII mode is used) the logged size did not reflect the actual transfer size. 
 +  * Bug fix: When connecting disconnected session the directory might be loaded twice. 
 +  * Bug fix: Failure when entering directory that contains file with a slash in its name. [[bug>;2016]] 
 +  * Bug fix: When S3 authentication region changes during session, previously visited buckets from the original authentication region could not be accessed anymore. [[bug>2027]] 
 +  * Bug fix: Failure when using multiple connections with local proxy command. [[bug>2028]] 
 +  * Bug fix: Configuration import  did not remove old sites and did not load all GUI settings. [[bug>2040]] 
 +  * Bug fix: When S3 transfer fatally fails, error details were lost.
-············} else if (intent.getAction().equals(Const.ACTION_SCREEN_SHARING_PERMISSION_NEEDED)) { +===== [[5.19.6]] 5.19.6 (hotfix) ((2022-02-22)) =====
-                startActivityForResult(projectionManager.createScreenCaptureIntent(), Const.REQUEST_SCREEN_SHARE); +
-············} +
- ·······} +
-····};+
-····@Override +··* Translation updated: German. 
-   protected void onCreate(Bundle savedInstanceState) +  * Back-propagated fixes from 5.20–5.20.2 releases: 
-       super.onCreate(savedInstanceState); + ···* TLS/SSL core upgraded to OpenSSL 1.1.1m. 
- ·······setContentView(R.layout.activity_main);+    * XML parser upgraded to Expat 2.4.6.
-········if (savedInstanceState != null) { +===== [[5.19.5]] 5.19.5 ((2021-11-25)) =====
- ···········restoreInstanceState(savedInstanceState); +
- ·······}+
-········Toolbar toolbar = findViewById(R.id.toolbar)+··* Compatibility with Google Cloud S3 API when duplicating files. [[bug>2038]] 
- ·······setSupportActionBar(toolbar)+ ·* Compatibility with Google Cloud S3 API when deleting implicitly existing directories. [[bug>;2042]] 
- ·······settingsHelper = SettingsHelper.getInstance(this); + ·* Translation updated: Turkish. 
- ·······sharingEngine = SharingEngineFactory.getSharingEngine()+··* Logging a reference to [[bug>1952]] when an OpenSSH 8.8 (or newer) server refuses the key. 
- ·······sharingEngine.setEventListener(this); + ·* Bug fix: Crash when new contents is copied to the clipboard while downloading files pasted from the clipboard. [[bug>;2036]] 
- ·······sharingEngine.setStateListener(this);+ ·* Bug fix: //Browse Remote Directory// command on Synchronization checklist did not locate file with spaces. 
 + ·* Bug fix: Extension //ZIP and Upload// does not work with files in a drive root. [[bug>2039]] 
 +  * Bug fix: Path on Console window was not shortened when it did not fit.
-········DisplayMetrics metrics = new DisplayMetrics()+===== [[5.19.4]] 5.19.4 ((2021-10-24)) =====
- ·······ScreenSharingHelper.getRealScreenSize(this, metrics); +
-        float videoScale = ScreenSharingHelper.adjustScreenMetrics(metrics); +
-       settingsHelper.setFloat(SettingsHelper.KEY_VIDEO_SCALE, videoScale); +
-        ScreenSharingHelper.setScreenMetrics(this, metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);+
-········sharingEngine.setScreenWidth(metrics.widthPixels)+··* Translation updated: Hungarian. 
- ·······sharingEngine.setScreenHeight(metrics.heightPixels);+··* Showing release date on the About dialog
 +  * Support for custom certificate store files. [[bug>;2034]] 
 + ·* Allow other ''2xx'' responses to ''PWD'' command, not only the standard ''257''. [[bug>;1768]] 
 +  * Bug fix: When there are both site folder and site with the same name and the site was selected when closing the Login dialog, when reopening, the folder was selected instead.
-········IntentFilter intentFilter = new IntentFilter(Const.ACTION_SCREEN_SHARING_START); +===== [[5.19.3]] 5.19.3 ((2021-10-11)) =====
-        intentFilter.addAction(Const.ACTION_SCREEN_SHARING_STOP)+
-       intentFilter.addAction(Const.ACTION_SCREEN_SHARING_PERMISSION_NEEDED); +
- ·······intentFilter.addAction(Const.ACTION_SCREEN_SHARING_FAILED)+
-        intentFilter.addAction(Const.ACTION_CONNECTION_FAILURE)+
- ·······LocalBroadcastManager.getInstance(this).registerReceiver(mSharingServiceReceiver, intentFilter);+
-········projectionManager = (MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE); +··* Translation updated: French
- +  * TLS/SSL core upgraded to OpenSSL 1.1.1l
-       initUI(); +  * Using //Documents// folder when the last used local directory in Explorer interface does not exist anymore. [[bug>2011]] 
-        setDefaultSettings(); +  * Bug fix: TLS session resumption is not working for subsequent FTP transfers with TLS 1.3 when the server requires reuse of the session of the previous transfer. [[bug>2018]] 
-    } +  * Bug fix: Cannot access S3 bucket root when the access policy checks for empty prefix. [[bug>2021]] 
- +  * Bug fix: Response from ProFTPD FTP checksum commands is not recognized. [[bug>2023]] 
-    @Override +  * Bug fix: Failure when submitting prompt with //"Never ask me again"// selected. [[bug>2022]] 
-    protected void onResume() { +  * Bug fix: Panels are drawn incorrectly after toggling //Full row select//. [[bug>2025]] 
-        super.onResume(); +  * Bug fix: Timeout while uploading files to some FTP servers using TLS 1.3. [[bug>2030]] 
-       updateUI(); +  * Bug fix: Incomplete listing for S3 servers that indicate truncated listing after the contents and whose pagination is a multiple of 8 (e.g. Backblaze). [[bug>2032]]
- +
- ·······startService(new Intent(MainActivity.this, GestureDispatchService.class)); +
-//       connect(); +
-       checkAccessibility(); +
-   } +
- +
-   private void checkAccessibility() { +
-        if (!Utils.isAccessibilityPermissionGranted(this)) { +
-            textViewConnect.setVisibility(View.INVISIBLE); +
-           new AlertDialog.Builder(this) +
-                   .setMessage(R.string.accessibility_hint) +
-                   .setPositiveButton(R.string.continue_button, new DialogInterface.OnClickListener() { +
-                        @Override +
-                        public void onClick(DialogInterface dialog, int which) { +
-                            Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS); +
-                            try { +
-                                startActivityForResult(intent, 0); +
-                            } catch (Exception e) { +
-································// Accessibility settings cannot be opened +
-                                reportAccessibilityUnavailable(); +
-                            } +
-                        } +
-                    }) +
-                    .setCancelable(false) +
-                    .create() +
-                    .show(); +
-        } else { +
-            configureAndConnect(); +
-        } +
-    } +
- +
-    private void reportAccessibilityUnavailable() { +
-        new AlertDialog.Builder(this) +
-                .setMessage(R.string.accessibility_unavailable_error) +
-                .setPositiveButton(R.string.button_exit, new DialogInterface.OnClickListener() { +
-                    @Override +
-                    public void onClick(DialogInterface dialog, int which) { +
-                        exitApp(); +
-                    } +
-                }) +
-                .setCancelable(false) +
-                .create() +
-                .show(); +
-    } +
- +
-    private void configureAndConnect() { +
-        if (settingsHelper.getString(SettingsHelper.KEY_SERVER_URL) == null) { +
-············// Not configured yet +
-           settingsHelper.setString(SettingsHelper.KEY_SERVER_URL, BuildConfig.DEFAULT_SERVER_URL); +
-           settingsHelper.setString(SettingsHelper.KEY_SECRET, BuildConfig.DEFAULT_SECRET); +
-           settingsHelper.setBoolean(SettingsHelper.KEY_USE_DEFAULT, !BuildConfig.DEFAULT_SECRET.equals("")); +
-           Intent intent = new Intent(this, SettingsActivity.class); +
- ···········startActivityForResult(intent, Const.REQUEST_SETTINGS); +
-            return; +
-        } +
- +
-        if (needReconnect) { +
-            // Here we go after changing settings +
-            needReconnect = false; +
-            if (sharingEngine.getState() != Const.STATE_DISCONNECTED) { +
-                sharingEngine.disconnect(MainActivity.this, (success, errorReason) -> connect()); +
-           } else { +
-               connect(); +
- ···········+
-       } else +
-           if (sharingEngine.getState() == Const.STATE_DISCONNECTED && sharingEngine.getErrorReason() == null) +
-               connect(); +
-            } +
-        } +
-    } +
- +
-    @Override +
-    public void onDestroy() { +
-        try { +
-            LocalBroadcastManager.getInstance(this).unregisterReceiver(mSharingServiceReceiver); +
-       } catch (Exception e) { +
-        } +
-        super.onDestroy(); +
-    } +
- +
-    @Override +
-    public void onSaveInstanceState(Bundle savedInstanceState) { +
-        savedInstanceState.putString(ATTR_SESSION_ID, sessionId); +
-        savedInstanceState.putString(ATTR_PASSWORD, password); +
-        savedInstanceState.putString(ATTR_ADMIN_NAME, adminName); +
-        super.onSaveInstanceState(savedInstanceState); +
-    } +
- +
-    private void restoreInstanceState(Bundle savedInstanceState) { +
-        sessionId = savedInstanceState.getString(ATTR_SESSION_ID); +
-        password = savedInstanceState.getString(ATTR_PASSWORD); +
-        adminName = savedInstanceState.getString(ATTR_ADMIN_NAME); +
-    } +
- +
-    @Override +
-    public void onBackPressed() { +
-        Toast.makeText(this, R.string.back_pressed, Toast.LENGTH_LONG).show(); +
-    } +
- +
-    @Override +
-    public boolean onCreateOptionsMenu(Menu menu) { +
-        // Inflate the menu; this adds items to the action bar if it is present. +
-        getMenuInflater().inflate(R.menu.menu_main, menu); +
-        return true; +
-    } +
- +
-    @Override +
-    public boolean onOptionsItemSelected(MenuItem item) { +
-        // Handle action bar item clicks here. The action bar will +
-        // automatically handle clicks on the Home/Up button, so long +
-        // as you specify a parent activity in AndroidManifest.xml. +
- ·······int id = item.getItemId(); +
- +
-        if (id == R.id.action_settings) { +
-            if (adminName != null) { +
-                Toast.makeText(this, R.string.settings_unavailable, Toast.LENGTH_LONG).show(); +
-                return true; +
-            } +
-            Intent intent = new Intent(this, SettingsActivity.class); +
-            startActivityForResult(intent, Const.REQUEST_SETTINGS); +
-            cancelExitOnIdle(); +
-            return true; +
-        } else if (id == R.id.action_about) { +
-            showAbout(); +
-            return true; +
-        } +
- +
-        return super.onOptionsItemSelected(item); +
-    } +
- +
-    @Override +
-    public void onActivityResult(int requestCode, int resultCode, Intent data) { +
-        super.onActivityResult(requestCode, resultCode, data); +
- +
-        if (requestCode == Const.REQUEST_SETTINGS) { +
-            if (resultCode == Const.RESULT_DIRTY) { +
-                needReconnect = true; +
-            } else { +
-                scheduleExitOnIdle(); +
-            } +
-        } else if (requestCode == Const.REQUEST_SCREEN_SHARE) { +
-            if (resultCode != RESULT_OK) { +
-                Toast.makeText(this, R.string.screen_cast_denied, Toast.LENGTH_LONG).show(); +
-                adminName = null; +
-                updateUI(); +
-                cancelSharingTimeout(); +
-                scheduleExitOnIdle(); +
-            } else { +
-                ScreenSharingHelper.startSharing(this, resultCode, data); +
-            } +
-        } +
-    } +
- +
-    private void initUI() { +
-        imageViewConnStatus = findViewById(R.id.image_conn_status); +
-        textViewConnStatus = findViewById(R.id.conn_status); +
-        editTextSessionId = findViewById(R.id.session_id_edit); +
-        editTextPassword = findViewById(R.id.password_edit); +
-        textViewComment = findViewById(R.id.comment); +
-        textViewConnect = findViewById(R.id.reconnect); +
-        textViewSendLink = findViewById(R.id.send_link); +
-        textViewExit = findViewById(R.id.disconnect_exit); +
- +
-        textViewConnect.setOnClickListener(v -> connect()); +
- +
-       textViewSendLink.setOnClickListener(v -> sendLink()); +
- +
- ·······textViewExit.setOnClickListener(v -> gracefulExit()); +
-   } +
- +
-   private void gracefulExit() +
-       if (adminName != null) +
-           notifySharingStop(); +
-            ScreenSharingHelper.stopSharing(MainActivity.this, true)+
-        } +
-        sharingEngine.disconnect(MainActivity.this, (success, errorReason) -> exitApp()); +
-       // 5 sec timeout to exit +
-       handler.postDelayed(() -> exitApp(), 5000); +
-   } +
- +
-   private void exitApp() +
-       Intent intent = new Intent(MainActivity.this, ScreenSharingService.class); +
-        stopService(intent); +
-        intent = new Intent(MainActivity.this, GestureDispatchService.class); +
-        stopService(intent); +
-        finishAffinity(); +
-        System.exit(0); +
-    } +
- +
-    private void updateUI() { +
-        int[] stateLabels = {R.string.state_disconnected, R.string.state_connecting, R.string.state_connected, R.string.state_sharing, R.string.state_disconnecting}; +
-        int[] stateImages = {R.drawable.ic_disconnected, R.drawable.ic_connecting, R.drawable.ic_connected, R.drawable.ic_sharing, R.drawable.ic_connecting}; +
- +
-        int state = sharingEngine.getState(); +
-        if (state == Const.STATE_CONNECTED && adminName != null) { +
-            imageViewConnStatus.setImageDrawable(getDrawable(stateImages[Const.STATE_SHARING])); +
-            textViewConnStatus.setText(stateLabels[Const.STATE_SHARING]); +
-       } else { +
-           imageViewConnStatus.setImageDrawable(getDrawable(stateImages[state])); +
- ···········textViewConnStatus.setText(stateLabels[state]); +
-        } +
-        String serverUrl = Utils.prepareDisplayUrl(settingsHelper.getString(SettingsHelper.KEY_SERVER_URL)); +
- +
-        textViewSendLink.setVisibility(state == Const.STATE_CONNECTED ? View.VISIBLE : View.INVISIBLE); +
-       textViewConnect.setVisibility(state == Const.STATE_DISCONNECTED ? View.VISIBLE : View.INVISIBLE); +
-        switch (state) { +
-            case Const.STATE_DISCONNECTED: +
-                editTextSessionId.setText(""); +
-               editTextPassword.setText(""); +
-               if (sharingEngine.getErrorReason() != null) { +
-                    textViewComment.setText(getString(R.string.hint_connection_error, serverUrl)); +
-                } +
-                break; +
-            case Const.STATE_CONNECTING: +
-                textViewComment.setText(getString(R.string.hint_connecting, serverUrl)); +
-                break; +
-            case Const.STATE_DISCONNECTING: +
-                textViewComment.setText(getString(R.string.hint_disconnecting)); +
-                break; +
-            case Const.STATE_CONNECTED: +
-                editTextSessionId.setText(sessionId); +
-                editTextPassword.setText(password); +
-                textViewComment.setText(adminName != null ? +
-                        getString(R.string.hint_sharing, adminName) : +
-                        getString(R.string.hint_connected, serverUrl) +
-                        ); +
-                break; +
-        } +
-    } +
- +
-    private void setDefaultSettings() { +
-        if (settingsHelper.getString(SettingsHelper.KEY_DEVICE_NAME) == null) { +
-            settingsHelper.setString(SettingsHelper.KEY_DEVICE_NAME, Build.MANUFACTURER + " " + Build.MODEL); +
-        } +
-        if (settingsHelper.getInt(SettingsHelper.KEY_BITRATE) == 0) { +
-            settingsHelper.setInt(SettingsHelper.KEY_BITRATE, Const.DEFAULT_BITRATE); +
-        } +
-        if (settingsHelper.getInt(SettingsHelper.KEY_FRAME_RATE) == 0) { +
-            settingsHelper.setInt(SettingsHelper.KEY_FRAME_RATE, Const.DEFAULT_FRAME_RATE); +
-        } +
-        if (settingsHelper.getInt(SettingsHelper.KEY_IDLE_TIMEOUT) == 0) { +
-            settingsHelper.setInt(SettingsHelper.KEY_IDLE_TIMEOUT, Const.DEFAULT_IDLE_TIMEOUT); +
-        } +
-        if (settingsHelper.getInt(SettingsHelper.KEY_PING_TIMEOUT) == 0) { +
-            settingsHelper.setInt(SettingsHelper.KEY_PING_TIMEOUT, Const.DEFAULT_PING_TIMEOUT); +
-        } +
-    } +
- +
-    private void sendLink() { +
-        String url = settingsHelper.getString(SettingsHelper.KEY_SERVER_URL); +
-        url += "?session=" + sessionId + "&pin=" + password; +
-        try { +
-            Intent shareIntent = new Intent(Intent.ACTION_SEND); +
-            shareIntent.setType("text/plain"); +
-            shareIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.send_link_subject)); +
-            String shareMessage= getString(R.string.send_link_message, url, settingsHelper.getString(SettingsHelper.KEY_DEVICE_NAME)); +
-            shareIntent.putExtra(Intent.EXTRA_TEXT, shareMessage); +
-            startActivity(Intent.createChooser(shareIntent, getString(R.string.send_link_chooser))); +
-        } catch(Exception e) { +
-            e.printStackTrace(); +
-            Toast.makeText(this, R.string.send_link_failed, Toast.LENGTH_LONG).show(); +
-        } +
-    } +
- +
-    private void showAbout() { +
-        ImageView imageView = new ImageView(this); +
-        imageView.setImageDrawable(getResources().getDrawable(R.mipmap.ic_launcher)); +
-        new AlertDialog.Builder(this) +
-                .setTitle(R.string.about_title) +
-                .setMessage(getString(R.string.about_message, BuildConfig.VERSION_NAME, BuildConfig.VARIANT)) +
-                .setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss()) +
-                .create() +
-                .show(); +
-    } +
- +
-    private void connect() { +
-        if (sessionId == null || password == null) { +
-            sessionId = Utils.randomString(8, true); +
-            password = Utils.randomString(4, true); +
-        } +
-        sharingEngine.setUsername(settingsHelper.getString(SettingsHelper.KEY_DEVICE_NAME)); +
-        sharingEngine.connect(this, sessionId, password, (success, errorReason) -> { +
-            if (!success) { +
-                if (errorReason != null && errorReason.equals(Const.ERROR_ICE_FAILED)) { +
-                    errorReason = getString(R.string.connection_error_ice); +
-                } +
-                String message = getString(R.string.connection_error, settingsHelper.getString(SettingsHelper.KEY_SERVER_URL), errorReason); +
-                reportError(message); +
-                editTextSessionId.setText(null); +
-                editTextPassword.setText(null); +
-            } +
-        }); +
- +
-        scheduleExitOnIdle(); +
-    } +
- +
-    private void reportError(final String message) { +
-//       Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show(); +
-        final AlertDialog dialog = new AlertDialog.Builder(this) +
-                .setMessage(message) +
-                .setNegativeButton(R.string.copy_message, (dialog1, which) -> { +
-····················ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); +
-                   ClipData clip = ClipData.newPlainText(Const.LOG_TAG, message); +
- ···················clipboard.setPrimaryClip(clip); +
-                   Toast.makeText(MainActivity.this, R.string.message_copied, Toast.LENGTH_LONG).show(); +
-                   dialog1.dismiss(); +
-               }) +
-               .setPositiveButton(R.string.close, (dialog1, which) -> dialog1.dismiss()) +
-                .create(); +
-        try { +
-            dialog.show(); +
-            handler.postDelayed(() -> { +
-                try { +
-                    dialog.dismiss(); +
-                } catch (Exception e) { +
-                } +
-            }, 10000); +
-        } catch (Exception e) { +
-        } +
-    } +
- +
-    @Override +
-    public void onStartSharing(String adminName) { +
-········// This event is raised when the admin joins the text room +
-       this.adminName = adminName; +
-        updateUI(); +
-        cancelExitOnIdle(); +
-        scheduleSharingTimeout(); +
-        ScreenSharingHelper.requestSharing(this); +
-    } +
- +
-    @Override +
-    public void onStopSharing() { +
-········// This event is raised when the admin leaves the text room +
-        notifySharingStop(); +
-        adminName = null; +
-        updateUI(); +
-        cancelSharingTimeout(); +
-        scheduleExitOnIdle(); +
-        ScreenSharingHelper.stopSharing(this, false); +
-    } +
- +
-    @Override +
-    public void onRemoteControlEvent(String event) { +
-        Intent intent = new Intent(MainActivity.this, GestureDispatchService.class); +
-        intent.setAction(Const.ACTION_GESTURE); +
-        intent.putExtra(Const.EXTRA_EVENT, event); +
-        startService(intent); +
-    } +
- +
-    @Override +
-    public void onPing() { +
-        if (adminName != null) { +
-            cancelSharingTimeout(); +
-            scheduleSharingTimeout(); +
-        } +
-    } +
- +
-    @Override +
-    public void onSharingApiStateChanged(int state) { +
-        updateUI(); +
-        if (state == Const.STATE_CONNECTED) { +
-            String rtpHost = Utils.getRtpUrl(settingsHelper.getString(SettingsHelper.KEY_SERVER_URL)); +
-            int rtpAudioPort = sharingEngine.getAudioPort(); +
-            int rtpVideoPort = sharingEngine.getVideoPort(); +
-            String testDstIp = settingsHelper.getString(SettingsHelper.KEY_TEST_DST_IP); +
-            if (testDstIp != null && !testDstIp.trim().equals("")) { +
-                rtpHost = testDstIp; +
-                rtpVideoPort = Const.TEST_RTP_PORT; +
-                Toast.makeText(this, "Test mode: sending stream to " + rtpHost + ":" + rtpVideoPort, Toast.LENGTH_LONG).show(); +
-            } +
- +
-            ScreenSharingHelper.configure(this, settingsHelper.getBoolean(SettingsHelper.KEY_TRANSLATE_AUDIO), +
-                    settingsHelper.getInt(SettingsHelper.KEY_FRAME_RATE), +
-                    settingsHelper.getInt(SettingsHelper.KEY_BITRATE), +
-                    rtpHost, +
-                    rtpAudioPort, +
-                    rtpVideoPort +
-                    ); +
-        } +
-    } +
- +
-    private void scheduleExitOnIdle() { +
-        int exitOnIdleTimeout = settingsHelper.getInt(SettingsHelper.KEY_IDLE_TIMEOUT); +
-        if (exitOnIdleTimeout > 0) { +
-············exitCounter = EXIT_PROMPT_SEC; +
-           handler.postDelayed(warningOnIdleRunnable, exitOnIdleTimeout * 1000); +
-            Log.d(Const.LOG_TAG, "Scheduling exit in " + (exitOnIdleTimeout * 1000) + " sec"); +
-       } +
-   } +
- +
-   private void cancelExitOnIdle() +
-       Log.d(Const.LOG_TAG, "Cancelling scheduled exit"); +
-        handler.removeCallbacks(warningOnIdleRunnable); +
-        handler.removeCallbacks(exitRunnable); +
- ···} +
- +
-    private Runnable exitRunnable = () -> { +
-········exitCounter--; +
-       if (exitCounter > 0) { +
-            TextView messageView = exitOnIdleDialog.findViewById(android.R.id.message); +
-            if (messageView != null) { +
-                messageView.setText(MainActivity.this.getResources().getString(R.string.app_idle_warning, exitCounter)); +
-            } +
-            scheduleExitRunnable(); +
- +
-        } else { +
-            gracefulExit(); +
-        } +
-    }; +
- +
-    private Runnable warningOnIdleRunnable = () -> { +
-        exitOnIdleDialog = new AlertDialog.Builder(MainActivity.this) +
-                .setMessage(MainActivity.this.getResources().getString(R.string.app_idle_warning, exitCounter)) +
-                .setPositiveButton(R.string.button_exit, (dialog1, which) -> { +
-                    gracefulExit(); +
-                }) +
-                .setNegativeButton(R.string.button_keep_idle, (dialog1, which) -> { +
-                    scheduleExitOnIdle(); +
-                    handler.removeCallbacks(exitRunnable); +
-                    dialog1.dismiss(); +
-                }) +
-                .setCancelable(false) +
-                .create(); +
-        try { +
-            exitOnIdleDialog.show(); +
-            scheduleExitRunnable(); +
-        } catch (Exception e) { +
-            gracefulExit(); +
-        } +
-    }; +
- +
-    private void scheduleExitRunnable() { +
-        handler.postDelayed(exitRunnable, 1000); +
-    } +
- +
-    private void scheduleSharingTimeout() { +
-        int pingTimeout = settingsHelper.getInt(SettingsHelper.KEY_PING_TIMEOUT); +
-        if (pingTimeout > 0) { +
-            Log.d(Const.LOG_TAG, "Scheduling sharing stop in " + (pingTimeout * 1000) + " sec"); +
-           handler.postDelayed(sharingStopByPingTimeoutRunnable, pingTimeout * 1000); +
-       } +
-   } +
- +
-   private void cancelSharingTimeout() +
-       Log.d(Const.LOG_TAG, "Cancelling scheduled sharing stop"); +
-        handler.removeCallbacks(sharingStopByPingTimeoutRunnable); +
-    } +
- +
-    private Runnable sharingStopByPingTimeoutRunnable = new Runnable() { +
-        @Override +
-        public void run() { +
-            Toast.makeText(MainActivity.this, R.string.app_sharing_session_ping_timeout, Toast.LENGTH_LONG).show(); +
-            if (adminName != null) { +
-                notifySharingStop(); +
-                ScreenSharingHelper.stopSharing(MainActivity.this, false); +
-            } +
-            adminName = null; +
-            updateUI(); +
-            cancelSharingTimeout(); +
-            scheduleExitOnIdle(); +
-            sharingEngine.disconnect(MainActivity.this, (success, errorReason) -> connect()); +
-        } +
-    }; +
- +
-    private Runnable overlayDotRunnable = new Runnable() { +
-        @Override +
-        public void run() { +
-            if (overlayDotDirection == 0) { +
-                return; +
-            } +
-            overlayDotAlpha += OVERLAY_DOT_ANIMATION_INCREMENT * overlayDotDirection; +
-            if (overlayDotAlpha > 255) { +
-                overlayDotAlpha = 255; +
-                overlayDotDirection = -overlayDotDirection; +
-            } +
-            if (overlayDotAlpha < 128) { +
-                overlayDotAlpha = 128; +
-                overlayDotDirection = -overlayDotDirection; +
-            } +
-            overlayDot.setImageAlpha(overlayDotAlpha); +
-            handler.postDelayed(overlayDotRunnable, OVERLAY_DOT_ANIMATION_DELAY); +
-        } +
-    }; +
- +
-    private void notifySharingStart() { +
-        notifyGestureService(Const.ACTION_SCREEN_SHARING_START); +
-        if (settingsHelper.getBoolean(SettingsHelper.KEY_NOTIFY_SHARING)) { +
-            // Show a flashing dot +
-           Utils.lockDeviceRotation(this, true); +
-            overlayDot = createOverlayDot(); +
-            overlayDotAlpha = 0; +
-            overlayDotDirection = 1; +
-            handler.postDelayed(overlayDotRunnable, OVERLAY_DOT_ANIMATION_DELAY); +
- +
-        } else { +
-            // Just show some dialog to trigger the traffic +
-            final AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) +
-                   .setMessage(R.string.share_start_text) +
-····················.setPositiveButton(R.string.ok, (dialog1, which) -> dialog1.dismiss()) +
-                    .create(); +
-            dialog.show(); +
-            handler.postDelayed(() -> { +
-                if (dialog != null && dialog.isShowing()) { +
-                    try { +
-                        dialog.dismiss(); +
-                    } catch (Exception e) { +
-                    } +
-                } +
-            }, 3000); +
-        } +
-    } +
- +
-    private void notifySharingStop() { +
-        notifyGestureService(Const.ACTION_SCREEN_SHARING_STOP); +
-        if (settingsHelper.getBoolean(SettingsHelper.KEY_NOTIFY_SHARING)) { +
-            overlayDotDirection = 0; +
-            if (overlayDot != null) { +
-                WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); +
-                wm.removeView(overlayDot); +
-                overlayDot = null; +
-            } +
-            Utils.lockDeviceRotation(this, false); +
-        } +
-    } +
- +
-    private void notifyGestureService(String action) { +
-        Intent intent = new Intent(MainActivity.this, GestureDispatchService.class); +
-        intent.setAction(action); +
-        startService(intent); +
-    } +
- +
-    public ImageView createOverlayDot() { +
-        int size = getResources().getDimensionPixelOffset(R.dimen.overlay_dot_size); +
-        WindowManager.LayoutParams params = new WindowManager.LayoutParams(size, size, +
-                Utils.OverlayWindowType(), +
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE +
-                        |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL +
-                        |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, +
-                PixelFormat.TRANSLUCENT); +
-        params.gravity = Gravity.LEFT | Gravity.TOP; +
-        params.x = getResources().getDimensionPixelOffset(R.dimen.overlay_dot_offset); +
-        params.y = getResources().getDimensionPixelOffset(R.dimen.overlay_dot_offset); +
- +
-        ImageView view = new ImageView(this); +
-        view.setImageResource(R.drawable.flash_dot); +
-        view.setImageAlpha(0); +
-        WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); +
-        wm.addView(view, params); +
-        return view; +
-    } +
-}+
 +[[history_old|Older versions]]
 +~~NOTOC~~
 +~~ARCHIVE=history_old~~

Last modified: by martin